aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.js.ini186
-rw-r--r--tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_Ed448.https.any.js.ini186
-rw-r--r--tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.js.ini162
-rw-r--r--tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_X448.https.any.js.ini162
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-color/parsing/color-computed-relative-color.html.ini6
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-color/parsing/color-valid-relative-color.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-overflowing-parsing.html.ini (renamed from tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-overflowing-parsing.html.ini)0
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-overflowing-serialization.html.ini (renamed from tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-overflowing-serialization.html.ini)0
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-snapped-parsing.html.ini (renamed from tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-snapped-parsing.html.ini)0
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-snapped-serialization.html.ini (renamed from tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-snapped-serialization.html.ini)0
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-stuck-parsing.html.ini (renamed from tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-stuck-parsing.html.ini)0
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-stuck-serialization.html.ini (renamed from tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-stuck-serialization.html.ini)0
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-computed.html.ini (renamed from tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/container-type-scroll-state-computed.html.ini)0
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-containment.html.ini (renamed from tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/container-type-scroll-state-containment.html.ini)0
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-parsing.html.ini (renamed from tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/container-type-scroll-state-parsing.html.ini)0
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-initially-snapped.html.ini (renamed from tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-initially-snapped.html.ini)0
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-initially-stuck.html.ini (renamed from tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-initially-stuck.html.ini)0
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-change.html.ini (renamed from tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-snapped-change.html.ini)0
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-container-type-change.html.ini (renamed from tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-snapped-container-type-change.html.ini)0
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-none.html.ini (renamed from tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-snapped-none.html.ini)0
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-wm.html.ini (renamed from tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-snapped-wm.html.ini)0
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-container-type-change.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-writing-direction.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-target-query-change.html.ini (renamed from tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-target-query-change.html.ini)0
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/size-container-writing-mode-change.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-fonts/generic-family-keywords-001.html.ini7
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-overflow/line-clamp/webkit-line-clamp-050.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-pseudo/first-line-below-float.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-pseudo/parsing/the-check-pseudo-element.tentative.html.ini18
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-sizing/animation/height-interpolation.html.ini24
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-sizing/stretch/abspos-1.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-sizing/stretch/abspos-2.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-sizing/stretch/bfc-next-to-float-1.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-sizing/stretch/block-height-1.html.ini27
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-sizing/stretch/block-height-2.html.ini6
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-sizing/stretch/min-width-1.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-sizing/stretch/positioned-non-replaced-1.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-sizing/stretch/positioned-replaced-1.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-text/white-space/white-space-intrinsic-size-021.html.ini41
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-ui/text-overflow-ellipsis-multiline-001.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-values/calc-serialization-002.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/calc-size-height-interpolation.html.ini120
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-max-height-composition.html.ini30
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-max-width-composition.html.ini30
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-min-height-composition.html.ini30
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-min-width-composition.html.ini30
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-values/minmax-length-percent-serialize.html.ini6
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-values/round-function.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/css/css-values/vh_not_refreshing_on_chrome.html.ini1
-rw-r--r--tests/wpt/meta-legacy-layout/custom-elements/CustomElementRegistry.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/dom/nodes/moveBefore/tentative/custom-element-move-reactions.html.ini12
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/fetch-preflight.https.sub.any.js.ini10
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/fetch.https.sub.any.js.ini102
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/css-font-face.sub.tentative.html.ini4
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/css-images.https.sub.tentative.html.ini18
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/css-images.sub.tentative.html.ini6
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-a.sub.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-audio.https.sub.html.ini36
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-audio.sub.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-iframe.sub.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-img.https.sub.html.ini72
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-img.sub.html.ini6
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-link-prefetch.https.optional.sub.html.ini30
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-link-prefetch.optional.sub.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-meta-refresh.https.optional.sub.html.ini20
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-meta-refresh.optional.sub.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-picture.https.sub.html.ini93
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-picture.sub.html.ini9
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-script.https.sub.html.ini60
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-script.sub.html.ini6
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-video.https.sub.html.ini36
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-video.sub.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/fetch.https.sub.html.ini36
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/fetch.sub.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-dynamic.https.sub.html.ini27
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-dynamic.sub.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-static.https.sub.html.ini27
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-static.sub.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/window-location.sub.html.ini12
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/worker-dedicated-constructor.https.sub.html.ini12
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/worker-dedicated-importscripts.https.sub.html.ini27
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/generated/worker-dedicated-importscripts.sub.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/navigation.https.sub.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/redirect/multiple-redirect-https-downgrade-upgrade.sub.html.ini9
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/redirect/redirect-https-downgrade.sub.html.ini12
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/style.https.sub.html.ini34
-rw-r--r--tests/wpt/meta-legacy-layout/fetch/metadata/worker.https.sub.html.ini10
-rw-r--r--tests/wpt/meta-legacy-layout/html/browsers/browsing-the-web/navigating-across-documents/navigation-unload-cross-origin.sub.window.js.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/element/text/2d.text.measure.text-clusters-position.tentative.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/element/text/2d.text.measure.text-clusters-range.tentative.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.w.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.w.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.w.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.w.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.w.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.w.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.w.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.w.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.w.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.w.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.w.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.w.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.worker.js.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.worker.js.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.w.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.w.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative.w.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/dom/elements/the-innertext-and-outertext-properties/innertext-whitespace-pre-line.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html.ini2
-rw-r--r--tests/wpt/meta-legacy-layout/html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html.ini119
-rw-r--r--tests/wpt/meta-legacy-layout/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html.ini15
-rw-r--r--tests/wpt/meta-legacy-layout/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/html/webappapis/update-rendering/child-document-raf-order.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/selection/caret-position-should-be-correct-while-moveup-movedown.html.ini72
-rw-r--r--tests/wpt/meta-legacy-layout/selection/shadow-dom/tentative/Selection-getComposedRanges-dom-mutations-removal.html.ini32
-rw-r--r--tests/wpt/meta-legacy-layout/selection/shadow-dom/tentative/Selection-getComposedRanges-slot.html.ini9
-rw-r--r--tests/wpt/meta-legacy-layout/url/failure.html.ini3
-rw-r--r--tests/wpt/meta-legacy-layout/url/percent-encoding.window.js.ini12
-rw-r--r--tests/wpt/meta-legacy-layout/wasm/jsapi/jspi/js-promise-integration.any.js.ini63
-rw-r--r--tests/wpt/meta-legacy-layout/wasm/jsapi/jspi/rejects.any.js.ini32
-rw-r--r--tests/wpt/meta-legacy-layout/webmessaging/with-ports/017.html.ini4
-rw-r--r--tests/wpt/meta-legacy-layout/webmessaging/without-ports/018.html.ini4
-rw-r--r--tests/wpt/meta-legacy-layout/webstorage/localstorage-about-blank-3P-iframe-opens-3P-window.partitioned.html.ini4
-rw-r--r--tests/wpt/meta-legacy-layout/workers/WorkerGlobalScope-close.html.ini3
-rw-r--r--tests/wpt/meta/MANIFEST.json4156
-rw-r--r--tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.js.ini186
-rw-r--r--tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_Ed448.https.any.js.ini186
-rw-r--r--tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.js.ini162
-rw-r--r--tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_X448.https.any.js.ini162
-rw-r--r--tests/wpt/meta/css/css-color/parsing/color-computed-relative-color.html.ini6
-rw-r--r--tests/wpt/meta/css/css-color/parsing/color-valid-relative-color.html.ini3
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-overflowing-parsing.html.ini (renamed from tests/wpt/meta/css/css-conditional/container-queries/at-container-overflowing-parsing.html.ini)0
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-overflowing-serialization.html.ini (renamed from tests/wpt/meta/css/css-conditional/container-queries/at-container-overflowing-serialization.html.ini)0
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-snapped-parsing.html.ini (renamed from tests/wpt/meta/css/css-conditional/container-queries/at-container-snapped-parsing.html.ini)0
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-snapped-serialization.html.ini (renamed from tests/wpt/meta/css/css-conditional/container-queries/at-container-snapped-serialization.html.ini)0
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-stuck-parsing.html.ini (renamed from tests/wpt/meta/css/css-conditional/container-queries/at-container-stuck-parsing.html.ini)0
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-stuck-serialization.html.ini (renamed from tests/wpt/meta/css/css-conditional/container-queries/at-container-stuck-serialization.html.ini)0
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-computed.html.ini (renamed from tests/wpt/meta/css/css-conditional/container-queries/container-type-scroll-state-computed.html.ini)0
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-containment.html.ini (renamed from tests/wpt/meta/css/css-conditional/container-queries/container-type-scroll-state-containment.html.ini)0
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-parsing.html.ini (renamed from tests/wpt/meta/css/css-conditional/container-queries/container-type-scroll-state-parsing.html.ini)0
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-initially-snapped.html.ini (renamed from tests/wpt/meta/css/css-conditional/container-queries/scroll-state-initially-snapped.html.ini)0
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-initially-stuck.html.ini (renamed from tests/wpt/meta/css/css-conditional/container-queries/scroll-state-initially-stuck.html.ini)0
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-change.html.ini (renamed from tests/wpt/meta/css/css-conditional/container-queries/scroll-state-snapped-change.html.ini)0
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-container-type-change.html.ini (renamed from tests/wpt/meta/css/css-conditional/container-queries/scroll-state-snapped-container-type-change.html.ini)0
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-none.html.ini (renamed from tests/wpt/meta/css/css-conditional/container-queries/scroll-state-snapped-none.html.ini)0
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-wm.html.ini (renamed from tests/wpt/meta/css/css-conditional/container-queries/scroll-state-snapped-wm.html.ini)0
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-container-type-change.html.ini2
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-writing-direction.html.ini2
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-target-query-change.html.ini (renamed from tests/wpt/meta/css/css-conditional/container-queries/scroll-state-target-query-change.html.ini)0
-rw-r--r--tests/wpt/meta/css/css-conditional/container-queries/size-container-writing-mode-change.html.ini2
-rw-r--r--tests/wpt/meta/css/css-overflow/line-clamp/webkit-line-clamp-050.html.ini2
-rw-r--r--tests/wpt/meta/css/css-pseudo/first-line-below-float.html.ini2
-rw-r--r--tests/wpt/meta/css/css-pseudo/parsing/the-check-pseudo-element.tentative.html.ini18
-rw-r--r--tests/wpt/meta/css/css-sizing/animation/height-interpolation.html.ini24
-rw-r--r--tests/wpt/meta/css/css-sizing/stretch/abspos-1.html.ini2
-rw-r--r--tests/wpt/meta/css/css-sizing/stretch/abspos-2.html.ini2
-rw-r--r--tests/wpt/meta/css/css-sizing/stretch/block-height-1.html.ini27
-rw-r--r--tests/wpt/meta/css/css-sizing/stretch/block-height-2.html.ini6
-rw-r--r--tests/wpt/meta/css/css-sizing/stretch/min-width-1.html.ini2
-rw-r--r--tests/wpt/meta/css/css-sizing/stretch/positioned-non-replaced-1.html.ini2
-rw-r--r--tests/wpt/meta/css/css-sizing/stretch/positioned-replaced-1.html.ini2
-rw-r--r--tests/wpt/meta/css/css-ui/text-overflow-ellipsis-multiline-001.html.ini2
-rw-r--r--tests/wpt/meta/css/css-values/calc-serialization-002.html.ini3
-rw-r--r--tests/wpt/meta/css/css-values/calc-size/animation/calc-size-height-interpolation.html.ini120
-rw-r--r--tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-height-composition.html.ini9
-rw-r--r--tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-max-height-composition.html.ini30
-rw-r--r--tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-max-width-composition.html.ini30
-rw-r--r--tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-min-height-composition.html.ini30
-rw-r--r--tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-min-width-composition.html.ini30
-rw-r--r--tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-width-composition.html.ini6
-rw-r--r--tests/wpt/meta/css/css-values/minmax-length-percent-serialize.html.ini6
-rw-r--r--tests/wpt/meta/css/css-values/round-function.html.ini3
-rw-r--r--tests/wpt/meta/css/cssom-view/MediaQueryList-extends-EventTarget.html.ini3
-rw-r--r--tests/wpt/meta/custom-elements/CustomElementRegistry.html.ini3
-rw-r--r--tests/wpt/meta/dom/nodes/moveBefore/tentative/custom-element-move-reactions.html.ini12
-rw-r--r--tests/wpt/meta/encoding/legacy-mb-tchinese/big5/big5-decode-csbig5.html.ini29
-rw-r--r--tests/wpt/meta/fetch/metadata/generated/css-font-face.https.sub.tentative.html.ini3
-rw-r--r--tests/wpt/meta/fetch/metadata/generated/css-images.sub.tentative.html.ini3
-rw-r--r--tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html.ini1
-rw-r--r--tests/wpt/meta/html/canvas/element/text/2d.text.measure.text-clusters-position.tentative.html.ini3
-rw-r--r--tests/wpt/meta/html/canvas/element/text/2d.text.measure.text-clusters-range.tentative.html.ini3
-rw-r--r--tests/wpt/meta/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.w.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.worker.js.ini78
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.w.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.worker.js.ini78
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.w.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.worker.js.ini78
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.w.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.worker.js.ini78
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.w.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.worker.js.ini78
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.w.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.worker.js.ini78
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.w.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.worker.js.ini78
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.w.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.worker.js.ini78
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.w.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.worker.js.ini78
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.w.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.worker.js.ini78
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.w.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.worker.js.ini78
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.w.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.worker.js.ini78
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.html.ini3
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.worker.js.ini3
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.html.ini3
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.worker.js.ini3
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.w.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.w.html.ini2
-rw-r--r--tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative.w.html.ini2
-rw-r--r--tests/wpt/meta/html/dom/elements/the-innertext-and-outertext-properties/innertext-whitespace-pre-line.html.ini3
-rw-r--r--tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini2
-rw-r--r--tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini2
-rw-r--r--tests/wpt/meta/html/semantics/forms/form-submission-0/reparent-form-during-planned-navigation-task.html.ini4
-rw-r--r--tests/wpt/meta/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html.ini3
-rw-r--r--tests/wpt/meta/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html.ini15
-rw-r--r--tests/wpt/meta/selection/caret-position-should-be-correct-while-moveup-movedown.html.ini72
-rw-r--r--tests/wpt/meta/selection/shadow-dom/tentative/Selection-getComposedRanges-dom-mutations-removal.html.ini32
-rw-r--r--tests/wpt/meta/selection/shadow-dom/tentative/Selection-getComposedRanges-slot.html.ini9
-rw-r--r--tests/wpt/meta/url/failure.html.ini3
-rw-r--r--tests/wpt/meta/wasm/jsapi/jspi/js-promise-integration.any.js.ini63
-rw-r--r--tests/wpt/meta/wasm/jsapi/jspi/rejects.any.js.ini32
-rw-r--r--tests/wpt/meta/webxr/render_state_update.https.html.ini2
-rw-r--r--tests/wpt/tests/.github/workflows/safari-wptrunner.yml115
-rw-r--r--tests/wpt/tests/.github/workflows/safari_stable.yml87
-rw-r--r--tests/wpt/tests/.github/workflows/safari_technology_preview.yml90
-rw-r--r--tests/wpt/tests/IndexedDB/cursor-overloads.any.js87
-rw-r--r--tests/wpt/tests/IndexedDB/cursor-overloads.htm88
-rw-r--r--tests/wpt/tests/IndexedDB/delete-request-queue.any.js23
-rw-r--r--tests/wpt/tests/IndexedDB/delete-request-queue.html27
-rw-r--r--tests/wpt/tests/IndexedDB/error-attributes.any.js32
-rw-r--r--tests/wpt/tests/IndexedDB/error-attributes.html38
-rw-r--r--tests/wpt/tests/IndexedDB/upgrade-transaction-deactivation-timing.any.js46
-rw-r--r--tests/wpt/tests/IndexedDB/upgrade-transaction-deactivation-timing.html48
-rw-r--r--tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-backend-aborted.any.js76
-rw-r--r--tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-backend-aborted.html84
-rw-r--r--tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-committed.any.js73
-rw-r--r--tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-committed.html80
-rw-r--r--tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-user-aborted.any.js (renamed from tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-user-aborted.html)27
-rw-r--r--tests/wpt/tests/WebCryptoAPI/import_export/okp_importKey.js80
-rw-r--r--tests/wpt/tests/attribution-reporting/aggregatable-report-no-contributions.sub.https.html1
-rw-r--r--tests/wpt/tests/attribution-reporting/resources/helpers.js41
-rw-r--r--tests/wpt/tests/attribution-reporting/simple-verbose-debug-report.sub.https.html1
-rw-r--r--tests/wpt/tests/clipboard-apis/async-navigator-clipboard-basics.https.html44
-rw-r--r--tests/wpt/tests/close-watcher/user-activation/y-dialog-disconnected.html43
-rw-r--r--tests/wpt/tests/close-watcher/user-activation/y-popover-disconnected.html43
-rw-r--r--tests/wpt/tests/css/CSS2/ui/overflow-applies-to-009.xht6
-rw-r--r--tests/wpt/tests/css/css-align/blocks/justify-self-block-in-inline.html12
-rw-r--r--tests/wpt/tests/css/css-anchor-position/anchor-scope-basic.html30
-rw-r--r--tests/wpt/tests/css/css-anchor-position/try-tactic-wm.html4
-rw-r--r--tests/wpt/tests/css/css-break/text-indent-and-wide-float.html18
-rw-r--r--tests/wpt/tests/css/css-break/transform-025.html13
-rw-r--r--tests/wpt/tests/css/css-color/parsing/color-computed-relative-color.html14
-rw-r--r--tests/wpt/tests/css/css-color/parsing/color-valid-relative-color.html1
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/at-container-style-serialization.html2
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-overflowing-parsing.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/at-container-overflowing-parsing.html)0
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-overflowing-serialization.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/at-container-overflowing-serialization.html)0
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-snapped-parsing.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/at-container-snapped-parsing.html)0
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-snapped-serialization.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/at-container-snapped-serialization.html)0
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-stuck-parsing.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/at-container-stuck-parsing.html)0
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-stuck-serialization.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/at-container-stuck-serialization.html)0
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-computed.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/container-type-scroll-state-computed.html)0
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-containment.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/container-type-scroll-state-containment.html)0
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-parsing.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/container-type-scroll-state-parsing.html)0
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-initially-snapped.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/scroll-state-initially-snapped.html)0
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-initially-stuck.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/scroll-state-initially-stuck.html)0
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-change.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/scroll-state-snapped-change.html)0
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-container-type-change.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/scroll-state-snapped-container-type-change.html)2
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-none.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/scroll-state-snapped-none.html)0
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-snap-changing.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/scroll-state-snapped-snap-changing.html)0
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-wm.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/scroll-state-snapped-wm.html)0
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-container-type-change.html48
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-writing-direction.html82
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-target-query-change.html (renamed from tests/wpt/tests/css/css-conditional/container-queries/scroll-state-target-query-change.html)0
-rw-r--r--tests/wpt/tests/css/css-conditional/container-queries/size-container-writing-mode-change.html36
-rw-r--r--tests/wpt/tests/css/css-multicol/crashtests/text-box-trim-end-and-widows.html9
-rw-r--r--tests/wpt/tests/css/css-overflow/line-clamp/reference/webkit-line-clamp-050-ref.html18
-rw-r--r--tests/wpt/tests/css/css-overflow/line-clamp/webkit-line-clamp-050.html30
-rw-r--r--tests/wpt/tests/css/css-pseudo/first-line-below-float.html23
-rw-r--r--tests/wpt/tests/css/css-pseudo/parsing/the-check-pseudo-element.tentative.html32
-rw-r--r--tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-001.tentative.html2
-rw-r--r--tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-002.tentative.html2
-rw-r--r--tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-003.tentative.html2
-rw-r--r--tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-004.tentative.html2
-rw-r--r--tests/wpt/tests/css/css-scroll-anchoring/start-edge-in-block-layout-direction.html26
-rw-r--r--tests/wpt/tests/css/css-sizing/animation/height-interpolation.html15
-rw-r--r--tests/wpt/tests/css/css-sizing/keyword-sizes-on-inline-block.html2
-rw-r--r--tests/wpt/tests/css/css-sizing/stretch/abspos-1.html21
-rw-r--r--tests/wpt/tests/css/css-sizing/stretch/abspos-2.html22
-rw-r--r--tests/wpt/tests/css/css-sizing/stretch/bfc-next-to-float-1.html23
-rw-r--r--tests/wpt/tests/css/css-sizing/stretch/block-height-1.html128
-rw-r--r--tests/wpt/tests/css/css-sizing/stretch/block-height-2.html31
-rw-r--r--tests/wpt/tests/css/css-sizing/stretch/min-width-1.html7
-rw-r--r--tests/wpt/tests/css/css-sizing/stretch/parsing.html28
-rw-r--r--tests/wpt/tests/css/css-sizing/stretch/positioned-non-replaced-1.html20
-rw-r--r--tests/wpt/tests/css/css-sizing/stretch/positioned-replaced-1.html18
-rw-r--r--tests/wpt/tests/css/css-text/text-indent/below-float.html14
-rw-r--r--tests/wpt/tests/css/css-ui/crashtests/text-overflow-ellipsis-multiline-crash.html15
-rw-r--r--tests/wpt/tests/css/css-ui/reference/text-overflow-ellipsis-multiline-001-ref.html13
-rw-r--r--tests/wpt/tests/css/css-ui/text-overflow-ellipsis-multiline-001.html18
-rw-r--r--tests/wpt/tests/css/css-values/calc-serialization-002.html2
-rw-r--r--tests/wpt/tests/css/css-values/calc-size/animation/calc-size-height-interpolation.html4
-rw-r--r--tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-height-composition.html19
-rw-r--r--tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-max-height-composition.html26
-rw-r--r--tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-max-width-composition.html22
-rw-r--r--tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-min-height-composition.html22
-rw-r--r--tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-min-width-composition.html27
-rw-r--r--tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-width-composition.html14
-rw-r--r--tests/wpt/tests/css/css-values/minmax-length-percent-serialize.html4
-rw-r--r--tests/wpt/tests/css/css-values/round-function.html7
-rw-r--r--tests/wpt/tests/css/css-view-transitions/inline-child-with-overflow-shadow-ref.html30
-rw-r--r--tests/wpt/tests/css/css-view-transitions/inline-child-with-overflow-shadow.html60
-rw-r--r--tests/wpt/tests/css/css-view-transitions/inline-with-offset-from-containing-block.html2
-rw-r--r--tests/wpt/tests/css/css-view-transitions/layered-capture/capture-mode-flat.tentative.html45
-rw-r--r--tests/wpt/tests/css/css-view-transitions/layered-capture/capture-mode-layered.tentative.html45
-rw-r--r--tests/wpt/tests/css/css-view-transitions/layered-capture/nested-opacity-backdrop-blend-animated.tentative.html (renamed from tests/wpt/tests/css/css-view-transitions/nested/opacity-backdrop-blend-animated.tentative.html)2
-rw-r--r--tests/wpt/tests/css/css-view-transitions/layered-capture/nested-opacity-backdrop-blend.tentative.html (renamed from tests/wpt/tests/css/css-view-transitions/nested/opacity-backdrop-blend.tentative.html)2
-rw-r--r--tests/wpt/tests/css/css-view-transitions/layered-capture/opacity-computed-style.tentative.html (renamed from tests/wpt/tests/css/css-view-transitions/nested/opacity-computed-style.tentative.html)0
-rw-r--r--tests/wpt/tests/css/css-view-transitions/layered-capture/opacity-resets-after-done.tentative.html (renamed from tests/wpt/tests/css/css-view-transitions/nested/opacity-resets-after-done.tentative.html)0
-rw-r--r--tests/wpt/tests/css/css-view-transitions/layered-capture/opacity-resets-after-skip.tentative.html (renamed from tests/wpt/tests/css/css-view-transitions/nested/opacity-resets-after-skip.tentative.html)0
-rw-r--r--tests/wpt/tests/css/css-view-transitions/layered-capture/parsing/view-transition-capture-mode-invalid.tentative.html18
-rw-r--r--tests/wpt/tests/css/css-view-transitions/layered-capture/parsing/view-transition-capture-mode-valid.tentative.html18
-rw-r--r--tests/wpt/tests/css/css-view-transitions/nested-elements-in-overflow-ref.html36
-rw-r--r--tests/wpt/tests/css/css-view-transitions/nested-elements-in-overflow.html71
-rw-r--r--tests/wpt/tests/css/css-view-transitions/new-and-old-sizes-match.html2
-rw-r--r--tests/wpt/tests/css/css-view-transitions/outer-padding-inner-background-ref.html26
-rw-r--r--tests/wpt/tests/css/css-view-transitions/outer-padding-inner-background.html57
-rw-r--r--tests/wpt/tests/css/filter-effects/backdrop-filter-plus-filter.html1
-rw-r--r--tests/wpt/tests/custom-elements/CustomElementRegistry.html35
-rw-r--r--tests/wpt/tests/digital-credentials/allow-attribute.https.html2
-rw-r--r--tests/wpt/tests/digital-credentials/support/iframe.html1
-rw-r--r--tests/wpt/tests/dom/nodes/moveBefore/tentative/custom-element-move-reactions.html98
-rw-r--r--tests/wpt/tests/editing/data/inserthtml.js26
-rw-r--r--tests/wpt/tests/editing/data/insertimage.js3
-rw-r--r--tests/wpt/tests/editing/data/inserttext.js74
-rw-r--r--tests/wpt/tests/editing/other/delete-before-invisible-line-break.html154
-rw-r--r--tests/wpt/tests/editing/other/double-click-range-selection-in-floating-list-item.html71
-rw-r--r--tests/wpt/tests/editing/other/double-click-range-selection-in-list-item.html72
-rw-r--r--tests/wpt/tests/editing/other/forwarddelete-before-invisible-line-break.html154
-rw-r--r--tests/wpt/tests/editing/plaintext-only/insertText.html76
-rw-r--r--tests/wpt/tests/eyedropper/idlharness.https.window.js7
-rw-r--r--tests/wpt/tests/fenced-frame/http-localhost-url.https.html25
-rw-r--r--tests/wpt/tests/fledge/tentative/get-interest-group-auction-data.https.window.js26
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage.html845
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage.pngbin0 -> 2291 bytes
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect.html767
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect.pngbin0 -> 2291 bytes
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern.html871
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern.pngbin0 -> 2291 bytes
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage.html897
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage.pngbin0 -> 4085 bytes
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect.html819
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect.pngbin0 -> 4085 bytes
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern.html923
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern.pngbin0 -> 4085 bytes
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html845
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.pngbin0 -> 1572 bytes
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html767
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.pngbin0 -> 1572 bytes
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html871
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern.pngbin0 -> 1572 bytes
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage.html897
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage.pngbin0 -> 2314 bytes
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect.html819
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect.pngbin0 -> 2314 bytes
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern.html923
-rw-r--r--tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern.pngbin0 -> 2314 bytes
-rw-r--r--tests/wpt/tests/html/canvas/element/text/2d.text.draw.fill.basic.pngbin1107 -> 1137 bytes
-rw-r--r--tests/wpt/tests/html/canvas/element/text/2d.text.draw.fill.maxWidth.large.pngbin1107 -> 1137 bytes
-rw-r--r--tests/wpt/tests/html/canvas/element/text/2d.text.draw.fill.rtl.pngbin1107 -> 1137 bytes
-rw-r--r--tests/wpt/tests/html/canvas/element/text/2d.text.draw.stroke.basic.pngbin1521 -> 1634 bytes
-rw-r--r--tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-position.tentative.html54
-rw-r--r--tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-range.tentative.html77
-rw-r--r--tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative-expected.html77
-rw-r--r--tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative.html90
-rw-r--r--tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative-expected.html87
-rw-r--r--tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html116
-rw-r--r--tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-font-change.tentative-expected.html22
-rw-r--r--tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-font-change.tentative.html27
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.html949
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.pngbin0 -> 2291 bytes
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.w.html1316
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.worker.js685
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.html871
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.pngbin0 -> 2291 bytes
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.w.html1238
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.worker.js607
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.html975
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.pngbin0 -> 2291 bytes
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.w.html1342
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.worker.js711
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.html1001
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.pngbin0 -> 4085 bytes
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.w.html1368
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.worker.js737
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.html923
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.pngbin0 -> 4085 bytes
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.w.html1290
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.worker.js659
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.html1027
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.pngbin0 -> 4085 bytes
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.w.html1394
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.worker.js763
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html949
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.pngbin0 -> 1572 bytes
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.w.html1316
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.worker.js685
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html871
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.pngbin0 -> 1572 bytes
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.w.html1238
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.worker.js607
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html975
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.pngbin0 -> 1572 bytes
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.w.html1342
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.worker.js711
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.html1001
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.pngbin0 -> 2314 bytes
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.w.html1368
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.worker.js737
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.html923
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.pngbin0 -> 2314 bytes
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.w.html1290
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.worker.js659
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern-expected.html270
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.html1027
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.pngbin0 -> 2314 bytes
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.w.html1394
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.worker.js763
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.fill.basic.pngbin1107 -> 1137 bytes
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.large.pngbin1107 -> 1137 bytes
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.fill.rtl.pngbin1107 -> 1137 bytes
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.stroke.basic.pngbin1521 -> 1634 bytes
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.html43
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.worker.js36
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.html66
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.worker.js59
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative-expected.html77
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.html102
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.w.html147
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative-expected.html87
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html132
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.w.html191
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative-expected.html22
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative.html30
-rw-r--r--tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative.w.html44
-rw-r--r--tests/wpt/tests/html/canvas/tools/gentestutilsunion.py122
-rw-r--r--tests/wpt/tests/html/canvas/tools/templates/reftest_img.html8
-rw-r--r--tests/wpt/tests/html/canvas/tools/templates/reftest_img_grid.html27
-rw-r--r--tests/wpt/tests/html/canvas/tools/yaml-new/compositing.yaml176
-rw-r--r--tests/wpt/tests/html/canvas/tools/yaml-new/text.yaml194
-rw-r--r--tests/wpt/tests/html/dom/documents/dom-tree-accessors/nameditem-names.html2
-rw-r--r--tests/wpt/tests/html/dom/elements/the-innertext-and-outertext-properties/innertext-whitespace-pre-line.html42
-rw-r--r--tests/wpt/tests/html/rendering/non-replaced-elements/tables/table-align-float-ref.xhtml27
-rw-r--r--tests/wpt/tests/html/rendering/non-replaced-elements/tables/table-align-float.xhtml26
-rw-r--r--tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/button-in-popover.tentative.html40
-rw-r--r--tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html11
-rw-r--r--tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/popover-dialog-does-not-block-mouse-events.html49
-rw-r--r--tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html108
-rw-r--r--tests/wpt/tests/html/webappapis/update-rendering/child-document-raf-order.html28
-rw-r--r--tests/wpt/tests/interfaces/turtledove.idl15
-rw-r--r--tests/wpt/tests/mediacapture-insertable-streams/VideoTrackGenerator-with-window-tracks.https.html14
-rw-r--r--tests/wpt/tests/navigation-api/state/cross-document-away-and-back.html6
-rw-r--r--tests/wpt/tests/navigation-api/state/cross-document-location-api.html6
-rw-r--r--tests/wpt/tests/navigation-api/state/history-pushState.html6
-rw-r--r--tests/wpt/tests/navigation-api/state/history-replaceState.html6
-rw-r--r--tests/wpt/tests/navigation-api/state/location-reload.html6
-rw-r--r--tests/wpt/tests/navigation-api/state/resources/helpers.js18
-rw-r--r--tests/wpt/tests/navigation-api/updateCurrentEntry-method/cross-document-away-and-back.html31
-rw-r--r--tests/wpt/tests/navigation-api/updateCurrentEntry-method/cross-document-location-api.html20
-rw-r--r--tests/wpt/tests/navigation-api/updateCurrentEntry-method/history-pushState.html11
-rw-r--r--tests/wpt/tests/navigation-api/updateCurrentEntry-method/history-replaceState.html11
-rw-r--r--tests/wpt/tests/navigation-api/updateCurrentEntry-method/location-reload.html19
-rw-r--r--tests/wpt/tests/permissions-policy/resources/digital-credentials-get.html1
-rw-r--r--tests/wpt/tests/sanitizer-api/html5lib-basics.tentative.html95
-rw-r--r--tests/wpt/tests/sanitizer-api/support/html5lib-testcase-support.js196
-rw-r--r--tests/wpt/tests/scroll-animations/css/animation-timeline-computed.html3
-rw-r--r--tests/wpt/tests/scroll-animations/css/animation-timeline-parsing.html1
-rw-r--r--tests/wpt/tests/scroll-animations/scroll-timelines/setting-current-time.html6
-rw-r--r--tests/wpt/tests/scroll-animations/scroll-timelines/setting-start-time.html6
-rw-r--r--tests/wpt/tests/selection/caret-position-should-be-correct-while-moveup-movedown.html450
-rw-r--r--tests/wpt/tests/selection/shadow-dom/tentative/Selection-getComposedRanges-collapsed.html16
-rw-r--r--tests/wpt/tests/selection/shadow-dom/tentative/Selection-getComposedRanges-dom-mutations-removal.html110
-rw-r--r--tests/wpt/tests/selection/shadow-dom/tentative/Selection-getComposedRanges-slot.html124
-rw-r--r--tests/wpt/tests/shadow-dom/focus-navigation/reading-flow/tentative/grid-order-across-scopes.html6
-rw-r--r--tests/wpt/tests/shadow-dom/focus-navigation/reading-flow/tentative/grid-order-with-display-contents.html12
-rw-r--r--tests/wpt/tests/shadow-dom/focus-navigation/reading-flow/tentative/grid-order-with-slots.html12
-rw-r--r--tests/wpt/tests/shared-storage/interest-groups.tentative.https.sub.html41
-rw-r--r--tests/wpt/tests/shared-storage/resources/simple-module.js53
-rw-r--r--tests/wpt/tests/shared-storage/web-locks.tentative.https.sub.html62
-rw-r--r--tests/wpt/tests/speculation-rules/prerender/resources/csp-script-src-self.html8
-rw-r--r--tests/wpt/tests/storage/quotachange-in-detached-iframe.tentative.https.html21
-rw-r--r--tests/wpt/tests/svg/animations/animate-display-to-none-001.html30
-rw-r--r--tests/wpt/tests/svg/painting/reftests/small-nested-viewbox-ref.html14
-rw-r--r--tests/wpt/tests/svg/painting/reftests/small-nested-viewbox.html19
-rw-r--r--tests/wpt/tests/tools/certs/cacert.key56
-rw-r--r--tests/wpt/tests/tools/certs/cacert.pem246
-rw-r--r--tests/wpt/tests/tools/certs/web-platform.test.key52
-rw-r--r--tests/wpt/tests/tools/certs/web-platform.test.pem214
-rw-r--r--tests/wpt/tests/tools/ci/jobs.py11
-rw-r--r--tests/wpt/tests/tools/wptrunner/wptrunner/browsers/chrome_spki_certs.py2
-rw-r--r--tests/wpt/tests/tools/wptrunner/wptrunner/executors/executorchrome.py114
-rw-r--r--tests/wpt/tests/tools/wptrunner/wptrunner/executors/executoredge.py4
-rw-r--r--tests/wpt/tests/tools/wptrunner/wptrunner/executors/executorwebdriver.py88
-rw-r--r--tests/wpt/tests/tools/wptrunner/wptrunner/executors/protocol.py1
-rw-r--r--tests/wpt/tests/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.html14
-rw-r--r--tests/wpt/tests/trusted-types/support/navigation-report-only-support.html49
-rw-r--r--tests/wpt/tests/trusted-types/support/navigation-support.html47
-rw-r--r--tests/wpt/tests/trusted-types/support/navigation-support.js75
-rw-r--r--tests/wpt/tests/trusted-types/trusted-types-navigation.html209
-rw-r--r--tests/wpt/tests/url/resources/urltestdata.json96
-rw-r--r--tests/wpt/tests/wasm/jsapi/jspi/README.txt3
-rw-r--r--tests/wpt/tests/wasm/jsapi/jspi/js-promise-integration.any.js372
-rw-r--r--tests/wpt/tests/wasm/jsapi/jspi/rejects.any.js143
-rw-r--r--tests/wpt/tests/wasm/jsapi/jspi/testharness-additions.js26
-rw-r--r--tests/wpt/tests/wasm/jsapi/memory/assertions.js2
-rw-r--r--tests/wpt/tests/wasm/jsapi/table/assertions.js2
-rw-r--r--tests/wpt/tests/wasm/jsapi/wasm-module-builder.js110
-rw-r--r--tests/wpt/tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-resume-after-suspended.html106
-rw-r--r--tests/wpt/tests/webaudio/the-audio-api/the-audiocontext-interface/processing-after-resume.https.html67
-rw-r--r--tests/wpt/tests/webdriver/tests/bidi/browsing_context/capture_screenshot/frame_tentative.py (renamed from tests/wpt/tests/webdriver/tests/bidi/browsing_context/capture_screenshot/frame.py)0
-rw-r--r--tests/wpt/tests/webdriver/tests/bidi/browsing_context/print/context.py48
-rw-r--r--tests/wpt/tests/webdriver/tests/bidi/browsing_context/print/frame_tentative.py49
-rw-r--r--tests/wpt/tests/webdriver/tests/bidi/network/__init__.py3
-rw-r--r--tests/wpt/tests/webdriver/tests/bidi/network/before_request_sent/before_request_sent_cached.py64
-rw-r--r--tests/wpt/tests/webdriver/tests/bidi/network/response_completed/response_completed_cached.py68
-rw-r--r--tests/wpt/tests/webdriver/tests/bidi/network/response_started/response_started_cached.py68
-rw-r--r--tests/wpt/tests/webnn/conformance_tests/byob_readtensor.https.any.js7
-rw-r--r--tests/wpt/tests/webnn/conformance_tests/dequantizeLinear.https.any.js191
-rw-r--r--tests/wpt/tests/webnn/conformance_tests/gather.https.any.js52
-rw-r--r--tests/wpt/tests/webnn/conformance_tests/gatherND.https.any.js177
-rw-r--r--tests/wpt/tests/webnn/conformance_tests/inputs-are-not-modified.https.any.js12
-rw-r--r--tests/wpt/tests/webnn/conformance_tests/logical_and.https.any.js4
-rw-r--r--tests/wpt/tests/webnn/conformance_tests/logical_or.https.any.js4
-rw-r--r--tests/wpt/tests/webnn/conformance_tests/logical_xor.https.any.js6
-rw-r--r--tests/wpt/tests/webnn/conformance_tests/parallel-dispatch.https.any.js27
-rw-r--r--tests/wpt/tests/webnn/conformance_tests/quantizeLinear.https.any.js187
-rw-r--r--tests/wpt/tests/webnn/conformance_tests/scatterElements.https.any.js91
-rw-r--r--tests/wpt/tests/webnn/conformance_tests/tensor.https.any.js46
-rw-r--r--tests/wpt/tests/webnn/resources/utils.js76
-rw-r--r--tests/wpt/tests/webnn/validation_tests/constant.https.any.js7
-rw-r--r--tests/wpt/tests/webnn/validation_tests/destroyContext.https.any.js6
-rw-r--r--tests/wpt/tests/webnn/validation_tests/destroyGraph.https.any.js6
-rw-r--r--tests/wpt/tests/webnn/validation_tests/input.https.any.js9
-rw-r--r--tests/wpt/tests/webnn/validation_tests/scatterElements.https.any.js150
-rw-r--r--tests/wpt/tests/webrtc/RTCPeerConnection-getStats-timestamp.https.html17
-rw-r--r--tests/wpt/tests/webrtc/RTCRtpEncodingParameters-codec-opus-stereo.https.html113
-rw-r--r--tests/wpt/tests/xhr/formdata/constructor-submitter-coordinate.html19
-rw-r--r--tests/wpt/tests/xhr/formdata/submitter-coordinate-value.html55
632 files changed, 69308 insertions, 3070 deletions
diff --git a/tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.js.ini b/tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.js.ini
index 53ae48faf06..813a67f7fcd 100644
--- a/tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.js.ini
+++ b/tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.js.ini
@@ -92,6 +92,99 @@
[Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), {name: Ed25519}, false, [sign, sign\])]
expected: FAIL
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), Ed25519, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), Ed25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), Ed25519, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(crv, d, x, kty), Ed25519, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(crv, d, x, kty), Ed25519, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, false, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, false, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, false, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, false, [sign, sign\])]
+ expected: FAIL
+
[okp_importKey_Ed25519.https.any.html]
[Good parameters: Ed25519 bits (spki, buffer(44), {name: Ed25519}, true, [verify\])]
@@ -186,3 +279,96 @@
[Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), {name: Ed25519}, false, [sign, sign\])]
expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), Ed25519, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), Ed25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), Ed25519, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(crv, d, x, kty), Ed25519, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(crv, d, x, kty), Ed25519, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, false, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, false, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, false, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, false, [sign, sign\])]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_Ed448.https.any.js.ini b/tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_Ed448.https.any.js.ini
index a648a2c9e95..b1f80afada5 100644
--- a/tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_Ed448.https.any.js.ini
+++ b/tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_Ed448.https.any.js.ini
@@ -92,6 +92,99 @@
[Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), {name: Ed448}, false, [sign, sign\])]
expected: FAIL
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(kty, crv, x), Ed448, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, true, [\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(kty, crv, x), Ed448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(kty, crv, x), Ed448, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (pkcs8, buffer(73), Ed448, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), Ed448, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(crv, d, x, kty), Ed448, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (pkcs8, buffer(73), Ed448, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), Ed448, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(crv, d, x, kty), Ed448, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (pkcs8, buffer(73), Ed448, false, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), Ed448, false, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (pkcs8, buffer(73), Ed448, false, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), Ed448, false, [sign, sign\])]
+ expected: FAIL
+
[okp_importKey_Ed448.https.any.html]
[Good parameters: Ed448 bits (spki, buffer(69), {name: Ed448}, true, [verify\])]
@@ -186,3 +279,96 @@
[Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), {name: Ed448}, false, [sign, sign\])]
expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(kty, crv, x), Ed448, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, true, [\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(kty, crv, x), Ed448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(kty, crv, x), Ed448, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (pkcs8, buffer(73), Ed448, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), Ed448, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(crv, d, x, kty), Ed448, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (pkcs8, buffer(73), Ed448, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), Ed448, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(crv, d, x, kty), Ed448, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (pkcs8, buffer(73), Ed448, false, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), Ed448, false, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (pkcs8, buffer(73), Ed448, false, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), Ed448, false, [sign, sign\])]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.js.ini b/tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.js.ini
index 6bf07f7980f..f35c0980194 100644
--- a/tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.js.ini
+++ b/tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.js.ini
@@ -80,6 +80,87 @@
[Good parameters: X25519 bits (jwk, object(crv, d, x, kty), {name: X25519}, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
expected: FAIL
+ [Good parameters: X25519 bits (spki, buffer(44), X25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(kty, crv, x), X25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(kty, crv, x), X25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (raw, buffer(32), X25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), X25519, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), X25519, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), X25519, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), X25519, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (spki, buffer(44), X25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(kty, crv, x), X25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (raw, buffer(32), X25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, false, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, false, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, false, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, false, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, false, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, false, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
[okp_importKey_X25519.https.any.worker.html]
[Good parameters: X25519 bits (spki, buffer(44), {name: X25519}, true, [\])]
@@ -162,3 +243,84 @@
[Good parameters: X25519 bits (jwk, object(crv, d, x, kty), {name: X25519}, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
expected: FAIL
+
+ [Good parameters: X25519 bits (spki, buffer(44), X25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(kty, crv, x), X25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(kty, crv, x), X25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (raw, buffer(32), X25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), X25519, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), X25519, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), X25519, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), X25519, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (spki, buffer(44), X25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(kty, crv, x), X25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (raw, buffer(32), X25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, false, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, false, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, false, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, false, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, false, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, false, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_X448.https.any.js.ini b/tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_X448.https.any.js.ini
index 9120981ca5b..1911cc7fa63 100644
--- a/tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_X448.https.any.js.ini
+++ b/tests/wpt/meta-legacy-layout/WebCryptoAPI/import_export/okp_importKey_X448.https.any.js.ini
@@ -80,6 +80,87 @@
[Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
expected: FAIL
+ [Good parameters: X448 bits (spki, buffer(68), X448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(kty, crv, x), X448, true, [\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(kty, crv, x), X448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (raw, buffer(56), X448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), X448, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), X448, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), X448, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), X448, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (spki, buffer(68), X448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(kty, crv, x), X448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (raw, buffer(56), X448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, false, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, false, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, false, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, false, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, false, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, false, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
[okp_importKey_X448.https.any.html]
[Good parameters: X448 bits (spki, buffer(68), {name: X448}, true, [\])]
@@ -162,3 +243,84 @@
[Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
expected: FAIL
+
+ [Good parameters: X448 bits (spki, buffer(68), X448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(kty, crv, x), X448, true, [\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(kty, crv, x), X448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (raw, buffer(56), X448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), X448, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), X448, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), X448, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), X448, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (spki, buffer(68), X448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(kty, crv, x), X448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (raw, buffer(56), X448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, false, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, false, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, false, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, false, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, false, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, false, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-color/parsing/color-computed-relative-color.html.ini b/tests/wpt/meta-legacy-layout/css/css-color/parsing/color-computed-relative-color.html.ini
index d4e0b6dccc5..70aa2015799 100644
--- a/tests/wpt/meta-legacy-layout/css/css-color/parsing/color-computed-relative-color.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-color/parsing/color-computed-relative-color.html.ini
@@ -3697,3 +3697,9 @@
[Property background-color value 'hsl(from currentColor calc((h / 360) * 360deg) s l)']
expected: FAIL
+
+ [Property color value 'light-dark(rgb(from rebeccapurple r g b), rgb(from rebeccapurple r g b))']
+ expected: FAIL
+
+ [Property color value 'light-dark(color-mix(in srgb, rgb(from rebeccapurple none g b), rebeccapurple), color-mix(in srgb, rgb(from rebeccapurple none g b), rebeccapurple))']
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-color/parsing/color-valid-relative-color.html.ini b/tests/wpt/meta-legacy-layout/css/css-color/parsing/color-valid-relative-color.html.ini
index 3d655cd0048..380c9a54f3f 100644
--- a/tests/wpt/meta-legacy-layout/css/css-color/parsing/color-valid-relative-color.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-color/parsing/color-valid-relative-color.html.ini
@@ -3724,3 +3724,6 @@
[e.style['color'\] = "color(from color-mix(in xyz-d65, color(xyz-d65 0.7 0.5 0.3), color(xyz-d65 0.7 0.5 0.3)) xyz-d65 x y z / alpha)" should set the property value]
expected: FAIL
+
+ [e.style['color'\] = "oklch(from red calc(1 / l) c h)" should set the property value]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-overflowing-parsing.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-overflowing-parsing.html.ini
index 72f4601118a..72f4601118a 100644
--- a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-overflowing-parsing.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-overflowing-parsing.html.ini
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-overflowing-serialization.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-overflowing-serialization.html.ini
index 18c1abafcc7..18c1abafcc7 100644
--- a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-overflowing-serialization.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-overflowing-serialization.html.ini
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-snapped-parsing.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-snapped-parsing.html.ini
index 6ad6378fe26..6ad6378fe26 100644
--- a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-snapped-parsing.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-snapped-parsing.html.ini
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-snapped-serialization.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-snapped-serialization.html.ini
index 35c90640507..35c90640507 100644
--- a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-snapped-serialization.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-snapped-serialization.html.ini
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-stuck-parsing.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-stuck-parsing.html.ini
index 849d4af452a..849d4af452a 100644
--- a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-stuck-parsing.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-stuck-parsing.html.ini
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-stuck-serialization.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-stuck-serialization.html.ini
index 95ca2e600cb..95ca2e600cb 100644
--- a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/at-container-stuck-serialization.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/at-container-stuck-serialization.html.ini
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/container-type-scroll-state-computed.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-computed.html.ini
index bf71bdf192b..bf71bdf192b 100644
--- a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/container-type-scroll-state-computed.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-computed.html.ini
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/container-type-scroll-state-containment.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-containment.html.ini
index 6816d82fe23..6816d82fe23 100644
--- a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/container-type-scroll-state-containment.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-containment.html.ini
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/container-type-scroll-state-parsing.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-parsing.html.ini
index 77be49bdc31..77be49bdc31 100644
--- a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/container-type-scroll-state-parsing.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-parsing.html.ini
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-initially-snapped.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-initially-snapped.html.ini
index 0b354083d7a..0b354083d7a 100644
--- a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-initially-snapped.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-initially-snapped.html.ini
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-initially-stuck.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-initially-stuck.html.ini
index 7260020fd97..7260020fd97 100644
--- a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-initially-stuck.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-initially-stuck.html.ini
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-snapped-change.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-change.html.ini
index 346d353eab5..346d353eab5 100644
--- a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-snapped-change.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-change.html.ini
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-snapped-container-type-change.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-container-type-change.html.ini
index a1cd47a47cc..a1cd47a47cc 100644
--- a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-snapped-container-type-change.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-container-type-change.html.ini
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-snapped-none.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-none.html.ini
index e5d314021fb..e5d314021fb 100644
--- a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-snapped-none.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-none.html.ini
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-snapped-wm.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-wm.html.ini
index a91d853ebd3..a91d853ebd3 100644
--- a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-snapped-wm.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-wm.html.ini
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-container-type-change.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-container-type-change.html.ini
new file mode 100644
index 00000000000..f0b3a1e7a8a
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-container-type-change.html.ini
@@ -0,0 +1,2 @@
+[scroll-state-stuck-container-type-change.html]
+ expected: ERROR
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-writing-direction.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-writing-direction.html.ini
new file mode 100644
index 00000000000..3caa58f120b
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-writing-direction.html.ini
@@ -0,0 +1,2 @@
+[scroll-state-stuck-writing-direction.html]
+ expected: ERROR
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-target-query-change.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-target-query-change.html.ini
index 8125d4e9608..8125d4e9608 100644
--- a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state-target-query-change.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/scroll-state/scroll-state-target-query-change.html.ini
diff --git a/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/size-container-writing-mode-change.html.ini b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/size-container-writing-mode-change.html.ini
new file mode 100644
index 00000000000..7e0cf86879c
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-conditional/container-queries/size-container-writing-mode-change.html.ini
@@ -0,0 +1,2 @@
+[size-container-writing-mode-change.html]
+ expected: ERROR
diff --git a/tests/wpt/meta-legacy-layout/css/css-fonts/generic-family-keywords-001.html.ini b/tests/wpt/meta-legacy-layout/css/css-fonts/generic-family-keywords-001.html.ini
index 8cfa1c28944..e7b1cf288a0 100644
--- a/tests/wpt/meta-legacy-layout/css/css-fonts/generic-family-keywords-001.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-fonts/generic-family-keywords-001.html.ini
@@ -8,17 +8,14 @@
[@font-face matching for quoted and unquoted serif]
expected: FAIL
- [@font-face matching for quoted and unquoted cursive]
- expected: FAIL
-
[@font-face matching for quoted and unquoted fantasy]
expected: FAIL
[@font-face matching for quoted and unquoted monospace]
expected: FAIL
- [@font-face matching for quoted and unquoted system-ui]
+ [@font-face matching for quoted and unquoted ui-monospace]
expected: FAIL
- [@font-face matching for quoted and unquoted ui-monospace]
+ [@font-face matching for quoted and unquoted emoji]
expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-overflow/line-clamp/webkit-line-clamp-050.html.ini b/tests/wpt/meta-legacy-layout/css/css-overflow/line-clamp/webkit-line-clamp-050.html.ini
new file mode 100644
index 00000000000..9a1676cf418
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-overflow/line-clamp/webkit-line-clamp-050.html.ini
@@ -0,0 +1,2 @@
+[webkit-line-clamp-050.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-pseudo/first-line-below-float.html.ini b/tests/wpt/meta-legacy-layout/css/css-pseudo/first-line-below-float.html.ini
new file mode 100644
index 00000000000..077242949df
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-pseudo/first-line-below-float.html.ini
@@ -0,0 +1,2 @@
+[first-line-below-float.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-pseudo/parsing/the-check-pseudo-element.tentative.html.ini b/tests/wpt/meta-legacy-layout/css/css-pseudo/parsing/the-check-pseudo-element.tentative.html.ini
new file mode 100644
index 00000000000..e06425a5209
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-pseudo/parsing/the-check-pseudo-element.tentative.html.ini
@@ -0,0 +1,18 @@
+[the-check-pseudo-element.tentative.html]
+ ["::check" should be a valid selector]
+ expected: FAIL
+
+ ["*::check" should be a valid selector]
+ expected: FAIL
+
+ ["foo.bar[baz\]::check" should be a valid selector]
+ expected: FAIL
+
+ ["::check::marker" should be a valid selector]
+ expected: FAIL
+
+ ["::slotted(*)::check" should be a valid selector]
+ expected: FAIL
+
+ ["::part(foo)::check" should be a valid selector]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-sizing/animation/height-interpolation.html.ini b/tests/wpt/meta-legacy-layout/css/css-sizing/animation/height-interpolation.html.ini
index 4e9354a0d3b..4ef5c8b240d 100644
--- a/tests/wpt/meta-legacy-layout/css/css-sizing/animation/height-interpolation.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-sizing/animation/height-interpolation.html.ini
@@ -478,3 +478,27 @@
[Web Animations: property <height> from neutral to [fit-content\] at (1.5) should be [fit-content\]]
expected: FAIL
+
+ [CSS Animations: property <height> from neutral to [100px\] at (0.5) should be [100px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from neutral to [100px\] at (0.6) should be [100px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from neutral to [100px\] at (1) should be [100px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from neutral to [100px\] at (1.5) should be [100px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from neutral to [100px\] at (0.5) should be [100px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from neutral to [100px\] at (0.6) should be [100px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from neutral to [100px\] at (1) should be [100px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from neutral to [100px\] at (1.5) should be [100px\]]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/abspos-1.html.ini b/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/abspos-1.html.ini
new file mode 100644
index 00000000000..c57e026f684
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/abspos-1.html.ini
@@ -0,0 +1,2 @@
+[abspos-1.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/abspos-2.html.ini b/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/abspos-2.html.ini
new file mode 100644
index 00000000000..c5dc50ec598
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/abspos-2.html.ini
@@ -0,0 +1,2 @@
+[abspos-2.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/bfc-next-to-float-1.html.ini b/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/bfc-next-to-float-1.html.ini
new file mode 100644
index 00000000000..e9afa40967e
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/bfc-next-to-float-1.html.ini
@@ -0,0 +1,2 @@
+[bfc-next-to-float-1.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/block-height-1.html.ini b/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/block-height-1.html.ini
new file mode 100644
index 00000000000..51f953f5c6a
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/block-height-1.html.ini
@@ -0,0 +1,27 @@
+[block-height-1.html]
+ [[data-expected-height\] 1]
+ expected: FAIL
+
+ [[data-expected-height\] 2]
+ expected: FAIL
+
+ [[data-expected-height\] 3]
+ expected: FAIL
+
+ [[data-expected-height\] 7]
+ expected: FAIL
+
+ [[data-expected-height\] 8]
+ expected: FAIL
+
+ [[data-expected-height\] 9]
+ expected: FAIL
+
+ [[data-expected-height\] 13]
+ expected: FAIL
+
+ [[data-expected-height\] 14]
+ expected: FAIL
+
+ [[data-expected-height\] 15]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/block-height-2.html.ini b/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/block-height-2.html.ini
new file mode 100644
index 00000000000..9b6449c79e3
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/block-height-2.html.ini
@@ -0,0 +1,6 @@
+[block-height-2.html]
+ [[data-expected-height\] 1]
+ expected: FAIL
+
+ [[data-expected-height\] 2]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/min-width-1.html.ini b/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/min-width-1.html.ini
new file mode 100644
index 00000000000..e3446c9bc89
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/min-width-1.html.ini
@@ -0,0 +1,2 @@
+[min-width-1.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/positioned-non-replaced-1.html.ini b/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/positioned-non-replaced-1.html.ini
new file mode 100644
index 00000000000..025f23f9b67
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/positioned-non-replaced-1.html.ini
@@ -0,0 +1,2 @@
+[positioned-non-replaced-1.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/positioned-replaced-1.html.ini b/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/positioned-replaced-1.html.ini
new file mode 100644
index 00000000000..062731ceee4
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-sizing/stretch/positioned-replaced-1.html.ini
@@ -0,0 +1,2 @@
+[positioned-replaced-1.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-text/white-space/white-space-intrinsic-size-021.html.ini b/tests/wpt/meta-legacy-layout/css/css-text/white-space/white-space-intrinsic-size-021.html.ini
index a1b8879de43..cf5d3972ffe 100644
--- a/tests/wpt/meta-legacy-layout/css/css-text/white-space/white-space-intrinsic-size-021.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-text/white-space/white-space-intrinsic-size-021.html.ini
@@ -65,18 +65,6 @@
[.container > div 77]
expected: FAIL
- [.container > div 103]
- expected: FAIL
-
- [.container > div 104]
- expected: FAIL
-
- [.container > div 127]
- expected: FAIL
-
- [.container > div 128]
- expected: FAIL
-
[.container > div 135]
expected: FAIL
@@ -110,14 +98,35 @@
[.container > div 152]
expected: FAIL
- [.container > div 169]
+ [.container > div 89]
+ expected: FAIL
+
+ [.container > div 91]
+ expected: FAIL
+
+ [.container > div 93]
+ expected: FAIL
+
+ [.container > div 119]
+ expected: FAIL
+
+ [.container > div 120]
+ expected: FAIL
+
+ [.container > div 159]
+ expected: FAIL
+
+ [.container > div 160]
+ expected: FAIL
+
+ [.container > div 177]
expected: FAIL
- [.container > div 170]
+ [.container > div 178]
expected: FAIL
- [.container > div 173]
+ [.container > div 181]
expected: FAIL
- [.container > div 174]
+ [.container > div 182]
expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-ui/text-overflow-ellipsis-multiline-001.html.ini b/tests/wpt/meta-legacy-layout/css/css-ui/text-overflow-ellipsis-multiline-001.html.ini
new file mode 100644
index 00000000000..6f62710f6d1
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-ui/text-overflow-ellipsis-multiline-001.html.ini
@@ -0,0 +1,2 @@
+[text-overflow-ellipsis-multiline-001.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-values/calc-serialization-002.html.ini b/tests/wpt/meta-legacy-layout/css/css-values/calc-serialization-002.html.ini
new file mode 100644
index 00000000000..e933384770c
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-values/calc-serialization-002.html.ini
@@ -0,0 +1,3 @@
+[calc-serialization-002.html]
+ [testing calc((min(10px, 20%) + max(1rem, 2%)) * 2)]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/calc-size-height-interpolation.html.ini b/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/calc-size-height-interpolation.html.ini
index 1ff5d2a7b72..a0f3ecf08a5 100644
--- a/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/calc-size-height-interpolation.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/calc-size-height-interpolation.html.ini
@@ -3796,3 +3796,123 @@
[Web Animations: property <height> from [calc-size(50px, size)\] to [calc-size(min-content, size)\] at (1) should be [100px\]]
expected: FAIL
+
+ [CSS Transitions: property <height> from [auto\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [auto\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [auto\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [auto\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [calc-size(any, 50px)\] to [calc-size(auto, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [calc-size(any, 50px)\] to [calc-size(auto, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(auto, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(auto, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [min-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [min-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [min-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [min-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [calc-size(any, 50px)\] to [calc-size(min-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [calc-size(any, 50px)\] to [calc-size(min-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(min-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(min-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [fit-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [fit-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [fit-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [fit-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [calc-size(any, 50px)\] to [calc-size(fit-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [calc-size(any, 50px)\] to [calc-size(fit-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(fit-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(fit-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [max-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [max-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [max-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [max-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [calc-size(any, 50px)\] to [calc-size(max-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [calc-size(any, 50px)\] to [calc-size(max-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(max-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(max-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [stretch\] to [calc-size(any, 50px)\] at (1.1) should be [25.000000000000007px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [stretch\] to [calc-size(any, 50px)\] at (1.1) should be [25.000000000000007px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [stretch\] to [calc-size(any, 50px)\] at (1.1) should be [25.000000000000007px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [stretch\] to [calc-size(any, 50px)\] at (1.1) should be [25.000000000000007px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [calc-size(any, 50px)\] to [calc-size(stretch, size * 2)\] at (-0.05) should be [22.5px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [calc-size(any, 50px)\] to [calc-size(stretch, size * 2)\] at (-0.05) should be [22.5px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(stretch, size * 2)\] at (-0.05) should be [22.5px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(stretch, size * 2)\] at (-0.05) should be [22.5px\]]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-max-height-composition.html.ini b/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-max-height-composition.html.ini
index c480e928296..7b0fbe413b9 100644
--- a/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-max-height-composition.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-max-height-composition.html.ini
@@ -28,3 +28,33 @@
[Compositing: property <max-height> underlying [fit-content\] from add [min-content\] to add [200px\] at (1.5) should be [calc-size(min-content, 300px + size * -0.5)\]]
expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [100px\] to add [200px\] at (-0.3) should be [calc-size(fit-content, (100px + size) * 1.3 + (200px + size) * -0.3)\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [100px\] to add [200px\] at (0) should be [calc-size(fit-content, (100px + size) * 1 + (200px + size) * 0)\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [100px\] to add [200px\] at (0.5) should be [calc-size(fit-content, (100px + size) * 0.5 + (200px + size) * 0.5)\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [100px\] to add [200px\] at (1) should be [calc-size(fit-content, (100px + size) * 0 + (200px + size) * 1)\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [100px\] to add [200px\] at (1.5) should be [calc-size(fit-content, (100px + size) * -0.5 + (200px + size) * 1.5)\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [min-content\] to add [200px\] at (-0.3) should be [min-content\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [min-content\] to add [200px\] at (0) should be [min-content\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [min-content\] to add [200px\] at (0.5) should be [calc-size(fit-content, 200px + size)\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [min-content\] to add [200px\] at (1) should be [calc-size(fit-content, 200px + size)\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [min-content\] to add [200px\] at (1.5) should be [calc-size(fit-content, 200px + size)\]]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-max-width-composition.html.ini b/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-max-width-composition.html.ini
index 3a8389477a1..c8802fc001d 100644
--- a/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-max-width-composition.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-max-width-composition.html.ini
@@ -43,3 +43,33 @@
[Compositing: property <max-width> underlying [max-content\] from add [100px\] to add [min-content\] at (1.5) should be [calc-size(min-content, -50px + size * 1.5)\]]
expected: FAIL
+
+ [Compositing: property <max-width> underlying [100px\] from add [100px\] to add [fit-content\] at (-0.3) should be [calc-size(fit-content, 260px + (100px + size) * -0.3)\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [100px\] from add [100px\] to add [fit-content\] at (0) should be [calc-size(fit-content, 200px + (100px + size) * 0)\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [100px\] from add [100px\] to add [fit-content\] at (0.5) should be [calc-size(fit-content, 100px + (100px + size) * 0.5)\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [100px\] from add [100px\] to add [fit-content\] at (1) should be [calc-size(fit-content, 0px + (100px + size) * 1)\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [100px\] from add [100px\] to add [fit-content\] at (1.5) should be [calc-size(fit-content, -100px + (100px + size) * 1.5)\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [max-content\] from add [100px\] to add [min-content\] at (-0.3) should be [calc-size(max-content, 100px + size)\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [max-content\] from add [100px\] to add [min-content\] at (0) should be [calc-size(max-content, 100px + size)\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [max-content\] from add [100px\] to add [min-content\] at (0.5) should be [min-content\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [max-content\] from add [100px\] to add [min-content\] at (1) should be [min-content\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [max-content\] from add [100px\] to add [min-content\] at (1.5) should be [min-content\]]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-min-height-composition.html.ini b/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-min-height-composition.html.ini
index 67c9993b16a..f973fc571e9 100644
--- a/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-min-height-composition.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-min-height-composition.html.ini
@@ -28,3 +28,33 @@
[Compositing: property <min-height> underlying [fit-content\] from add [200px\] to add [min-content\] at (1.5) should be [calc-size(min-content, -100px + size * 1.5)\]]
expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [100px\] to add [200px\] at (-0.3) should be [calc-size(fit-content, (100px + size) * 1.3 + (200px + size) * -0.3)\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [100px\] to add [200px\] at (0) should be [calc-size(fit-content, (100px + size) * 1 + (200px + size) * 0)\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [100px\] to add [200px\] at (0.5) should be [calc-size(fit-content, (100px + size) * 0.5 + (200px + size) * 0.5)\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [100px\] to add [200px\] at (1) should be [calc-size(fit-content, (100px + size) * 0 + (200px + size) * 1)\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [100px\] to add [200px\] at (1.5) should be [calc-size(fit-content, (100px + size) * -0.5 + (200px + size) * 1.5)\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [200px\] to add [min-content\] at (-0.3) should be [calc-size(fit-content, 200px + size)\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [200px\] to add [min-content\] at (0) should be [calc-size(fit-content, 200px + size)\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [200px\] to add [min-content\] at (0.5) should be [min-content\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [200px\] to add [min-content\] at (1) should be [min-content\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [200px\] to add [min-content\] at (1.5) should be [min-content\]]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-min-width-composition.html.ini b/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-min-width-composition.html.ini
index ab115e64efe..e3ee8af41b7 100644
--- a/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-min-width-composition.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-values/calc-size/animation/interpolate-size-min-width-composition.html.ini
@@ -43,3 +43,33 @@
[Compositing: property <min-width> underlying [max-content\] from add [100px\] to add [min-content\] at (1.5) should be [calc-size(min-content, -50px + size * 1.5)\]]
expected: FAIL
+
+ [Compositing: property <min-width> underlying [100px\] from add [max-content\] to add [100px\] at (-0.3) should be [calc-size(max-content, (100px + size) * 1.3 + -60px)\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [100px\] from add [max-content\] to add [100px\] at (0) should be [calc-size(max-content, (100px + size) * 1 + 0px)\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [100px\] from add [max-content\] to add [100px\] at (0.5) should be [calc-size(max-content, (100px + size) * 0.5 + 100px)\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [100px\] from add [max-content\] to add [100px\] at (1) should be [calc-size(max-content, (100px + size) * 0 + 200px)\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [100px\] from add [max-content\] to add [100px\] at (1.5) should be [calc-size(max-content, (100px + size) * -0.5 + 300px)\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [max-content\] from add [100px\] to add [min-content\] at (-0.3) should be [calc-size(max-content, 100px + size)\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [max-content\] from add [100px\] to add [min-content\] at (0) should be [calc-size(max-content, 100px + size)\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [max-content\] from add [100px\] to add [min-content\] at (0.5) should be [min-content\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [max-content\] from add [100px\] to add [min-content\] at (1) should be [min-content\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [max-content\] from add [100px\] to add [min-content\] at (1.5) should be [min-content\]]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-values/minmax-length-percent-serialize.html.ini b/tests/wpt/meta-legacy-layout/css/css-values/minmax-length-percent-serialize.html.ini
index 3a95b5bb439..401b2b107b3 100644
--- a/tests/wpt/meta-legacy-layout/css/css-values/minmax-length-percent-serialize.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-values/minmax-length-percent-serialize.html.ini
@@ -214,3 +214,9 @@
['max((min(10%, 30px) + 10px) * 2 + 10px, 5em + 5%)' as a computed value should serialize as 'max(10px + (10px + min(10%, 30px)) * 2, 5% + 80px)'.]
expected: FAIL
+
+ ['max((min(10%, 30px) + 10px) * 2 + 10px, 5em + 5%)' as a specified value should serialize as 'max(10px + (2 * (10px + min(10%, 30px))), 5% + 5em)'.]
+ expected: FAIL
+
+ ['max((min(10%, 30px) + 10px) * 2 + 10px, 5em + 5%)' as a computed value should serialize as 'max(10px + (2 * (10px + min(10%, 30px))), 5% + 80px)'.]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-values/round-function.html.ini b/tests/wpt/meta-legacy-layout/css/css-values/round-function.html.ini
new file mode 100644
index 00000000000..819fbf742db
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/css/css-values/round-function.html.ini
@@ -0,0 +1,3 @@
+[round-function.html]
+ [round(down, (7 - 1) / 3, 1) should be used-value-equivalent to 2]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/css/css-values/vh_not_refreshing_on_chrome.html.ini b/tests/wpt/meta-legacy-layout/css/css-values/vh_not_refreshing_on_chrome.html.ini
index 599b3e07f8d..9bafc27593e 100644
--- a/tests/wpt/meta-legacy-layout/css/css-values/vh_not_refreshing_on_chrome.html.ini
+++ b/tests/wpt/meta-legacy-layout/css/css-values/vh_not_refreshing_on_chrome.html.ini
@@ -1,2 +1,3 @@
[vh_not_refreshing_on_chrome.html]
bug: https://github.com/servo/servo/issues/8984
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/custom-elements/CustomElementRegistry.html.ini b/tests/wpt/meta-legacy-layout/custom-elements/CustomElementRegistry.html.ini
index deab4a1159a..df317e32f5c 100644
--- a/tests/wpt/meta-legacy-layout/custom-elements/CustomElementRegistry.html.ini
+++ b/tests/wpt/meta-legacy-layout/custom-elements/CustomElementRegistry.html.ini
@@ -2,3 +2,6 @@
type: testharness
[customElements.define must upgrade elements in the shadow-including tree order]
expected: FAIL
+
+ [customElements.define must get "observedAttributes" property on the constructor prototype when "attributeChangedCallback" is present]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/dom/nodes/moveBefore/tentative/custom-element-move-reactions.html.ini b/tests/wpt/meta-legacy-layout/dom/nodes/moveBefore/tentative/custom-element-move-reactions.html.ini
new file mode 100644
index 00000000000..d8b66a385b9
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/dom/nodes/moveBefore/tentative/custom-element-move-reactions.html.ini
@@ -0,0 +1,12 @@
+[custom-element-move-reactions.html]
+ [the disconnected/connected callbacks should be called when no other callback is defined]
+ expected: FAIL
+
+ [the element should stay connected during the callbacks]
+ expected: FAIL
+
+ [When connectedMoveCallback is defined, it is called instead of disconnectedCallback/connectedCallback]
+ expected: FAIL
+
+ [Reactions to atomic move are called in order of element, not in order of operation]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/fetch-preflight.https.sub.any.js.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/fetch-preflight.https.sub.any.js.ini
index f290329dfbe..0147b1bc84c 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/fetch-preflight.https.sub.any.js.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/fetch-preflight.https.sub.any.js.ini
@@ -1,16 +1,10 @@
[fetch-preflight.https.sub.any.html]
- [Same-site fetch with preflight]
- expected: FAIL
-
- [Cross-site fetch with preflight]
+ [Cross-site fetch with preflight: sec-fetch-site]
expected: FAIL
[fetch-preflight.https.sub.any.worker.html]
- [Same-site fetch with preflight]
- expected: FAIL
-
- [Cross-site fetch with preflight]
+ [Cross-site fetch with preflight: sec-fetch-site]
expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/fetch.https.sub.any.js.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/fetch.https.sub.any.js.ini
index 3d653a386bc..31cda1be01e 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/fetch.https.sub.any.js.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/fetch.https.sub.any.js.ini
@@ -1,114 +1,12 @@
[fetch.https.sub.any.html]
- [CORS mode: sec-fetch-site]
- expected: FAIL
-
- [Same-origin mode: sec-fetch-dest]
- expected: FAIL
-
- [Cross-site fetch: sec-fetch-dest]
- expected: FAIL
-
[Cross-site fetch: sec-fetch-site]
expected: FAIL
- [Same-origin fetch: sec-fetch-mode]
- expected: FAIL
-
- [CORS mode: sec-fetch-mode]
- expected: FAIL
-
- [Same-origin mode: sec-fetch-mode]
- expected: FAIL
-
- [Same-origin mode: sec-fetch-site]
- expected: FAIL
-
- [Same-origin fetch: sec-fetch-site]
- expected: FAIL
-
- [Cross-site fetch: sec-fetch-mode]
- expected: FAIL
-
- [CORS mode: sec-fetch-dest]
- expected: FAIL
-
- [Same-origin fetch: sec-fetch-dest]
- expected: FAIL
-
- [no-CORS mode: sec-fetch-dest]
- expected: FAIL
-
- [Same-site fetch: sec-fetch-dest]
- expected: FAIL
-
- [no-CORS mode: sec-fetch-site]
- expected: FAIL
-
- [Same-site fetch: sec-fetch-site]
- expected: FAIL
-
- [no-CORS mode: sec-fetch-mode]
- expected: FAIL
-
- [Same-site fetch: sec-fetch-mode]
- expected: FAIL
-
[fetch.https.sub.any.worker.html]
- [CORS mode: sec-fetch-site]
- expected: FAIL
-
- [Same-origin mode: sec-fetch-dest]
- expected: FAIL
-
- [Cross-site fetch: sec-fetch-dest]
- expected: FAIL
-
[Cross-site fetch: sec-fetch-site]
expected: FAIL
- [Same-origin fetch: sec-fetch-mode]
- expected: FAIL
-
- [CORS mode: sec-fetch-mode]
- expected: FAIL
-
- [Same-origin mode: sec-fetch-mode]
- expected: FAIL
-
- [Same-origin mode: sec-fetch-site]
- expected: FAIL
-
- [Same-origin fetch: sec-fetch-site]
- expected: FAIL
-
- [Cross-site fetch: sec-fetch-mode]
- expected: FAIL
-
- [CORS mode: sec-fetch-dest]
- expected: FAIL
-
- [Same-origin fetch: sec-fetch-dest]
- expected: FAIL
-
- [no-CORS mode: sec-fetch-dest]
- expected: FAIL
-
- [Same-site fetch: sec-fetch-dest]
- expected: FAIL
-
- [no-CORS mode: sec-fetch-site]
- expected: FAIL
-
- [Same-site fetch: sec-fetch-site]
- expected: FAIL
-
- [no-CORS mode: sec-fetch-mode]
- expected: FAIL
-
- [Same-site fetch: sec-fetch-mode]
- expected: FAIL
-
[fetch.https.sub.any.sharedworker.html]
expected: ERROR
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/css-font-face.sub.tentative.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/css-font-face.sub.tentative.html.ini
index f5e8ecddd7f..eaa11f4cf28 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/css-font-face.sub.tentative.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/css-font-face.sub.tentative.html.ini
@@ -23,8 +23,8 @@
[sec-fetch-mode - Not sent to non-trustworthy cross-site destination]
expected: FAIL
- [sec-fetch-mode - Not sent to non-trustworthy same-site destination]
+ [sec-fetch-user - Not sent to non-trustworthy cross-site destination]
expected: FAIL
- [sec-fetch-user - Not sent to non-trustworthy cross-site destination]
+ [sec-fetch-dest - Not sent to non-trustworthy cross-site destination]
expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/css-images.https.sub.tentative.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/css-images.https.sub.tentative.html.ini
index ec48f2ec823..4ec27c8b8aa 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/css-images.https.sub.tentative.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/css-images.https.sub.tentative.html.ini
@@ -3,9 +3,6 @@
[background-image sec-fetch-site - Same origin]
expected: TIMEOUT
- [border-image sec-fetch-site - Same origin]
- expected: FAIL
-
[content sec-fetch-site - Same origin]
expected: FAIL
@@ -33,9 +30,6 @@
[background-image sec-fetch-site - Same site]
expected: TIMEOUT
- [border-image sec-fetch-site - Same site]
- expected: FAIL
-
[content sec-fetch-site - Same site]
expected: FAIL
@@ -138,9 +132,6 @@
[background-image sec-fetch-site - Same-Origin -> Same-Site]
expected: TIMEOUT
- [border-image sec-fetch-site - Same-Origin -> Same-Site]
- expected: FAIL
-
[content sec-fetch-site - Same-Origin -> Same-Site]
expected: FAIL
@@ -183,9 +174,6 @@
[background-image sec-fetch-site - Same-Site -> Same-Site]
expected: TIMEOUT
- [border-image sec-fetch-site - Same-Site -> Same-Site]
- expected: FAIL
-
[content sec-fetch-site - Same-Site -> Same-Site]
expected: FAIL
@@ -228,9 +216,6 @@
[background-image sec-fetch-mode]
expected: TIMEOUT
- [border-image sec-fetch-mode]
- expected: FAIL
-
[content sec-fetch-mode]
expected: FAIL
@@ -243,9 +228,6 @@
[background-image sec-fetch-dest]
expected: TIMEOUT
- [border-image sec-fetch-dest]
- expected: FAIL
-
[content sec-fetch-dest]
expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/css-images.sub.tentative.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/css-images.sub.tentative.html.ini
index f9de5391ad6..741af78eff8 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/css-images.sub.tentative.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/css-images.sub.tentative.html.ini
@@ -146,3 +146,9 @@
[list-style-image sec-fetch-site - HTTPS downgrade-upgrade]
expected: FAIL
+
+ [background-image sec-fetch-site - HTTPS downgrade (header not sent)]
+ expected: TIMEOUT
+
+ [border-image sec-fetch-site - HTTPS downgrade (header not sent)]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-a.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-a.sub.html.ini
index 6f19fd27de4..dd0b375d338 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-a.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-a.sub.html.ini
@@ -4,3 +4,6 @@
[sec-fetch-site - HTTPS downgrade-upgrade - no attributes]
expected: FAIL
+
+ [sec-fetch-site - HTTPS downgrade (header not sent) - no attributes]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-audio.https.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-audio.https.sub.html.ini
index 4a4d16a5676..03e98a8db48 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-audio.https.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-audio.https.sub.html.ini
@@ -1,19 +1,10 @@
[element-audio.https.sub.html]
- [sec-fetch-site - Same origin, no attributes]
- expected: FAIL
-
[sec-fetch-site - Cross-site, no attributes]
expected: FAIL
- [sec-fetch-site - Same site, no attributes]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site -> Same-Origin redirect, no attributes]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same-Site -> Same-Origin redirect, no attributes]
- expected: FAIL
-
[sec-fetch-site - Cross-Site -> Same Origin, no attributes]
expected: FAIL
@@ -23,38 +14,11 @@
[sec-fetch-site - Cross-Site -> Cross-Site, no attributes]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same Origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - Same-Origin -> Same-Site, no attributes]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site, no attributes]
expected: FAIL
- [sec-fetch-site - Same-Site -> Same Origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - Same-Site -> Same-Site, no attributes]
- expected: FAIL
-
[sec-fetch-site - Same-Site -> Cross-Site, no attributes]
expected: FAIL
[sec-fetch-site - HTTPS downgrade-upgrade, no attributes]
expected: FAIL
-
- [sec-fetch-mode - no attributes]
- expected: FAIL
-
- [sec-fetch-mode - attributes: crossorigin]
- expected: FAIL
-
- [sec-fetch-mode - attributes: crossorigin=anonymous]
- expected: FAIL
-
- [sec-fetch-mode - attributes: crossorigin=use-credentials]
- expected: FAIL
-
- [sec-fetch-dest - no attributes]
- expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-audio.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-audio.sub.html.ini
index 3b31ea96366..7cc93481772 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-audio.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-audio.sub.html.ini
@@ -4,3 +4,6 @@
[sec-fetch-site - HTTPS downgrade-upgrade, no attributes]
expected: FAIL
+
+ [sec-fetch-site - HTTPS downgrade (header not sent), no attributes]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-iframe.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-iframe.sub.html.ini
index 6d496e923ca..b154a96d9de 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-iframe.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-iframe.sub.html.ini
@@ -4,3 +4,6 @@
[sec-fetch-site - HTTPS downgrade-upgrade]
expected: FAIL
+
+ [sec-fetch-site - HTTPS downgrade (header not sent)]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-img.https.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-img.https.sub.html.ini
index 13f6a1ecd91..a42697b3dc8 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-img.https.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-img.https.sub.html.ini
@@ -1,34 +1,16 @@
[element-img.https.sub.html]
- [sec-fetch-site - src - Same origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - srcset - Same origin, no attributes]
- expected: FAIL
-
[sec-fetch-site - src - Cross-site, no attributes]
expected: FAIL
[sec-fetch-site - srcset - Cross-site, no attributes]
expected: FAIL
- [sec-fetch-site - src - Same site, no attributes]
- expected: FAIL
-
- [sec-fetch-site - srcset - Same site, no attributes]
- expected: FAIL
-
[sec-fetch-site - src - Same-Origin -> Cross-Site -> Same-Origin redirect, no attributes]
expected: FAIL
[sec-fetch-site - srcset - Same-Origin -> Cross-Site -> Same-Origin redirect, no attributes]
expected: FAIL
- [sec-fetch-site - src - Same-Origin -> Same-Site -> Same-Origin redirect, no attributes]
- expected: FAIL
-
- [sec-fetch-site - srcset - Same-Origin -> Same-Site -> Same-Origin redirect, no attributes]
- expected: FAIL
-
[sec-fetch-site - src - Cross-Site -> Same Origin, no attributes]
expected: FAIL
@@ -47,36 +29,12 @@
[sec-fetch-site - srcset - Cross-Site -> Cross-Site, no attributes]
expected: FAIL
- [sec-fetch-site - src - Same-Origin -> Same Origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - srcset - Same-Origin -> Same Origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - src - Same-Origin -> Same-Site, no attributes]
- expected: FAIL
-
- [sec-fetch-site - srcset - Same-Origin -> Same-Site, no attributes]
- expected: FAIL
-
[sec-fetch-site - src - Same-Origin -> Cross-Site, no attributes]
expected: FAIL
[sec-fetch-site - srcset - Same-Origin -> Cross-Site, no attributes]
expected: FAIL
- [sec-fetch-site - src - Same-Site -> Same Origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - srcset - Same-Site -> Same Origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - src - Same-Site -> Same-Site, no attributes]
- expected: FAIL
-
- [sec-fetch-site - srcset - Same-Site -> Same-Site, no attributes]
- expected: FAIL
-
[sec-fetch-site - src - Same-Site -> Cross-Site, no attributes]
expected: FAIL
@@ -85,33 +43,3 @@
[sec-fetch-site - src - HTTPS downgrade-upgrade, no attributes]
expected: FAIL
-
- [sec-fetch-mode - src - no attributes]
- expected: FAIL
-
- [sec-fetch-mode - src - attributes: crossorigin]
- expected: FAIL
-
- [sec-fetch-mode - src - attributes: crossorigin=anonymous]
- expected: FAIL
-
- [sec-fetch-mode - src - attributes: crossorigin=use-credentials]
- expected: FAIL
-
- [sec-fetch-mode - srcset - no attributes]
- expected: FAIL
-
- [sec-fetch-mode - srcset - attributes: crossorigin]
- expected: FAIL
-
- [sec-fetch-mode - srcset - attributes: crossorigin=anonymous]
- expected: FAIL
-
- [sec-fetch-mode - srcset - attributes: crossorigin=use-credentials]
- expected: FAIL
-
- [sec-fetch-dest - src - no attributes]
- expected: FAIL
-
- [sec-fetch-dest - srcset - no attributes]
- expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-img.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-img.sub.html.ini
index 2d53a409cf2..cd58db1fdd2 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-img.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-img.sub.html.ini
@@ -10,3 +10,9 @@
[sec-fetch-site - srcset - HTTPS downgrade-upgrade, no attributes]
expected: FAIL
+
+ [sec-fetch-site - src - HTTPS downgrade (header not sent), no attributes]
+ expected: FAIL
+
+ [sec-fetch-site - srcset - HTTPS downgrade (header not sent), no attributes]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-link-prefetch.https.optional.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-link-prefetch.https.optional.sub.html.ini
index f083672c134..a1d357e629e 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-link-prefetch.https.optional.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-link-prefetch.https.optional.sub.html.ini
@@ -5,15 +5,9 @@
[sec-fetch-site - Cross-site no attributes]
expected: FAIL
- [sec-fetch-site - Same site no attributes]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site -> Same-Origin redirect no attributes]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same-Site -> Same-Origin redirect no attributes]
- expected: FAIL
-
[sec-fetch-site - Cross-Site -> Same Origin no attributes]
expected: FAIL
@@ -26,36 +20,12 @@
[sec-fetch-site - Same-Origin -> Same Origin no attributes]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same-Site no attributes]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site no attributes]
expected: FAIL
- [sec-fetch-site - Same-Site -> Same Origin no attributes]
- expected: FAIL
-
- [sec-fetch-site - Same-Site -> Same-Site no attributes]
- expected: FAIL
-
[sec-fetch-site - Same-Site -> Cross-Site no attributes]
expected: FAIL
- [sec-fetch-mode no attributes]
- expected: FAIL
-
- [sec-fetch-mode attributes: crossorigin]
- expected: FAIL
-
- [sec-fetch-mode attributes: crossorigin=anonymous]
- expected: FAIL
-
- [sec-fetch-mode attributes: crossorigin=use-credentials]
- expected: FAIL
-
- [sec-fetch-dest no attributes]
- expected: FAIL
-
[sec-fetch-dest attributes: as=audio]
expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-link-prefetch.optional.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-link-prefetch.optional.sub.html.ini
index c91344a198e..b75a39a81a0 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-link-prefetch.optional.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-link-prefetch.optional.sub.html.ini
@@ -4,3 +4,6 @@
[sec-fetch-site - HTTPS downgrade-upgrade no attributes]
expected: FAIL
+
+ [sec-fetch-site - HTTPS downgrade (header not sent) no attributes]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-meta-refresh.https.optional.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-meta-refresh.https.optional.sub.html.ini
index 1b884336d31..5bc9bb2c8cf 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-meta-refresh.https.optional.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-meta-refresh.https.optional.sub.html.ini
@@ -1,7 +1,4 @@
[element-meta-refresh.https.optional.sub.html]
- [sec-fetch-site - Same origin]
- expected: FAIL
-
[sec-fetch-site - Cross-site]
expected: FAIL
@@ -11,9 +8,6 @@
[sec-fetch-site - Same-Origin -> Cross-Site -> Same-Origin redirect]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same-Site -> Same-Origin redirect]
- expected: FAIL
-
[sec-fetch-site - Cross-Site -> Same Origin]
expected: FAIL
@@ -23,18 +17,9 @@
[sec-fetch-site - Cross-Site -> Cross-Site]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same Origin]
- expected: FAIL
-
- [sec-fetch-site - Same-Origin -> Same-Site]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site]
expected: FAIL
- [sec-fetch-site - Same-Site -> Same Origin]
- expected: FAIL
-
[sec-fetch-site - Same-Site -> Same-Site]
expected: FAIL
@@ -44,8 +29,5 @@
[sec-fetch-site - HTTPS downgrade-upgrade]
expected: FAIL
- [sec-fetch-mode]
- expected: FAIL
-
- [sec-fetch-dest]
+ [sec-fetch-user]
expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-meta-refresh.optional.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-meta-refresh.optional.sub.html.ini
index f7602907106..6af80d8f7e8 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-meta-refresh.optional.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-meta-refresh.optional.sub.html.ini
@@ -4,3 +4,6 @@
[sec-fetch-site - HTTPS downgrade-upgrade]
expected: FAIL
+
+ [sec-fetch-site - HTTPS downgrade (header not sent)]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-picture.https.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-picture.https.sub.html.ini
index 2280b961e90..f5c5d952e0c 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-picture.https.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-picture.https.sub.html.ini
@@ -1,13 +1,4 @@
[element-picture.https.sub.html]
- [sec-fetch-site - img[src\] - Same origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - img[srcset\] - Same origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - source[srcset\] - Same origin, no attributes]
- expected: FAIL
-
[sec-fetch-site - img[src\] - Cross-site, no attributes]
expected: FAIL
@@ -17,15 +8,6 @@
[sec-fetch-site - source[srcset\] - Cross-site, no attributes]
expected: FAIL
- [sec-fetch-site - img[src\] - Same site, no attributes]
- expected: FAIL
-
- [sec-fetch-site - img[srcset\] - Same site, no attributes]
- expected: FAIL
-
- [sec-fetch-site - source[srcset\] - Same site, no attributes]
- expected: FAIL
-
[sec-fetch-site - img[src\] - Same-Origin -> Cross-Site -> Same-Origin redirect, no attributes]
expected: FAIL
@@ -35,15 +17,6 @@
[sec-fetch-site - source[srcset\] - Same-Origin -> Cross-Site -> Same-Origin redirect, no attributes]
expected: FAIL
- [sec-fetch-site - img[src\] - Same-Origin -> Same-Site -> Same-Origin redirect, no attributes]
- expected: FAIL
-
- [sec-fetch-site - img[srcset\] - Same-Origin -> Same-Site -> Same-Origin redirect, no attributes]
- expected: FAIL
-
- [sec-fetch-site - source[srcset\] - Same-Origin -> Same-Site -> Same-Origin redirect, no attributes]
- expected: FAIL
-
[sec-fetch-site - img[src\] - Cross-Site -> Same Origin, no attributes]
expected: FAIL
@@ -71,24 +44,6 @@
[sec-fetch-site - source[srcset\] - Cross-Site -> Cross-Site, no attributes]
expected: FAIL
- [sec-fetch-site - img[src\] - Same-Origin -> Same Origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - img[srcset\] - Same-Origin -> Same Origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - source[srcset\] - Same-Origin -> Same Origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - img[src\] - Same-Origin -> Same-Site, no attributes]
- expected: FAIL
-
- [sec-fetch-site - img[srcset\] - Same-Origin -> Same-Site, no attributes]
- expected: FAIL
-
- [sec-fetch-site - source[srcset\] - Same-Origin -> Same-Site, no attributes]
- expected: FAIL
-
[sec-fetch-site - img[src\] - Same-Origin -> Cross-Site, no attributes]
expected: FAIL
@@ -98,24 +53,6 @@
[sec-fetch-site - source[srcset\] - Same-Origin -> Cross-Site, no attributes]
expected: FAIL
- [sec-fetch-site - img[src\] - Same-Site -> Same Origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - img[srcset\] - Same-Site -> Same Origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - source[srcset\] - Same-Site -> Same Origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - img[src\] - Same-Site -> Same-Site, no attributes]
- expected: FAIL
-
- [sec-fetch-site - img[srcset\] - Same-Site -> Same-Site, no attributes]
- expected: FAIL
-
- [sec-fetch-site - source[srcset\] - Same-Site -> Same-Site, no attributes]
- expected: FAIL
-
[sec-fetch-site - img[src\] - Same-Site -> Cross-Site, no attributes]
expected: FAIL
@@ -125,21 +62,6 @@
[sec-fetch-site - source[srcset\] - Same-Site -> Cross-Site, no attributes]
expected: FAIL
- [sec-fetch-mode - img[src\] - no attributes]
- expected: FAIL
-
- [sec-fetch-mode - img[srcset\] - no attributes]
- expected: FAIL
-
- [sec-fetch-mode - source[srcset\] - no attributes]
- expected: FAIL
-
- [sec-fetch-mode - img[src\] - attributes: crossorigin]
- expected: FAIL
-
- [sec-fetch-mode - img[srcset\] - attributes: crossorigin]
- expected: FAIL
-
[sec-fetch-mode - source[srcset\] - attributes: crossorigin]
expected: FAIL
@@ -149,23 +71,8 @@
[sec-fetch-mode - img[srcset\] - attributes: crossorigin=anonymous]
expected: FAIL
- [sec-fetch-mode - source[srcset\] - attributes: crossorigin=anonymous]
- expected: FAIL
-
[sec-fetch-mode - img[src\] - attributes: crossorigin=use-credentials]
expected: FAIL
[sec-fetch-mode - img[srcset\] - attributes: crossorigin=use-credentials]
expected: FAIL
-
- [sec-fetch-mode - source[srcset\] - attributes: crossorigin=use-credentials]
- expected: FAIL
-
- [sec-fetch-dest - img[src\] - no attributes]
- expected: FAIL
-
- [sec-fetch-dest - img[srcset\] - no attributes]
- expected: FAIL
-
- [sec-fetch-dest - source[srcset\] - no attributes]
- expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-picture.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-picture.sub.html.ini
index 96ee7c6eafe..3232ec358eb 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-picture.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-picture.sub.html.ini
@@ -16,3 +16,12 @@
[sec-fetch-site - source[srcset\] - HTTPS downgrade-upgrade, no attributes]
expected: FAIL
+
+ [sec-fetch-site - img[src\] - HTTPS downgrade (header not sent), no attributes]
+ expected: FAIL
+
+ [sec-fetch-site - img[srcset\] - HTTPS downgrade (header not sent), no attributes]
+ expected: FAIL
+
+ [sec-fetch-site - source[srcset\] - HTTPS downgrade (header not sent), no attributes]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-script.https.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-script.https.sub.html.ini
index ade689e17a5..217a1c62e79 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-script.https.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-script.https.sub.html.ini
@@ -1,34 +1,16 @@
[element-script.https.sub.html]
- [sec-fetch-site - Same origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - Same origin, attributes: type=module]
- expected: FAIL
-
[sec-fetch-site - Cross-site, no attributes]
expected: FAIL
[sec-fetch-site - Cross-site, attributes: type=module]
expected: FAIL
- [sec-fetch-site - Same site, no attributes]
- expected: FAIL
-
- [sec-fetch-site - Same site, attributes: type=module]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site -> Same-Origin redirect, no attributes]
expected: FAIL
[sec-fetch-site - Same-Origin -> Cross-Site -> Same-Origin redirect, attributes: type=module]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same-Site -> Same-Origin redirect, no attributes]
- expected: FAIL
-
- [sec-fetch-site - Same-Origin -> Same-Site -> Same-Origin redirect, attributes: type=module]
- expected: FAIL
-
[sec-fetch-site - Cross-Site -> Same Origin, no attributes]
expected: FAIL
@@ -47,56 +29,14 @@
[sec-fetch-site - Cross-Site -> Cross-Site, attributes: type=module]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same Origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - Same-Origin -> Same Origin, attributes: type=module]
- expected: FAIL
-
- [sec-fetch-site - Same-Origin -> Same-Site, no attributes]
- expected: FAIL
-
- [sec-fetch-site - Same-Origin -> Same-Site, attributes: type=module]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site, no attributes]
expected: FAIL
[sec-fetch-site - Same-Origin -> Cross-Site, attributes: type=module]
expected: FAIL
- [sec-fetch-site - Same-Site -> Same Origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - Same-Site -> Same Origin, attributes: type=module]
- expected: FAIL
-
- [sec-fetch-site - Same-Site -> Same-Site, no attributes]
- expected: FAIL
-
- [sec-fetch-site - Same-Site -> Same-Site, attributes: type=module]
- expected: FAIL
-
[sec-fetch-site - Same-Site -> Cross-Site, no attributes]
expected: FAIL
[sec-fetch-site - Same-Site -> Cross-Site, attributes: type=module]
expected: FAIL
-
- [sec-fetch-mode - no attributes]
- expected: FAIL
-
- [sec-fetch-mode - attributes: type=module]
- expected: FAIL
-
- [sec-fetch-mode - attributes: crossorigin]
- expected: FAIL
-
- [sec-fetch-mode - attributes: crossorigin=anonymous]
- expected: FAIL
-
- [sec-fetch-mode - attributes: crossorigin=use-credentials]
- expected: FAIL
-
- [sec-fetch-dest - no attributes]
- expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-script.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-script.sub.html.ini
index 247f8800f48..ef877c37311 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-script.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-script.sub.html.ini
@@ -10,3 +10,9 @@
[sec-fetch-site - HTTPS downgrade-upgrade, attributes: type=module]
expected: FAIL
+
+ [sec-fetch-site - HTTPS downgrade (header not sent), no attributes]
+ expected: FAIL
+
+ [sec-fetch-site - HTTPS downgrade (header not sent), attributes: type=module]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-video.https.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-video.https.sub.html.ini
index 56699467370..2978eb8f94f 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-video.https.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-video.https.sub.html.ini
@@ -1,19 +1,10 @@
[element-video.https.sub.html]
- [sec-fetch-site - Same origin, no attributes]
- expected: FAIL
-
[sec-fetch-site - Cross-site, no attributes]
expected: FAIL
- [sec-fetch-site - Same site, no attributes]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site -> Same-Origin redirect, no attributes]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same-Site -> Same-Origin redirect, no attributes]
- expected: FAIL
-
[sec-fetch-site - Cross-Site -> Same Origin, no attributes]
expected: FAIL
@@ -23,38 +14,11 @@
[sec-fetch-site - Cross-Site -> Cross-Site, no attributes]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same Origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - Same-Origin -> Same-Site, no attributes]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site, no attributes]
expected: FAIL
- [sec-fetch-site - Same-Site -> Same Origin, no attributes]
- expected: FAIL
-
- [sec-fetch-site - Same-Site -> Same-Site, no attributes]
- expected: FAIL
-
[sec-fetch-site - Same-Site -> Cross-Site, no attributes]
expected: FAIL
[sec-fetch-site - HTTPS downgrade-upgrade, no attributes]
expected: FAIL
-
- [sec-fetch-mode - no attributes]
- expected: FAIL
-
- [sec-fetch-mode - attributes: crossorigin]
- expected: FAIL
-
- [sec-fetch-mode - attributes: crossorigin=anonymous]
- expected: FAIL
-
- [sec-fetch-mode - attributes: crossorigin=use-credentials]
- expected: FAIL
-
- [sec-fetch-dest - no attributes]
- expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-video.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-video.sub.html.ini
index a33a4431dcc..70d776ac203 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-video.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/element-video.sub.html.ini
@@ -4,3 +4,6 @@
[sec-fetch-site - HTTPS downgrade-upgrade, no attributes]
expected: FAIL
+
+ [sec-fetch-site - HTTPS downgrade (header not sent), no attributes]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/fetch.https.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/fetch.https.sub.html.ini
index 7ae4931e7bc..6153b15aec8 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/fetch.https.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/fetch.https.sub.html.ini
@@ -1,19 +1,10 @@
[fetch.https.sub.html]
- [sec-fetch-site - Same origin, init: mode=no-cors]
- expected: FAIL
-
[sec-fetch-site - Cross-site, init: mode=no-cors]
expected: FAIL
- [sec-fetch-site - Same site, init: mode=no-cors]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site -> Same-Origin redirect, init: mode=no-cors]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same-Site -> Same-Origin redirect, init: mode=no-cors]
- expected: FAIL
-
[sec-fetch-site - Cross-Site -> Same Origin, init: mode=no-cors]
expected: FAIL
@@ -23,35 +14,8 @@
[sec-fetch-site - Cross-Site -> Cross-Site, init: mode=no-cors]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same Origin, init: mode=no-cors]
- expected: FAIL
-
- [sec-fetch-site - Same-Origin -> Same-Site, init: mode=no-cors]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site, init: mode=no-cors]
expected: FAIL
- [sec-fetch-site - Same-Site -> Same Origin, init: mode=no-cors]
- expected: FAIL
-
- [sec-fetch-site - Same-Site -> Same-Site, init: mode=no-cors]
- expected: FAIL
-
[sec-fetch-site - Same-Site -> Cross-Site, init: mode=no-cors]
expected: FAIL
-
- [sec-fetch-mode - no init]
- expected: FAIL
-
- [sec-fetch-mode - init: mode=cors]
- expected: FAIL
-
- [sec-fetch-mode - init: mode=no-cors]
- expected: FAIL
-
- [sec-fetch-mode - init: mode=same-origin]
- expected: FAIL
-
- [sec-fetch-dest - no init]
- expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/fetch.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/fetch.sub.html.ini
index b24c676699b..339edb2c742 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/fetch.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/fetch.sub.html.ini
@@ -4,3 +4,6 @@
[sec-fetch-site - HTTPS downgrade-upgrade, no init]
expected: FAIL
+
+ [sec-fetch-site - HTTPS downgrade (header not sent), no init]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-dynamic.https.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-dynamic.https.sub.html.ini
index 03be57bbc6c..9da83749a21 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-dynamic.https.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-dynamic.https.sub.html.ini
@@ -1,19 +1,10 @@
[script-module-import-dynamic.https.sub.html]
- [sec-fetch-site - Same origin]
- expected: FAIL
-
[sec-fetch-site - Cross-site]
expected: FAIL
- [sec-fetch-site - Same site]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site -> Same-Origin redirect]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same-Site -> Same-Origin redirect]
- expected: FAIL
-
[sec-fetch-site - Cross-Site -> Same Origin]
expected: FAIL
@@ -23,26 +14,8 @@
[sec-fetch-site - Cross-Site -> Cross-Site]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same Origin]
- expected: FAIL
-
- [sec-fetch-site - Same-Origin -> Same-Site]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site]
expected: FAIL
- [sec-fetch-site - Same-Site -> Same Origin]
- expected: FAIL
-
- [sec-fetch-site - Same-Site -> Same-Site]
- expected: FAIL
-
[sec-fetch-site - Same-Site -> Cross-Site]
expected: FAIL
-
- [sec-fetch-mode]
- expected: FAIL
-
- [sec-fetch-dest]
- expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-dynamic.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-dynamic.sub.html.ini
index 9359c473d82..318935e7f3d 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-dynamic.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-dynamic.sub.html.ini
@@ -4,3 +4,6 @@
[sec-fetch-site - HTTPS downgrade-upgrade]
expected: FAIL
+
+ [sec-fetch-site - HTTPS downgrade (header not sent)]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-static.https.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-static.https.sub.html.ini
index bdea2870180..27b82550f15 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-static.https.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-static.https.sub.html.ini
@@ -1,19 +1,10 @@
[script-module-import-static.https.sub.html]
- [sec-fetch-site - Same origin]
- expected: FAIL
-
[sec-fetch-site - Cross-site]
expected: FAIL
- [sec-fetch-site - Same site]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site -> Same-Origin redirect]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same-Site -> Same-Origin redirect]
- expected: FAIL
-
[sec-fetch-site - Cross-Site -> Same Origin]
expected: FAIL
@@ -23,26 +14,8 @@
[sec-fetch-site - Cross-Site -> Cross-Site]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same Origin]
- expected: FAIL
-
- [sec-fetch-site - Same-Origin -> Same-Site]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site]
expected: FAIL
- [sec-fetch-site - Same-Site -> Same Origin]
- expected: FAIL
-
- [sec-fetch-site - Same-Site -> Same-Site]
- expected: FAIL
-
[sec-fetch-site - Same-Site -> Cross-Site]
expected: FAIL
-
- [sec-fetch-mode]
- expected: FAIL
-
- [sec-fetch-dest]
- expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-static.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-static.sub.html.ini
index f2964cf3a1d..bc7a5e2d884 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-static.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/script-module-import-static.sub.html.ini
@@ -4,3 +4,6 @@
[sec-fetch-site - HTTPS downgrade-upgrade]
expected: FAIL
+
+ [sec-fetch-site - HTTPS downgrade (header not sent)]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/window-location.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/window-location.sub.html.ini
index 54042826d40..6643b0b2cc7 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/window-location.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/window-location.sub.html.ini
@@ -22,3 +22,15 @@
[sec-fetch-site - HTTPS downgrade-upgrade - location.replace]
expected: FAIL
+
+ [sec-fetch-site - HTTPS downgrade (header not sent) - location]
+ expected: FAIL
+
+ [sec-fetch-site - HTTPS downgrade (header not sent) - location.href]
+ expected: FAIL
+
+ [sec-fetch-site - HTTPS downgrade (header not sent) - location.assign]
+ expected: FAIL
+
+ [sec-fetch-site - HTTPS downgrade (header not sent) - location.replace]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/worker-dedicated-constructor.https.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/worker-dedicated-constructor.https.sub.html.ini
deleted file mode 100644
index 71a0d06a338..00000000000
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/worker-dedicated-constructor.https.sub.html.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[worker-dedicated-constructor.https.sub.html]
- [sec-fetch-mode - no options]
- expected: FAIL
-
- [sec-fetch-mode - options: type=module]
- expected: FAIL
-
- [sec-fetch-dest - no options]
- expected: FAIL
-
- [sec-fetch-dest - options: type=module]
- expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/worker-dedicated-importscripts.https.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/worker-dedicated-importscripts.https.sub.html.ini
index adf36ed21d4..c4c3f669fe2 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/worker-dedicated-importscripts.https.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/worker-dedicated-importscripts.https.sub.html.ini
@@ -1,19 +1,10 @@
[worker-dedicated-importscripts.https.sub.html]
- [sec-fetch-site - Same origin]
- expected: FAIL
-
[sec-fetch-site - Cross-site]
expected: FAIL
- [sec-fetch-site - Same site]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site -> Same-Origin redirect]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same-Site -> Same-Origin redirect]
- expected: FAIL
-
[sec-fetch-site - Cross-Site -> Same Origin]
expected: FAIL
@@ -23,26 +14,8 @@
[sec-fetch-site - Cross-Site -> Cross-Site]
expected: FAIL
- [sec-fetch-site - Same-Origin -> Same Origin]
- expected: FAIL
-
- [sec-fetch-site - Same-Origin -> Same-Site]
- expected: FAIL
-
[sec-fetch-site - Same-Origin -> Cross-Site]
expected: FAIL
- [sec-fetch-site - Same-Site -> Same Origin]
- expected: FAIL
-
- [sec-fetch-site - Same-Site -> Same-Site]
- expected: FAIL
-
[sec-fetch-site - Same-Site -> Cross-Site]
expected: FAIL
-
- [sec-fetch-mode]
- expected: FAIL
-
- [sec-fetch-dest]
- expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/worker-dedicated-importscripts.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/worker-dedicated-importscripts.sub.html.ini
index 906554c2f3b..b5ee5020c7a 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/generated/worker-dedicated-importscripts.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/generated/worker-dedicated-importscripts.sub.html.ini
@@ -4,3 +4,6 @@
[sec-fetch-site - HTTPS downgrade-upgrade]
expected: FAIL
+
+ [sec-fetch-site - HTTPS downgrade (header not sent)]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/navigation.https.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/navigation.https.sub.html.ini
index a53ed577de8..e7801fc0b84 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/navigation.https.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/navigation.https.sub.html.ini
@@ -1,2 +1,3 @@
[navigation.https.sub.html]
- expected: TIMEOUT
+ [undefined: sec-fetch-site]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/redirect/multiple-redirect-https-downgrade-upgrade.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/redirect/multiple-redirect-https-downgrade-upgrade.sub.html.ini
index 9f8a81560a0..a04dff862ba 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/redirect/multiple-redirect-https-downgrade-upgrade.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/redirect/multiple-redirect-https-downgrade-upgrade.sub.html.ini
@@ -1,8 +1,5 @@
[multiple-redirect-https-downgrade-upgrade.sub.html]
expected: TIMEOUT
- [Https downgrade-upgrade top level navigation: sec-fetch-dest]
- expected: FAIL
-
[Https downgrade-upgrade script => No headers: sec-fetch-dest]
expected: FAIL
@@ -18,9 +15,6 @@
[Https downgrade-upgrade object]
expected: NOTRUN
- [Https downgrade-upgrade top level navigation: sec-fetch-mode]
- expected: FAIL
-
[Https downgrade-upgrade script => No headers: sec-fetch-mode]
expected: FAIL
@@ -44,3 +38,6 @@
[Https downgrade-upgrade preload]
expected: TIMEOUT
+
+ [Https downgrade-upgrade top level navigation: sec-fetch-user]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/redirect/redirect-https-downgrade.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/redirect/redirect-https-downgrade.sub.html.ini
index 24727d48899..f6c65ea2f19 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/redirect/redirect-https-downgrade.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/redirect/redirect-https-downgrade.sub.html.ini
@@ -17,3 +17,15 @@
[Https downgrade track]
expected: NOTRUN
+
+ [Https downgrade top level navigation: sec-fetch-dest]
+ expected: FAIL
+
+ [Https downgrade top level navigation: sec-fetch-mode]
+ expected: FAIL
+
+ [Https downgrade top level navigation: sec-fetch-site]
+ expected: FAIL
+
+ [Https downgrade top level navigation: sec-fetch-user]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/style.https.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/style.https.sub.html.ini
index 644e0f93c46..e977bc4e881 100644
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/style.https.sub.html.ini
+++ b/tests/wpt/meta-legacy-layout/fetch/metadata/style.https.sub.html.ini
@@ -1,37 +1,3 @@
[style.https.sub.html]
- [Cross-Site style: sec-fetch-dest]
- expected: FAIL
-
- [Same-Site style: sec-fetch-dest]
- expected: FAIL
-
[Cross-Site style: sec-fetch-site]
expected: FAIL
-
- [Same-Origin style: sec-fetch-mode]
- expected: FAIL
-
- [Same-Origin, cors style: sec-fetch-mode]
- expected: FAIL
-
- [Same-Site style: sec-fetch-mode]
- expected: FAIL
-
- [Same-Site style: sec-fetch-site]
- expected: FAIL
-
- [Same-Origin, cors style: sec-fetch-site]
- expected: FAIL
-
- [Same-Origin style: sec-fetch-dest]
- expected: FAIL
-
- [Same-Origin, cors style: sec-fetch-dest]
- expected: FAIL
-
- [Same-Origin style: sec-fetch-site]
- expected: FAIL
-
- [Cross-Site style: sec-fetch-mode]
- expected: FAIL
-
diff --git a/tests/wpt/meta-legacy-layout/fetch/metadata/worker.https.sub.html.ini b/tests/wpt/meta-legacy-layout/fetch/metadata/worker.https.sub.html.ini
deleted file mode 100644
index 49ad74b23a6..00000000000
--- a/tests/wpt/meta-legacy-layout/fetch/metadata/worker.https.sub.html.ini
+++ /dev/null
@@ -1,10 +0,0 @@
-[worker.https.sub.html]
- [undefined: sec-fetch-mode]
- expected: FAIL
-
- [undefined: sec-fetch-site]
- expected: FAIL
-
- [undefined: sec-fetch-dest]
- expected: FAIL
-
diff --git a/tests/wpt/meta-legacy-layout/html/browsers/browsing-the-web/navigating-across-documents/navigation-unload-cross-origin.sub.window.js.ini b/tests/wpt/meta-legacy-layout/html/browsers/browsing-the-web/navigating-across-documents/navigation-unload-cross-origin.sub.window.js.ini
new file mode 100644
index 00000000000..4ecd6d9f753
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/browsers/browsing-the-web/navigating-across-documents/navigation-unload-cross-origin.sub.window.js.ini
@@ -0,0 +1,3 @@
+[navigation-unload-cross-origin.sub.window.html]
+ [Cross-origin navigation started from unload handler must be ignored]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage.html.ini
new file mode 100644
index 00000000000..a1927668778
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.drawImage.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect.html.ini
new file mode 100644
index 00000000000..ef9c00de33f
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.fillRect.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern.html.ini
new file mode 100644
index 00000000000..62eee6c2c0b
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.pattern.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage.html.ini
new file mode 100644
index 00000000000..39cfa83a2dc
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.drawImage.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect.html.ini
new file mode 100644
index 00000000000..fdb0e9a81f1
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.fillRect.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern.html.ini
new file mode 100644
index 00000000000..146aa84730e
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.pattern.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html.ini
new file mode 100644
index 00000000000..a195925f726
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.drawImage.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html.ini
new file mode 100644
index 00000000000..eb4b6f2408e
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.fillRect.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html.ini
new file mode 100644
index 00000000000..a6edb5e7c8e
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.pattern.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage.html.ini
new file mode 100644
index 00000000000..99c3038f22f
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.drawImage.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect.html.ini
new file mode 100644
index 00000000000..1167fcdd4df
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.fillRect.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern.html.ini
new file mode 100644
index 00000000000..8055e0e6233
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.pattern.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/element/text/2d.text.measure.text-clusters-position.tentative.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/element/text/2d.text.measure.text-clusters-position.tentative.html.ini
new file mode 100644
index 00000000000..142f3700afd
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/element/text/2d.text.measure.text-clusters-position.tentative.html.ini
@@ -0,0 +1,3 @@
+[2d.text.measure.text-clusters-position.tentative.html]
+ [Test that TextMetrics::getTextClusters() returns clusters that are positioned according to the target align and baseline passed as options.]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/element/text/2d.text.measure.text-clusters-range.tentative.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/element/text/2d.text.measure.text-clusters-range.tentative.html.ini
new file mode 100644
index 00000000000..ef0e5ba4fbd
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/element/text/2d.text.measure.text-clusters-range.tentative.html.ini
@@ -0,0 +1,3 @@
+[2d.text.measure.text-clusters-range.tentative.html]
+ [Test that getTextClusters() and fillTextCluster() correctly render different ranges of the input text.]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative.html.ini
new file mode 100644
index 00000000000..034846a0a91
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative.html.ini
@@ -0,0 +1,2 @@
+[2d.text.measure.text-clusters-rendering-align.tentative.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html.ini
new file mode 100644
index 00000000000..42e0bb131e5
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html.ini
@@ -0,0 +1,2 @@
+[2d.text.measure.text-clusters-rendering-baseline.tentative.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.html.ini
new file mode 100644
index 00000000000..a1927668778
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.drawImage.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.w.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.w.html.ini
new file mode 100644
index 00000000000..1d2295f3217
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.drawImage.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.html.ini
new file mode 100644
index 00000000000..ef9c00de33f
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.fillRect.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.w.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.w.html.ini
new file mode 100644
index 00000000000..6a6e343494b
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.fillRect.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.html.ini
new file mode 100644
index 00000000000..62eee6c2c0b
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.pattern.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.w.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.w.html.ini
new file mode 100644
index 00000000000..0902ce494c4
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.pattern.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.html.ini
new file mode 100644
index 00000000000..39cfa83a2dc
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.drawImage.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.w.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.w.html.ini
new file mode 100644
index 00000000000..2ded60b14cb
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.drawImage.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.html.ini
new file mode 100644
index 00000000000..fdb0e9a81f1
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.fillRect.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.w.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.w.html.ini
new file mode 100644
index 00000000000..322c7ef3429
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.fillRect.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.html.ini
new file mode 100644
index 00000000000..146aa84730e
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.pattern.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.w.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.w.html.ini
new file mode 100644
index 00000000000..602d69c0f16
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.pattern.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html.ini
new file mode 100644
index 00000000000..a195925f726
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.drawImage.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.w.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.w.html.ini
new file mode 100644
index 00000000000..cd15152caf6
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.drawImage.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html.ini
new file mode 100644
index 00000000000..eb4b6f2408e
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.fillRect.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.w.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.w.html.ini
new file mode 100644
index 00000000000..eec2f16a70d
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.fillRect.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html.ini
new file mode 100644
index 00000000000..a6edb5e7c8e
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.pattern.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.w.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.w.html.ini
new file mode 100644
index 00000000000..087fd35298c
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.pattern.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.html.ini
new file mode 100644
index 00000000000..99c3038f22f
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.drawImage.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.w.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.w.html.ini
new file mode 100644
index 00000000000..5b9f81d55a7
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.drawImage.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.html.ini
new file mode 100644
index 00000000000..1167fcdd4df
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.fillRect.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.w.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.w.html.ini
new file mode 100644
index 00000000000..d56ee6bbf95
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.fillRect.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.html.ini
new file mode 100644
index 00000000000..8055e0e6233
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.pattern.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.w.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.w.html.ini
new file mode 100644
index 00000000000..8108a9bc658
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.pattern.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.html.ini
new file mode 100644
index 00000000000..142f3700afd
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.html.ini
@@ -0,0 +1,3 @@
+[2d.text.measure.text-clusters-position.tentative.html]
+ [Test that TextMetrics::getTextClusters() returns clusters that are positioned according to the target align and baseline passed as options.]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.worker.js.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.worker.js.ini
new file mode 100644
index 00000000000..4cc1c748611
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.worker.js.ini
@@ -0,0 +1,3 @@
+[2d.text.measure.text-clusters-position.tentative.worker.html]
+ [Test that TextMetrics::getTextClusters() returns clusters that are positioned according to the target align and baseline passed as options.]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.html.ini
new file mode 100644
index 00000000000..ef0e5ba4fbd
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.html.ini
@@ -0,0 +1,3 @@
+[2d.text.measure.text-clusters-range.tentative.html]
+ [Test that getTextClusters() and fillTextCluster() correctly render different ranges of the input text.]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.worker.js.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.worker.js.ini
new file mode 100644
index 00000000000..ca35bd126f7
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.worker.js.ini
@@ -0,0 +1,3 @@
+[2d.text.measure.text-clusters-range.tentative.worker.html]
+ [Test that getTextClusters() and fillTextCluster() correctly render different ranges of the input text.]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.html.ini
new file mode 100644
index 00000000000..034846a0a91
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.html.ini
@@ -0,0 +1,2 @@
+[2d.text.measure.text-clusters-rendering-align.tentative.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.w.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.w.html.ini
new file mode 100644
index 00000000000..16b4355c27f
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.w.html.ini
@@ -0,0 +1,2 @@
+[2d.text.measure.text-clusters-rendering-align.tentative.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html.ini
new file mode 100644
index 00000000000..42e0bb131e5
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html.ini
@@ -0,0 +1,2 @@
+[2d.text.measure.text-clusters-rendering-baseline.tentative.html]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.w.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.w.html.ini
new file mode 100644
index 00000000000..3d7dd3b6b3a
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.w.html.ini
@@ -0,0 +1,2 @@
+[2d.text.measure.text-clusters-rendering-baseline.tentative.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative.w.html.ini b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative.w.html.ini
new file mode 100644
index 00000000000..2150f92957f
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative.w.html.ini
@@ -0,0 +1,2 @@
+[2d.text.measure.text-clusters-rendering-font-change.tentative.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/html/dom/elements/the-innertext-and-outertext-properties/innertext-whitespace-pre-line.html.ini b/tests/wpt/meta-legacy-layout/html/dom/elements/the-innertext-and-outertext-properties/innertext-whitespace-pre-line.html.ini
new file mode 100644
index 00000000000..5ce7adc27b8
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/dom/elements/the-innertext-and-outertext-properties/innertext-whitespace-pre-line.html.ini
@@ -0,0 +1,3 @@
+[innertext-whitespace-pre-line.html]
+ [innerText has collapsed whitespace but preserved newlines with pre-line]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html.ini b/tests/wpt/meta-legacy-layout/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html.ini
index 6bec7a732b8..49e3449f144 100644
--- a/tests/wpt/meta-legacy-layout/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html.ini
+++ b/tests/wpt/meta-legacy-layout/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html.ini
@@ -1,4 +1,4 @@
[iframe_sandbox_popups_nonescaping-2.html]
type: testharness
[Check that popups from a sandboxed iframe do not escape the sandbox]
- expected: FAIL
+ expected: NOTRUN
diff --git a/tests/wpt/meta-legacy-layout/html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html.ini b/tests/wpt/meta-legacy-layout/html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html.ini
index 759ada2991f..fcbbf505b49 100644
--- a/tests/wpt/meta-legacy-layout/html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html.ini
+++ b/tests/wpt/meta-legacy-layout/html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html.ini
@@ -1,150 +1,169 @@
[parse-a-srcset-attribute.html]
type: testharness
- expected: CRASH
- [" data:,a 1x "]
+ ["data:,a,, , "]
expected: FAIL
- ["\\t\\tdata:,a\\t\\t1x\\t\\t"]
+ [",,,data:,a"]
expected: FAIL
- ["\\n\\ndata:,a\\n\\n1x\\n\\n"]
+ [" , ,,data:,a"]
expected: FAIL
- ["\\v\\vdata:,a\\v\\v1x\\v\\v"]
+ ["data:,a \\\\,data:;\\,b, data:,c"]
expected: FAIL
- ["\\f\\fdata:,a\\f\\f1x\\f\\f"]
+ ["data:,a 0x"]
expected: FAIL
- ["\\r\\rdata:,a\\r\\r1x\\r\\r"]
+ ["data:,a -0x"]
expected: FAIL
- ["\\x0e\\x0edata:,a\\x0e\\x0e1x\\x0e\\x0e"]
+ ["data:,a 1.0w"]
expected: FAIL
- ["\\x0f\\x0fdata:,a\\x0f\\x0f1x\\x0f\\x0f"]
+ ["data:,a 1e0w"]
expected: FAIL
- ["\\x10\\x10data:,a\\x10\\x101x\\x10\\x10"]
+ ["data:,a 1www"]
expected: FAIL
- ["data:,a"]
+ ["data:,a +1w"]
expected: FAIL
- ["data:,a "]
+ ["data:,a 1\\x01w" (trailing U+0001)]
expected: FAIL
- ["data:,a ,"]
+ ["data:,a 1 w" (trailing U+00A0)]
expected: FAIL
- ["data:,a,"]
+ ["data:,a 1 w" (trailing U+1680)]
expected: FAIL
- ["data:,a, "]
+ ["data:,a 1 w" (trailing U+2000)]
expected: FAIL
- ["data:,a,,,"]
+ ["data:,a 1 w" (trailing U+2001)]
expected: FAIL
- ["data:,a,, , "]
+ ["data:,a 1 w" (trailing U+2002)]
expected: FAIL
- [" data:,a"]
+ ["data:,a 1 w" (trailing U+2003)]
expected: FAIL
- [",,,data:,a"]
+ ["data:,a 1 w" (trailing U+2004)]
expected: FAIL
- [" , ,,data:,a"]
+ ["data:,a 1 w" (trailing U+2005)]
expected: FAIL
- [" data:,a"]
+ ["data:,a 1 w" (trailing U+2006)]
expected: FAIL
- ["data:,a "]
+ ["data:,a 1 w" (trailing U+2007)]
expected: FAIL
- ["data:,a 1x"]
+ ["data:,a 1 w" (trailing U+2008)]
expected: FAIL
- ["data:,a 1x "]
+ ["data:,a 1 w" (trailing U+2009)]
expected: FAIL
- ["data:,a 1x,"]
+ ["data:,a 1 w" (trailing U+200A)]
expected: FAIL
- ["data:,a ( , data:,b 1x, ), data:,c"]
+ ["data:,a 1‌w" (trailing U+200C)]
expected: FAIL
- ["data:,a ((( , data:,b 1x, ), data:,c"]
+ ["data:,a 1‍w" (trailing U+200D)]
expected: FAIL
- ["data:,a [ , data:,b 1x, \], data:,c"]
+ ["data:,a 1 w" (trailing U+202F)]
expected: FAIL
- ["data:,a { , data:,b 1x, }, data:,c"]
+ ["data:,a 1 w" (trailing U+205F)]
expected: FAIL
- ["data:,a \\" , data:,b 1x, \\", data:,c"]
+ ["data:,a 1 w" (trailing U+3000)]
expected: FAIL
- ["data:,a \\\\,data:;\\,b, data:,c"]
+ ["data:,a 1w" (trailing U+FEFF)]
expected: FAIL
- ["data:,a, data:,b ("]
+ ["data:,a 1.x"]
expected: FAIL
- ["data:,a, data:,b ( "]
+ ["data:,a +1x"]
expected: FAIL
- ["data:,a, data:,b (,"]
+ ["data:,a 1w 1.0h"]
expected: FAIL
- ["data:,a, data:,b (x"]
+ ["data:,a 1w 1e0h"]
expected: FAIL
- ["data:,a, data:,b ()"]
+ ["data:,a 1w 1hhh"]
expected: FAIL
- ["data:,a /*, data:,b, data:,c */"]
+ ["data:,a 1w +1h"]
expected: FAIL
- ["data:,a //, data:,b"]
+ ["data:,a 1w 1\\x01h" (trailing U+0001)]
expected: FAIL
- ["data:,a 1w 1h"]
+ ["data:,a 1w 1 h" (trailing U+00A0)]
expected: FAIL
- ["data:,a 1h 1w"]
+ ["data:,a 1w 1 h" (trailing U+1680)]
expected: FAIL
- ["data:,a 1w"]
+ ["data:,a 1w 1 h" (trailing U+2000)]
expected: FAIL
- ["data:,a 0x"]
+ ["data:,a 1w 1 h" (trailing U+2001)]
expected: FAIL
- ["data:,a -0x"]
+ ["data:,a 1w 1 h" (trailing U+2002)]
expected: FAIL
- ["data:,a 1e0x"]
+ ["data:,a 1w 1 h" (trailing U+2003)]
expected: FAIL
- ["data:,a 1E0x"]
+ ["data:,a 1w 1 h" (trailing U+2004)]
expected: FAIL
- ["data:,a 1e-1x"]
+ ["data:,a 1w 1 h" (trailing U+2005)]
expected: FAIL
- ["data:,a 1.5e1x"]
+ ["data:,a 1w 1 h" (trailing U+2006)]
expected: FAIL
- ["data:,a .5x"]
+ ["data:,a 1w 1 h" (trailing U+2007)]
expected: FAIL
- ["data:,a .5e1x"]
+ ["data:,a 1w 1 h" (trailing U+2008)]
expected: FAIL
- ["data:,a 1.0x"]
+ ["data:,a 1w 1 h" (trailing U+2009)]
expected: FAIL
+ ["data:,a 1w 1 h" (trailing U+200A)]
+ expected: FAIL
+
+ ["data:,a 1w 1‌h" (trailing U+200C)]
+ expected: FAIL
+
+ ["data:,a 1w 1‍h" (trailing U+200D)]
+ expected: FAIL
+
+ ["data:,a 1w 1 h" (trailing U+202F)]
+ expected: FAIL
+
+ ["data:,a 1w 1 h" (trailing U+205F)]
+ expected: FAIL
+
+ ["data:,a 1w 1 h" (trailing U+3000)]
+ expected: FAIL
+
+ ["data:,a 1w 1h" (trailing U+FEFF)]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html.ini b/tests/wpt/meta-legacy-layout/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html.ini
index 19b3d41fe42..373ba604823 100644
--- a/tests/wpt/meta-legacy-layout/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html.ini
+++ b/tests/wpt/meta-legacy-layout/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html.ini
@@ -16,3 +16,6 @@
[Divs and imgs should be allowed as direct children of select and within options without a datalist.]
expected: FAIL
+
+ [Input tags should parse inside select instead of closing the select.]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html.ini b/tests/wpt/meta-legacy-layout/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html.ini
index f7b6c87f9c5..d566064c0e0 100644
--- a/tests/wpt/meta-legacy-layout/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html.ini
+++ b/tests/wpt/meta-legacy-layout/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html.ini
@@ -16,3 +16,18 @@
[dialog.showModal() should coalesce asynchronous toggle events.]
expected: FAIL
+
+ [dialog.show() should not open if beforetoggle removes]
+ expected: FAIL
+
+ [dialog.show() should not open if beforetoggle calls showPopover]
+ expected: FAIL
+
+ [dialog.showModal() should not double-set open/close if beforetoggle re-opens]
+ expected: FAIL
+
+ [dialog.showModal() should not open if beforetoggle removes]
+ expected: FAIL
+
+ [dialog.showModal() should not open if beforetoggle calls showPopover]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html.ini b/tests/wpt/meta-legacy-layout/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html.ini
deleted file mode 100644
index 53acb938c1b..00000000000
--- a/tests/wpt/meta-legacy-layout/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[module-static-import-delayed.html]
- [document.write in an imported module]
- expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/html/webappapis/update-rendering/child-document-raf-order.html.ini b/tests/wpt/meta-legacy-layout/html/webappapis/update-rendering/child-document-raf-order.html.ini
new file mode 100644
index 00000000000..312c6689170
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/html/webappapis/update-rendering/child-document-raf-order.html.ini
@@ -0,0 +1,3 @@
+[child-document-raf-order.html]
+ [Ordering of steps in "Update the Rendering" - child document requestAnimationFrame order]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/selection/caret-position-should-be-correct-while-moveup-movedown.html.ini b/tests/wpt/meta-legacy-layout/selection/caret-position-should-be-correct-while-moveup-movedown.html.ini
new file mode 100644
index 00000000000..32a129e1440
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/selection/caret-position-should-be-correct-while-moveup-movedown.html.ini
@@ -0,0 +1,72 @@
+[caret-position-should-be-correct-while-moveup-movedown.html]
+ [Caret position should be correct in moving up horizontal div when selection was left to right with line granularity]
+ expected: FAIL
+
+ [Caret position should be correct in moving up horizontal div when selection was right to left with line granularity]
+ expected: FAIL
+
+ [Caret position should be correct in moving down horizontal div when selection was left to right with line granularity]
+ expected: FAIL
+
+ [Caret position should be correct in moving down horizontal div when selection was right to left with line granularity]
+ expected: FAIL
+
+ [Caret position should be correct in moving up horizontal div when selection was left to right with paragraph granularity]
+ expected: FAIL
+
+ [Caret position should be correct in moving up horizontal div when selection was right to left with paragraph granularity]
+ expected: FAIL
+
+ [Caret position should be correct in moving down horizontal div when selection was left to right with paragraph granularity]
+ expected: FAIL
+
+ [Caret position should be correct in moving down horizontal div when selection was right to left with paragraph granularity]
+ expected: FAIL
+
+ [Caret position should be correct in move right with line granularity for vertical-lr div when selection was top to bottom]
+ expected: FAIL
+
+ [Caret position should be correct in move right with line granularity for vertical-lr div when selection was bottom to top]
+ expected: FAIL
+
+ [Caret position should be correct in move left with line granularity for vertical-lr div when selection was top to bottom]
+ expected: FAIL
+
+ [Caret position should be correct in move left with line granularity for vertical-lr div when selection was bottom to top]
+ expected: FAIL
+
+ [Caret position should be correct in move right with paragraph granularity for vertical-lr div when selection was top to bottom]
+ expected: FAIL
+
+ [Caret position should be correct in move right with paragraph granularity for vertical-lr div when selection was bottom to top]
+ expected: FAIL
+
+ [Caret position should be correct in move left with paragraph granularity for vertical-lr div when selection was top to bottom]
+ expected: FAIL
+
+ [Caret position should be correct in move left with paragraph granularity for vertical-lr div when selection was bottom to top]
+ expected: FAIL
+
+ [Caret position should be correct in move left with line granularity for vertical-rl div when selection was top to bottom]
+ expected: FAIL
+
+ [Caret position should be correct in move left with line granularity for vertical-rl div when selection was bottom to top]
+ expected: FAIL
+
+ [Caret position should be correct in move right with line granularity for vertical-rl div when selection was top to bottom]
+ expected: FAIL
+
+ [Caret position should be correct in move right with line granularity for vertical-rl div when selection was bottom to top]
+ expected: FAIL
+
+ [Caret position should be correct in move left with paragraph granularity for vertical-rl div when selection was top to bottom]
+ expected: FAIL
+
+ [Caret position should be correct in move left with paragraph granularity for vertical-rl div when selection was bottom to top]
+ expected: FAIL
+
+ [Caret position should be correct in move right with paragraph granularity for vertical-rl div when selection was top to bottom]
+ expected: FAIL
+
+ [Caret position should be correct in move right with paragraph granularity for vertical-rl div when selection was bottom to top]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/selection/shadow-dom/tentative/Selection-getComposedRanges-dom-mutations-removal.html.ini b/tests/wpt/meta-legacy-layout/selection/shadow-dom/tentative/Selection-getComposedRanges-dom-mutations-removal.html.ini
new file mode 100644
index 00000000000..4448f3238a0
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/selection/shadow-dom/tentative/Selection-getComposedRanges-dom-mutations-removal.html.ini
@@ -0,0 +1,32 @@
+[Selection-getComposedRanges-dom-mutations-removal.html?mode=closed]
+ [Range is fully in shadow tree. Removing shadow host collapses composed StaticRange. Note it does not update previously returned composed StaticRange.]
+ expected: FAIL
+
+ [Range is fully in shadow tree. Removing parent of shadow host collapses composed StaticRange.]
+ expected: FAIL
+
+ [Range is in light DOM. Removing startContainer rescopes new composed range to its parent.]
+ expected: FAIL
+
+ [Range is across shadow trees. Replacing shadowRoot content rescopes new composed range to the shadowRoot.]
+ expected: FAIL
+
+ [Range is between two light slotted contents. Removing start container rescopes to its parent in light tree.]
+ expected: FAIL
+
+
+[Selection-getComposedRanges-dom-mutations-removal.html?mode=open]
+ [Range is fully in shadow tree. Removing shadow host collapses composed StaticRange. Note it does not update previously returned composed StaticRange.]
+ expected: FAIL
+
+ [Range is fully in shadow tree. Removing parent of shadow host collapses composed StaticRange.]
+ expected: FAIL
+
+ [Range is in light DOM. Removing startContainer rescopes new composed range to its parent.]
+ expected: FAIL
+
+ [Range is across shadow trees. Replacing shadowRoot content rescopes new composed range to the shadowRoot.]
+ expected: FAIL
+
+ [Range is between two light slotted contents. Removing start container rescopes to its parent in light tree.]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/selection/shadow-dom/tentative/Selection-getComposedRanges-slot.html.ini b/tests/wpt/meta-legacy-layout/selection/shadow-dom/tentative/Selection-getComposedRanges-slot.html.ini
new file mode 100644
index 00000000000..97d7f6316fd
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/selection/shadow-dom/tentative/Selection-getComposedRanges-slot.html.ini
@@ -0,0 +1,9 @@
+[Selection-getComposedRanges-slot.html]
+ [Setting the range to start on slotted content and end in shadow tree, should follow DOM tree order.]
+ expected: FAIL
+
+ [Setting the range to start and end on slotted content, should follow DOM tree order.]
+ expected: FAIL
+
+ [Setting the range to start on unslotted content and end in shadow tree, should follow DOM tree order.]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/url/failure.html.ini b/tests/wpt/meta-legacy-layout/url/failure.html.ini
index e739baf2ea5..c1929ede7ab 100644
--- a/tests/wpt/meta-legacy-layout/url/failure.html.ini
+++ b/tests/wpt/meta-legacy-layout/url/failure.html.ini
@@ -728,3 +728,6 @@
[Location's href: stun://[:1\] should throw]
expected: FAIL
+
+ [Location's href: non-special://host\\a should throw]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/url/percent-encoding.window.js.ini b/tests/wpt/meta-legacy-layout/url/percent-encoding.window.js.ini
index 47e8f02f61e..41167982b64 100644
--- a/tests/wpt/meta-legacy-layout/url/percent-encoding.window.js.ini
+++ b/tests/wpt/meta-legacy-layout/url/percent-encoding.window.js.ini
@@ -1,10 +1,4 @@
[percent-encoding.window.html]
- [Input † with encoding windows-1252]
- expected: FAIL
-
- [Input − with encoding shift_jis]
- expected: FAIL
-
[Input \x0eA with encoding iso-2022-jp]
expected: FAIL
@@ -14,11 +8,5 @@
[Input † with encoding big5]
expected: FAIL
- [Input † with encoding euc-kr]
- expected: FAIL
-
- [Input ‾\\ with encoding iso-2022-jp]
- expected: FAIL
-
[Input U+d800 with encoding windows-1252]
expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/wasm/jsapi/jspi/js-promise-integration.any.js.ini b/tests/wpt/meta-legacy-layout/wasm/jsapi/jspi/js-promise-integration.any.js.ini
new file mode 100644
index 00000000000..bcf0c39c471
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/wasm/jsapi/jspi/js-promise-integration.any.js.ini
@@ -0,0 +1,63 @@
+[js-promise-integration.any.html]
+ expected: ERROR
+ [Promising function always entered]
+ expected: FAIL
+
+ [Always get a Promise]
+ expected: FAIL
+
+ [Suspend once]
+ expected: FAIL
+
+ [Suspend/resume in a loop]
+ expected: FAIL
+
+ [Suspending with mismatched args and via Proxy]
+ expected: FAIL
+
+ [Make sure we actually suspend]
+ expected: FAIL
+
+ [Do not suspend if the import's return value is not a Promise]
+ expected: FAIL
+
+ [Catch rejected promise]
+ expected: FAIL
+
+ [Promising with no return]
+ expected: FAIL
+
+ [Suspend two modules]
+ expected: FAIL
+
+
+[js-promise-integration.any.worker.html]
+ [Promising function always entered]
+ expected: FAIL
+
+ [Always get a Promise]
+ expected: FAIL
+
+ [Suspend once]
+ expected: FAIL
+
+ [Suspend/resume in a loop]
+ expected: FAIL
+
+ [Suspending with mismatched args and via Proxy]
+ expected: FAIL
+
+ [Make sure we actually suspend]
+ expected: FAIL
+
+ [Do not suspend if the import's return value is not a Promise]
+ expected: FAIL
+
+ [Catch rejected promise]
+ expected: FAIL
+
+ [Promising with no return]
+ expected: FAIL
+
+ [Suspend two modules]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/wasm/jsapi/jspi/rejects.any.js.ini b/tests/wpt/meta-legacy-layout/wasm/jsapi/jspi/rejects.any.js.ini
new file mode 100644
index 00000000000..94e3c87d1a7
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/wasm/jsapi/jspi/rejects.any.js.ini
@@ -0,0 +1,32 @@
+[rejects.any.worker.html]
+ [Throw after the first suspension]
+ expected: FAIL
+
+ [Throw before suspending]
+ expected: FAIL
+
+ [Throw and propagate via Promise]
+ expected: FAIL
+
+ [Stack overflow]
+ expected: FAIL
+
+ [Try to suspend JS]
+ expected: FAIL
+
+
+[rejects.any.html]
+ [Throw after the first suspension]
+ expected: FAIL
+
+ [Throw before suspending]
+ expected: FAIL
+
+ [Throw and propagate via Promise]
+ expected: FAIL
+
+ [Stack overflow]
+ expected: FAIL
+
+ [Try to suspend JS]
+ expected: FAIL
diff --git a/tests/wpt/meta-legacy-layout/webmessaging/with-ports/017.html.ini b/tests/wpt/meta-legacy-layout/webmessaging/with-ports/017.html.ini
deleted file mode 100644
index c7946fc91b4..00000000000
--- a/tests/wpt/meta-legacy-layout/webmessaging/with-ports/017.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[017.html]
- expected: TIMEOUT
- [origin of the script that invoked the method, about:blank]
- expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/webmessaging/without-ports/018.html.ini b/tests/wpt/meta-legacy-layout/webmessaging/without-ports/018.html.ini
deleted file mode 100644
index b7b36c1d3a4..00000000000
--- a/tests/wpt/meta-legacy-layout/webmessaging/without-ports/018.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[018.html]
- expected: TIMEOUT
- [origin of the script that invoked the method, javascript:]
- expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/webstorage/localstorage-about-blank-3P-iframe-opens-3P-window.partitioned.html.ini b/tests/wpt/meta-legacy-layout/webstorage/localstorage-about-blank-3P-iframe-opens-3P-window.partitioned.html.ini
new file mode 100644
index 00000000000..76d85b5bdf6
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/webstorage/localstorage-about-blank-3P-iframe-opens-3P-window.partitioned.html.ini
@@ -0,0 +1,4 @@
+[localstorage-about-blank-3P-iframe-opens-3P-window.partitioned.html]
+ expected: TIMEOUT
+ [StorageKey: test 3P about:blank window opened from a 3P iframe]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta-legacy-layout/workers/WorkerGlobalScope-close.html.ini b/tests/wpt/meta-legacy-layout/workers/WorkerGlobalScope-close.html.ini
new file mode 100644
index 00000000000..24daae4c2e7
--- /dev/null
+++ b/tests/wpt/meta-legacy-layout/workers/WorkerGlobalScope-close.html.ini
@@ -0,0 +1,3 @@
+[WorkerGlobalScope-close.html]
+ [Test sending a message after closing.]
+ expected: FAIL
diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json
index f19ef328fdd..239e5bf47d6 100644
--- a/tests/wpt/meta/MANIFEST.json
+++ b/tests/wpt/meta/MANIFEST.json
@@ -3745,6 +3745,13 @@
{}
]
],
+ "text-box-trim-end-and-widows.html": [
+ "8ff033342c19062e5a30a13b9758120329e5f8c1",
+ [
+ null,
+ {}
+ ]
+ ],
"text-in-inline-interrupted-by-float.html": [
"fbb26507a21c3d93cd47c0595f697e3e92ac9fb9",
[
@@ -5182,6 +5189,13 @@
null,
{}
]
+ ],
+ "text-overflow-ellipsis-multiline-crash.html": [
+ "a281df3a28068f38c370b786c94c532066c7e505",
+ [
+ null,
+ {}
+ ]
]
},
"neg-outline-offset-border-radius-crash.html": [
@@ -115349,7 +115363,7 @@
]
],
"overflow-applies-to-009.xht": [
- "5867a68b7a574334d28b8850e0ddb47301ab6c61",
+ "1a82a0806544a565e5c6564edc3f7c276b41f09a",
[
null,
[
@@ -146484,6 +146498,19 @@
{}
]
],
+ "text-indent-and-wide-float.html": [
+ "59885e7c2c08805241e93004eeb5a6c9e374e828",
+ [
+ null,
+ [
+ [
+ "/css/reference/ref-filled-green-100px-square.xht",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"trailing-child-margin-000.html": [
"d204483a33ebff421cf9f3da9fab2d1183fcd1c0",
[
@@ -146783,6 +146810,19 @@
{}
]
],
+ "transform-025.html": [
+ "58020065dc112080cc1e6b5bdacf52f75a976f70",
+ [
+ null,
+ [
+ [
+ "/css/reference/ref-filled-green-100px-square.xht",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"truncated-margin-at-fragmentainer-end-001.html": [
"cfb8590f9026194020afaea854f1d4d9fc570b49",
[
@@ -218995,6 +219035,19 @@
{}
]
],
+ "webkit-line-clamp-050.html": [
+ "973871b72d85328aa1b8f32a8c539cd657392102",
+ [
+ null,
+ [
+ [
+ "/css/css-overflow/line-clamp/reference/webkit-line-clamp-050-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"webkit-line-clamp-block-in-inline-001.html": [
"75d1de3bf5bcf5d00d6980de4a70845e9f7ae8e4",
[
@@ -225516,6 +225569,19 @@
{}
]
],
+ "first-line-below-float.html": [
+ "2e32513e9c7be3cb548732d821a453db89268f45",
+ [
+ null,
+ [
+ [
+ "/css/reference/ref-filled-green-100px-square.xht",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"first-line-change-inline-color-nested.html": [
"4a58f1ea5b623ffa5acd2993be16de399cd24127",
[
@@ -240753,6 +240819,86 @@
{}
]
],
+ "stretch": {
+ "abspos-1.html": [
+ "a64f0d05fdf39c3afd0cfb2818b4f2c9912efee1",
+ [
+ null,
+ [
+ [
+ "/css/reference/ref-filled-green-100px-square.xht",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "abspos-2.html": [
+ "80d815113d18cbc30548c1f928fe70dfefd09b4a",
+ [
+ null,
+ [
+ [
+ "/css/reference/ref-filled-green-100px-square.xht",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "bfc-next-to-float-1.html": [
+ "9c2a60e6c01917f590d09710adb43c2203294fb2",
+ [
+ null,
+ [
+ [
+ "/css/reference/ref-filled-green-100px-square.xht",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "min-width-1.html": [
+ "a1a39073e88d4626be7c469611e3593415849e7a",
+ [
+ null,
+ [
+ [
+ "/css/reference/ref-filled-green-100px-square-only.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "positioned-non-replaced-1.html": [
+ "b66916b8ab486742a67b4f33027640e4ff84142d",
+ [
+ null,
+ [
+ [
+ "/css/reference/ref-filled-green-100px-square-only.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "positioned-replaced-1.html": [
+ "60b817933d33301c755be3785fd7cf56607c4539",
+ [
+ null,
+ [
+ [
+ "/css/reference/ref-filled-green-100px-square-only.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ]
+ },
"svg-intrinsic-size-005.html": [
"68be3f2e1156271e3c2139ee764abd8ec8d045a0",
[
@@ -252133,6 +252279,19 @@
{}
]
],
+ "below-float.html": [
+ "a386232fd0e062c449ddadb3c23289f0df4c21b3",
+ [
+ null,
+ [
+ [
+ "/css/reference/ref-filled-green-100px-square.xht",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"text-indent-each-line-hanging.html": [
"2c3ac08df4a8a7962ec3ce1e1d1318ee39bdd7fb",
[
@@ -289251,6 +289410,19 @@
{}
]
],
+ "text-overflow-ellipsis-multiline-001.html": [
+ "5987817a5c98bdef181c37d37ff2de4cfd9db2f8",
+ [
+ null,
+ [
+ [
+ "/css/css-ui/reference/text-overflow-ellipsis-multiline-001-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"text-overflow-ruby.html": [
"c8abebb7206b57444051937c171b2884ec750403",
[
@@ -295115,6 +295287,19 @@
{}
]
],
+ "inline-child-with-overflow-shadow.html": [
+ "2c2d50af60c1b1eceff434253e432cf6bb70587c",
+ [
+ null,
+ [
+ [
+ "/css/css-view-transitions/inline-child-with-overflow-shadow-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"inline-element-size.html": [
"a571ace718a32882d727ac965bb2431451d8046c",
[
@@ -295129,7 +295314,7 @@
]
],
"inline-with-offset-from-containing-block.html": [
- "026ecb240a35f1ca1c7044f95f4d09468af9e05f",
+ "6bbb8b49392c84adecf32f972e4889f2ba356968",
[
null,
[
@@ -295149,7 +295334,7 @@
],
[
0,
- 1400
+ 1500
]
]
]
@@ -295171,6 +295356,122 @@
]
],
"layered-capture": {
+ "capture-mode-flat.tentative.html": [
+ "beed17c89735e419a8bcd33d903d913aa7c7227b",
+ [
+ null,
+ [
+ [
+ "/css/css-view-transitions/layered-capture/nested-opacity-ref.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 255
+ ],
+ [
+ 0,
+ 515
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "capture-mode-layered.tentative.html": [
+ "d1f190343b0c6e1526dbc44ee207b2896732ec06",
+ [
+ null,
+ [
+ [
+ "/css/css-view-transitions/layered-capture/nested-opacity-ref.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 255
+ ],
+ [
+ 0,
+ 515
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "nested-opacity-backdrop-blend-animated.tentative.html": [
+ "73100015cddd61558b01b092c18f25be6ae3ad08",
+ [
+ null,
+ [
+ [
+ "/css/css-view-transitions/layered-capture/nested-opacity-ref.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 255
+ ],
+ [
+ 0,
+ 515
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "nested-opacity-backdrop-blend.tentative.html": [
+ "0042d9676f2fbb26f2140ae8843995d478ab0942",
+ [
+ null,
+ [
+ [
+ "/css/css-view-transitions/layered-capture/nested-opacity-ref.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 255
+ ],
+ [
+ 0,
+ 515
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
"opacity-capture-observable-when-flat.tentative.html": [
"6d4ddbe86b175ff0cae19b3ed4a4cb0d827e22ec",
[
@@ -295200,6 +295501,64 @@
}
]
],
+ "opacity-resets-after-done.tentative.html": [
+ "7616638dc5ee816a3f9c9442a00eea3e32c73741",
+ [
+ null,
+ [
+ [
+ "/css/css-view-transitions/layered-capture/nested-opacity-ref.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 255
+ ],
+ [
+ 0,
+ 515
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "opacity-resets-after-skip.tentative.html": [
+ "e7a11ebe33125707f381c15f848c5f10ed25d50a",
+ [
+ null,
+ [
+ [
+ "/css/css-view-transitions/layered-capture/nested-opacity-ref.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 255
+ ],
+ [
+ 0,
+ 515
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
"tree-effects.tentative.sub.html": [
"31bb324e633117f3a2e4fd7d6fb0826fae4dce0b",
[
@@ -296951,42 +297310,13 @@
}
]
],
- "opacity-backdrop-blend-animated.tentative.html": [
- "835f068c49211a10e0d8259953a918ffd5f2236b",
- [
- null,
- [
- [
- "/css/css-view-transitions/nested/nested-opacity-ref.html",
- "=="
- ]
- ],
- {
- "fuzzy": [
- [
- null,
- [
- [
- 0,
- 255
- ],
- [
- 0,
- 515
- ]
- ]
- ]
- ]
- }
- ]
- ],
- "opacity-backdrop-blend.tentative.html": [
- "ea8acfc86b070ca375d4ebda54d48c6a42018696",
+ "render-element.tentative.html": [
+ "59a5a108314c0270b561339bf9a8a0cb6fdfe27d",
[
null,
[
[
- "/css/css-view-transitions/nested/nested-opacity-ref.html",
+ "/css/css-view-transitions/nested/nested-ref-100.html",
"=="
]
],
@@ -297008,97 +297338,40 @@
]
}
]
- ],
- "opacity-resets-after-done.tentative.html": [
- "7616638dc5ee816a3f9c9442a00eea3e32c73741",
+ ]
+ },
+ "nested-elements-in-overflow.html": [
+ "cce8fe8d8ffee2ffec953fc2207aed280b809be4",
+ [
+ null,
[
- null,
[
+ "/css/css-view-transitions/nested-elements-in-overflow-ref.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
[
- "/css/css-view-transitions/nested/nested-opacity-ref.html",
- "=="
- ]
- ],
- {
- "fuzzy": [
+ null,
[
- null,
[
- [
- 0,
- 255
- ],
- [
- 0,
- 515
- ]
- ]
- ]
- ]
- }
- ]
- ],
- "opacity-resets-after-skip.tentative.html": [
- "e7a11ebe33125707f381c15f848c5f10ed25d50a",
- [
- null,
- [
- [
- "/css/css-view-transitions/nested/nested-opacity-ref.html",
- "=="
- ]
- ],
- {
- "fuzzy": [
- [
- null,
+ 0,
+ 60
+ ],
[
- [
- 0,
- 255
- ],
- [
- 0,
- 515
- ]
+ 0,
+ 500
]
]
]
- }
- ]
- ],
- "render-element.tentative.html": [
- "59a5a108314c0270b561339bf9a8a0cb6fdfe27d",
- [
- null,
- [
- [
- "/css/css-view-transitions/nested/nested-ref-100.html",
- "=="
- ]
],
- {
- "fuzzy": [
- [
- null,
- [
- [
- 0,
- 255
- ],
- [
- 0,
- 515
- ]
- ]
- ]
- ]
- }
- ]
+ "timeout": "long"
+ }
]
- },
+ ],
"new-and-old-sizes-match.html": [
- "f23f63d28ffa31c185858d5af8f639a905329ad8",
+ "7245e4b42f26a00710be23f8d545b1fcb6c8766e",
[
null,
[
@@ -297114,11 +297387,11 @@
[
[
0,
- 15
+ 25
],
[
0,
- 500
+ 1500
]
]
]
@@ -298304,6 +298577,19 @@
{}
]
],
+ "outer-padding-inner-background.html": [
+ "6bbcf514ab47241fee2a4f5475cc364e176ed26c",
+ [
+ null,
+ [
+ [
+ "/css/css-view-transitions/outer-padding-inner-background-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"paint-holding-in-iframe.html": [
"4f2aa5360b03b8eaf65400203251ba936b947144",
[
@@ -316135,7 +316421,7 @@
]
],
"backdrop-filter-plus-filter.html": [
- "546786d8e60ac87e4d1dbf2c6bfdd7332cab1e01",
+ "5c83faae8686bd1b22f655f9aac2c50f1ab32a0a",
[
null,
[
@@ -316144,7 +316430,23 @@
"=="
]
],
- {}
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 1
+ ],
+ [
+ 0,
+ 210
+ ]
+ ]
+ ]
+ ]
+ }
]
],
"backdrop-filter-plus-opacity.html": [
@@ -326913,6 +327215,354 @@
]
}
]
+ ],
+ "2d.composite.grid.filter.no_shadow.drawImage.html": [
+ "8e6b95ae2210375f6e0db2cfa408bf4a7694deb3",
+ [
+ null,
+ [
+ [
+ "/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.filter.no_shadow.fillRect.html": [
+ "5dca89e3c12b884f9d226d9b6b8f10f1a67d68ae",
+ [
+ null,
+ [
+ [
+ "/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.filter.no_shadow.pattern.html": [
+ "6b3c4c6a5890f555e3831ea7a27c5896a2f08b5f",
+ [
+ null,
+ [
+ [
+ "/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.filter.shadow.drawImage.html": [
+ "f6872b221274b543dd16aa7568dc9f5b36da3791",
+ [
+ null,
+ [
+ [
+ "/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.filter.shadow.fillRect.html": [
+ "1c68c0e454059db077a2469143608ad7f95cdb7c",
+ [
+ null,
+ [
+ [
+ "/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.filter.shadow.pattern.html": [
+ "1e3f14fb9a3c1b62ec7b21c4ac7152d958811616",
+ [
+ null,
+ [
+ [
+ "/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.no_shadow.drawImage.html": [
+ "31e0fba79189df8fab876b886a278509abbc8581",
+ [
+ null,
+ [
+ [
+ "/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.no_shadow.fillRect.html": [
+ "e14c336868ecdef5024ba8fd2f9d4b6bdb202d25",
+ [
+ null,
+ [
+ [
+ "/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.no_shadow.pattern.html": [
+ "6f8159466dbd72bf6ae879484d2eb2a2b5db00fa",
+ [
+ null,
+ [
+ [
+ "/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.shadow.drawImage.html": [
+ "84527f5a2832d77cbd1e358ebee7bb9fbf2ae483",
+ [
+ null,
+ [
+ [
+ "/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.shadow.fillRect.html": [
+ "46bc366c8ac0cdad497c6145db3c8b16e96ee80e",
+ [
+ null,
+ [
+ [
+ "/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.shadow.pattern.html": [
+ "e636330c59f5b3b37f790c060e729730640b37af",
+ [
+ null,
+ [
+ [
+ "/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
]
},
"filters": {
@@ -329300,6 +329950,45 @@
{}
]
],
+ "2d.text.measure.text-clusters-rendering-align.tentative.html": [
+ "159efb4fee4dd290f35faa76d86b407418a4680b",
+ [
+ null,
+ [
+ [
+ "/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative-expected.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "2d.text.measure.text-clusters-rendering-baseline.tentative.html": [
+ "c20e076a3514921f6a82b10304c04fdb01c1da0e",
+ [
+ null,
+ [
+ [
+ "/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative-expected.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "2d.text.measure.text-clusters-rendering-font-change.tentative.html": [
+ "a927cfcd33094f502c3d46fd88da7bd26381256b",
+ [
+ null,
+ [
+ [
+ "/html/canvas/element/text/2d.text.measure.text-clusters-rendering-font-change.tentative-expected.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"2d.text.writingmode.html": [
"3d2fe020b0bb4298318ba0a854a19a4d9117319a",
[
@@ -329355,6 +330044,704 @@
}
},
"offscreen": {
+ "compositing": {
+ "2d.composite.grid.filter.no_shadow.drawImage.html": [
+ "72b23aeeafb87787e402a298b2b9c6b87a6a1cb5",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.filter.no_shadow.drawImage.w.html": [
+ "89f4dba75b570cc5ff514cd02d52b7597a3c9dfe",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.filter.no_shadow.fillRect.html": [
+ "3f8fdc8164d1fc971fd30d881d4a7ad4d28580fc",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.filter.no_shadow.fillRect.w.html": [
+ "37839bf8a8b460c1a500c6ba05047210edc3120f",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.filter.no_shadow.pattern.html": [
+ "0bb970ab3f84683b2ce40a140bd7288c13112838",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.filter.no_shadow.pattern.w.html": [
+ "81d0a8e6a693ef89a730a7bbc12bddd09c0a8fc6",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.filter.shadow.drawImage.html": [
+ "5c9e992c7ce72164d04615a9d4fda9b629b21a85",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.filter.shadow.drawImage.w.html": [
+ "08e66abd46439ecb07fa8312fc5c0dad1bd28854",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.filter.shadow.fillRect.html": [
+ "0f6b88fd5e9e16e69213bdeb4dc66bb49c21427d",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.filter.shadow.fillRect.w.html": [
+ "f754f538b560b5bfd95539d4fd2033f3dbbea34a",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.filter.shadow.pattern.html": [
+ "e89aff9196dc194b5a4dd12a41f24312a0173e3d",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.filter.shadow.pattern.w.html": [
+ "79f7aab01cd4e14509bc951dd3e67bdfb1e60667",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.no_shadow.drawImage.html": [
+ "54a53b46576b55657183a59248937405efe3031a",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.no_shadow.drawImage.w.html": [
+ "4750ed210ffe98e6b7de2443764fd648e69e1254",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.no_shadow.fillRect.html": [
+ "e69af8a79a92adbc0b3eff5e27a6295e873180f4",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.no_shadow.fillRect.w.html": [
+ "0cfc23ab86a5d823f695bc11d1ac2a24a94feb5d",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.no_shadow.pattern.html": [
+ "b6008b7c79f3106750ec7e07bdf1d98582e02843",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.no_shadow.pattern.w.html": [
+ "ef952ce12cdaa3ea260cbc0ff4aa0ed4de3ea68e",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.shadow.drawImage.html": [
+ "d25f183aeb8bc510e76a09c5571332e066c30aed",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.shadow.drawImage.w.html": [
+ "c66b467d627df12414affa25f21a23d6088cff6a",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.shadow.fillRect.html": [
+ "3fdbfa72cafc7fe9a5e2e8eaf41662fd2c4013d8",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.shadow.fillRect.w.html": [
+ "519631612f05abd4f078c6d6a632dcbfb4913ace",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.shadow.pattern.html": [
+ "d9df6be84f174dde2a3d1f4b957cf4f8315d32ad",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
+ "2d.composite.grid.no_filter.shadow.pattern.w.html": [
+ "5c698e8c7603057f8e6207dcca9396aae585b43e",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern-expected.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 2
+ ],
+ [
+ 0,
+ 10210
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ]
+ },
"filters": {
"2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.html": [
"cc6c548499afb98698e2d498ba4392fcbb931507",
@@ -332026,6 +333413,84 @@
{}
]
],
+ "2d.text.measure.text-clusters-rendering-align.tentative.html": [
+ "4fc41c79cc44eba408bba38829ee42e1c7ead945",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative-expected.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "2d.text.measure.text-clusters-rendering-align.tentative.w.html": [
+ "35ddd54bfd78bad7f43ac91d0dfff53a541dbd49",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative-expected.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "2d.text.measure.text-clusters-rendering-baseline.tentative.html": [
+ "84def142a9ba38c3901d4fb45d53f9ec9ffecc8c",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative-expected.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "2d.text.measure.text-clusters-rendering-baseline.tentative.w.html": [
+ "9227776d8c8f5c274638be3c4acd0cfec4632ed9",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative-expected.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "2d.text.measure.text-clusters-rendering-font-change.tentative.html": [
+ "c8e3383a4623ae1ba9b9c76fd5073a4defb36a3b",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative-expected.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "2d.text.measure.text-clusters-rendering-font-change.tentative.w.html": [
+ "6bca8ebbc3515d3c40039390737cd9171d74be95",
+ [
+ null,
+ [
+ [
+ "/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative-expected.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"canvas.2d.fontStretch.condensed.html": [
"0cbd5e3c1f18935d04a18359caa8c91c89fd1806",
[
@@ -334844,6 +336309,19 @@
{}
]
],
+ "table-align-float.xhtml": [
+ "05de0d6b2807d7df911a88d2429e2f265152478b",
+ [
+ null,
+ [
+ [
+ "/html/rendering/non-replaced-elements/tables/table-align-float-ref.xhtml",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"table-border-1.html": [
"333881399555a8018be91b9c6053b15be694def3",
[
@@ -347033,6 +348511,19 @@
},
"svg": {
"animations": {
+ "animate-display-to-none-001.html": [
+ "ce8e493840e9743bdf211bd5e52b0d2fe7f84cb5",
+ [
+ null,
+ [
+ [
+ "/svg/struct/reftests/reference/green-100x100.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"conditional-processing-01.html": [
"fe3958f71f3ba6fdc37b65afd02aeabe5dc88bb7",
[
@@ -349189,6 +350680,19 @@
{}
]
],
+ "small-nested-viewbox.html": [
+ "3d9fb8cb45f57cc2e2fcf6293e9ebef5987704ce",
+ [
+ null,
+ [
+ [
+ "/svg/painting/reftests/small-nested-viewbox-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"symbol-in-mask.html": [
"da1e11f1704468c2ec77476ea1c566299737d9f9",
[
@@ -355114,12 +356618,16 @@
"bb0cea9f396c41faf9f045b402fb3b8ee99e1f4a",
[]
],
+ "safari-wptrunner.yml": [
+ "0860533dc92a398d23c965e7b72d3c65a2a491e4",
+ []
+ ],
"safari_stable.yml": [
- "0df13f43d4403b5aa5bf61868849f7ce37832168",
+ "7c344fe667f7dbf738f114bdc82893c8130e466e",
[]
],
"safari_technology_preview.yml": [
- "01380aa718e325b5a4b31b4db1833afe0afb8a93",
+ "70827a365ac048f374a8f98ecf5d695bc472d78e",
[]
],
"wpt_fyi_notify.yml": [
@@ -355541,7 +357049,7 @@
[]
],
"okp_importKey.js": [
- "5699341d9e49d4ab5af1cf4bc33fa515d969f01e",
+ "0e6a016fe2096015686e5616215f9bb81915f50a",
[]
],
"okp_importKey_failures_fixtures.js": [
@@ -357953,7 +359461,7 @@
[]
],
"helpers.js": [
- "0f20a71237c83589f676afeacb4660b39457fea3",
+ "56e2a2812b65a7978242654cf9cd82ff756a9fa9",
[]
],
"reporting_origin.py": [
@@ -420860,6 +422368,10 @@
"7a3591b5eead803163450acc1cfed4a3e8fd39d1",
[]
],
+ "webkit-line-clamp-050-ref.html": [
+ "1fa0720aeaf433714bfc80a3dd425197565e58e2",
+ []
+ ],
"webkit-line-clamp-block-in-inline-001-ref.html": [
"79f2e409109d72a76e12374220bd423aba16f4eb",
[]
@@ -433253,6 +434765,10 @@
"660a7c4d52e7e2a763bfffc7582469896a5835b8",
[]
],
+ "text-overflow-ellipsis-multiline-001-ref.html": [
+ "a26b8260eae55de6c9a9e0d2f3b6df3bb439b93b",
+ []
+ ],
"transparent-accent-color-001-ref.html": [
"91a9600e180cd9636b2ec3aa0ad63f79bbc334b5",
[]
@@ -435138,6 +436654,10 @@
"44a41f1bf93366e06f2eae0cbfcd4acb126d192f",
[]
],
+ "inline-child-with-overflow-shadow-ref.html": [
+ "69ed62da57db63215db71f234e80f6b369ca0614",
+ []
+ ],
"inline-element-size-ref.html": [
"ea791930e9bdf51a25125062b7da7cedafea1b95",
[]
@@ -435400,6 +436920,10 @@
]
}
},
+ "nested-elements-in-overflow-ref.html": [
+ "a05172fa40eb5171a773bcfb25709bddc2e4939b",
+ []
+ ],
"new-and-old-sizes-match-ref.html": [
"79e89801391530b6fb074545a92db68493667f05",
[]
@@ -435588,6 +437112,10 @@
"2927b468d08d452afc6a66267bf9786a6b00498e",
[]
],
+ "outer-padding-inner-background-ref.html": [
+ "7c7ee533f5c6d94a6b855ecb304371daadb2403d",
+ []
+ ],
"paint-holding-in-iframe-ref.html": [
"23852cf6a7cae7868ee19a52315be1f20c47ac84",
[]
@@ -441391,7 +442919,7 @@
[]
],
"iframe.html": [
- "6f3c072f29f9681042e55f044badf138304108c6",
+ "3ec761e08a6266ab24fcea357d866f76d8c9ed2f",
[]
]
},
@@ -442603,11 +444131,11 @@
[]
],
"inserthtml.js": [
- "bdfc1d34020bd9094fa5da591607c4c6a884d336",
+ "412fa63ef3144aca159e3848ea85e8b35887aa2d",
[]
],
"insertimage.js": [
- "b62331e152098ed6d63e294119cfe7abeddb174d",
+ "f92a570919189e30717b86f39c0a5ad1de006671",
[]
],
"insertlinebreak.js": [
@@ -442623,7 +444151,7 @@
[]
],
"inserttext.js": [
- "8fa8127f2df30800abb2097096a60b4e5ad35326",
+ "568b467f153c486b3792ca16947920b14d0a0859",
[]
],
"insertunorderedlist.js": [
@@ -451302,6 +452830,102 @@
"0ae6b502a9b2ce79b26dcf1059ea66382a1c11cc",
[]
],
+ "2d.composite.grid.filter.no_shadow.drawImage-expected.html": [
+ "eea78248a836f217a93d176c60b45ca202ea43ed",
+ []
+ ],
+ "2d.composite.grid.filter.no_shadow.drawImage.png": [
+ "2318c1ec94e401b19677b4c4b5e7badff8cea77e",
+ []
+ ],
+ "2d.composite.grid.filter.no_shadow.fillRect-expected.html": [
+ "08ed3566fd11df66e8d9e6ec4c84150be8e683bc",
+ []
+ ],
+ "2d.composite.grid.filter.no_shadow.fillRect.png": [
+ "2318c1ec94e401b19677b4c4b5e7badff8cea77e",
+ []
+ ],
+ "2d.composite.grid.filter.no_shadow.pattern-expected.html": [
+ "22c84f42e89b91df473f435c3c10b3399215eb72",
+ []
+ ],
+ "2d.composite.grid.filter.no_shadow.pattern.png": [
+ "2318c1ec94e401b19677b4c4b5e7badff8cea77e",
+ []
+ ],
+ "2d.composite.grid.filter.shadow.drawImage-expected.html": [
+ "2072348f904966cd1630efc1243aadddfbfe11e9",
+ []
+ ],
+ "2d.composite.grid.filter.shadow.drawImage.png": [
+ "fde787731168e3a2565ca15d6da5e160a03ef484",
+ []
+ ],
+ "2d.composite.grid.filter.shadow.fillRect-expected.html": [
+ "1e119bcbde5a2996567214e864ad33d00cc0d877",
+ []
+ ],
+ "2d.composite.grid.filter.shadow.fillRect.png": [
+ "fde787731168e3a2565ca15d6da5e160a03ef484",
+ []
+ ],
+ "2d.composite.grid.filter.shadow.pattern-expected.html": [
+ "f45fe82c302917293852ced72f3dd53628f398c2",
+ []
+ ],
+ "2d.composite.grid.filter.shadow.pattern.png": [
+ "fde787731168e3a2565ca15d6da5e160a03ef484",
+ []
+ ],
+ "2d.composite.grid.no_filter.no_shadow.drawImage-expected.html": [
+ "923d8360a9d73c9c336e8c460090b0e197e33a12",
+ []
+ ],
+ "2d.composite.grid.no_filter.no_shadow.drawImage.png": [
+ "ce392a1dcccc5e06a3d163dff873a5647ecdb65c",
+ []
+ ],
+ "2d.composite.grid.no_filter.no_shadow.fillRect-expected.html": [
+ "c809e56cac391699d5f4bd284424164833d09419",
+ []
+ ],
+ "2d.composite.grid.no_filter.no_shadow.fillRect.png": [
+ "ce392a1dcccc5e06a3d163dff873a5647ecdb65c",
+ []
+ ],
+ "2d.composite.grid.no_filter.no_shadow.pattern-expected.html": [
+ "f052442a637ed64db37ad12ea7f799f667ff9cd8",
+ []
+ ],
+ "2d.composite.grid.no_filter.no_shadow.pattern.png": [
+ "ce392a1dcccc5e06a3d163dff873a5647ecdb65c",
+ []
+ ],
+ "2d.composite.grid.no_filter.shadow.drawImage-expected.html": [
+ "ad07c35d3101c61b1e1ac4df2ec05348af251439",
+ []
+ ],
+ "2d.composite.grid.no_filter.shadow.drawImage.png": [
+ "aca03a61b220c1022c65b71dbd092f7b6de3c754",
+ []
+ ],
+ "2d.composite.grid.no_filter.shadow.fillRect-expected.html": [
+ "e16a5fcf4582efd0e691da4057f501e4be3702d3",
+ []
+ ],
+ "2d.composite.grid.no_filter.shadow.fillRect.png": [
+ "aca03a61b220c1022c65b71dbd092f7b6de3c754",
+ []
+ ],
+ "2d.composite.grid.no_filter.shadow.pattern-expected.html": [
+ "01e1d4d7b264624b94066ddd3b9e0f696b8c8517",
+ []
+ ],
+ "2d.composite.grid.no_filter.shadow.pattern.png": [
+ "aca03a61b220c1022c65b71dbd092f7b6de3c754",
+ []
+ ],
"2d.composite.image.clear.png": [
"eeedd0ff05889ffd4468bf19a2e8e9e0a094201c",
[]
@@ -452931,19 +454555,19 @@
},
"text": {
"2d.text.draw.fill.basic.png": [
- "8021427a07dc4ed754e2b3b1357aca7029bb0fe3",
+ "70d7b046cb226cfcb2bfeebe3477d3b580d8270a",
[]
],
"2d.text.draw.fill.maxWidth.large.png": [
- "8021427a07dc4ed754e2b3b1357aca7029bb0fe3",
+ "70d7b046cb226cfcb2bfeebe3477d3b580d8270a",
[]
],
"2d.text.draw.fill.rtl.png": [
- "8021427a07dc4ed754e2b3b1357aca7029bb0fe3",
+ "70d7b046cb226cfcb2bfeebe3477d3b580d8270a",
[]
],
"2d.text.draw.stroke.basic.png": [
- "d4f6dc1ee883e0a25a17149bc04154be3e7b5738",
+ "fb3b5b830d345d2aa858e41673e08f99977baf08",
[]
],
"2d.text.drawing.style.reset.fontKerning.none2-expected.html": [
@@ -452974,6 +454598,18 @@
"ad55a2083a740c2eb188da37fbf8dbee60386ff0",
[]
],
+ "2d.text.measure.text-clusters-rendering-align.tentative-expected.html": [
+ "967ae7e46365ff181f4323b39f9ff13bb62a34c7",
+ []
+ ],
+ "2d.text.measure.text-clusters-rendering-baseline.tentative-expected.html": [
+ "2dffe90aadc57ae07067fa7decab24fd43fc8728",
+ []
+ ],
+ "2d.text.measure.text-clusters-rendering-font-change.tentative-expected.html": [
+ "9a9443962dfb988da61453159d02d953e620be6c",
+ []
+ ],
"2d.text.writingmode-expected.html": [
"81259c11b7d9226fe659fc437f69b222093079fd",
[]
@@ -453003,6 +454639,104 @@
"b1f003a745f43bce7e24744902c9668a65fa5338",
[]
],
+ "compositing": {
+ "2d.composite.grid.filter.no_shadow.drawImage-expected.html": [
+ "eea78248a836f217a93d176c60b45ca202ea43ed",
+ []
+ ],
+ "2d.composite.grid.filter.no_shadow.drawImage.png": [
+ "2318c1ec94e401b19677b4c4b5e7badff8cea77e",
+ []
+ ],
+ "2d.composite.grid.filter.no_shadow.fillRect-expected.html": [
+ "08ed3566fd11df66e8d9e6ec4c84150be8e683bc",
+ []
+ ],
+ "2d.composite.grid.filter.no_shadow.fillRect.png": [
+ "2318c1ec94e401b19677b4c4b5e7badff8cea77e",
+ []
+ ],
+ "2d.composite.grid.filter.no_shadow.pattern-expected.html": [
+ "22c84f42e89b91df473f435c3c10b3399215eb72",
+ []
+ ],
+ "2d.composite.grid.filter.no_shadow.pattern.png": [
+ "2318c1ec94e401b19677b4c4b5e7badff8cea77e",
+ []
+ ],
+ "2d.composite.grid.filter.shadow.drawImage-expected.html": [
+ "2072348f904966cd1630efc1243aadddfbfe11e9",
+ []
+ ],
+ "2d.composite.grid.filter.shadow.drawImage.png": [
+ "fde787731168e3a2565ca15d6da5e160a03ef484",
+ []
+ ],
+ "2d.composite.grid.filter.shadow.fillRect-expected.html": [
+ "1e119bcbde5a2996567214e864ad33d00cc0d877",
+ []
+ ],
+ "2d.composite.grid.filter.shadow.fillRect.png": [
+ "fde787731168e3a2565ca15d6da5e160a03ef484",
+ []
+ ],
+ "2d.composite.grid.filter.shadow.pattern-expected.html": [
+ "f45fe82c302917293852ced72f3dd53628f398c2",
+ []
+ ],
+ "2d.composite.grid.filter.shadow.pattern.png": [
+ "fde787731168e3a2565ca15d6da5e160a03ef484",
+ []
+ ],
+ "2d.composite.grid.no_filter.no_shadow.drawImage-expected.html": [
+ "923d8360a9d73c9c336e8c460090b0e197e33a12",
+ []
+ ],
+ "2d.composite.grid.no_filter.no_shadow.drawImage.png": [
+ "ce392a1dcccc5e06a3d163dff873a5647ecdb65c",
+ []
+ ],
+ "2d.composite.grid.no_filter.no_shadow.fillRect-expected.html": [
+ "c809e56cac391699d5f4bd284424164833d09419",
+ []
+ ],
+ "2d.composite.grid.no_filter.no_shadow.fillRect.png": [
+ "ce392a1dcccc5e06a3d163dff873a5647ecdb65c",
+ []
+ ],
+ "2d.composite.grid.no_filter.no_shadow.pattern-expected.html": [
+ "f052442a637ed64db37ad12ea7f799f667ff9cd8",
+ []
+ ],
+ "2d.composite.grid.no_filter.no_shadow.pattern.png": [
+ "ce392a1dcccc5e06a3d163dff873a5647ecdb65c",
+ []
+ ],
+ "2d.composite.grid.no_filter.shadow.drawImage-expected.html": [
+ "ad07c35d3101c61b1e1ac4df2ec05348af251439",
+ []
+ ],
+ "2d.composite.grid.no_filter.shadow.drawImage.png": [
+ "aca03a61b220c1022c65b71dbd092f7b6de3c754",
+ []
+ ],
+ "2d.composite.grid.no_filter.shadow.fillRect-expected.html": [
+ "e16a5fcf4582efd0e691da4057f501e4be3702d3",
+ []
+ ],
+ "2d.composite.grid.no_filter.shadow.fillRect.png": [
+ "aca03a61b220c1022c65b71dbd092f7b6de3c754",
+ []
+ ],
+ "2d.composite.grid.no_filter.shadow.pattern-expected.html": [
+ "01e1d4d7b264624b94066ddd3b9e0f696b8c8517",
+ []
+ ],
+ "2d.composite.grid.no_filter.shadow.pattern.png": [
+ "aca03a61b220c1022c65b71dbd092f7b6de3c754",
+ []
+ ]
+ },
"fill-and-stroke-styles": {
"2d.gradient.interpolate.alpha.png": [
"af5ac0f07d64e7598e0ea6a8e37cff2a5c4ea2a0",
@@ -453441,19 +455175,19 @@
},
"text": {
"2d.text.draw.fill.basic.png": [
- "8021427a07dc4ed754e2b3b1357aca7029bb0fe3",
+ "70d7b046cb226cfcb2bfeebe3477d3b580d8270a",
[]
],
"2d.text.draw.fill.maxWidth.large.png": [
- "8021427a07dc4ed754e2b3b1357aca7029bb0fe3",
+ "70d7b046cb226cfcb2bfeebe3477d3b580d8270a",
[]
],
"2d.text.draw.fill.rtl.png": [
- "8021427a07dc4ed754e2b3b1357aca7029bb0fe3",
+ "70d7b046cb226cfcb2bfeebe3477d3b580d8270a",
[]
],
"2d.text.draw.stroke.basic.png": [
- "d4f6dc1ee883e0a25a17149bc04154be3e7b5738",
+ "fb3b5b830d345d2aa858e41673e08f99977baf08",
[]
],
"2d.text.drawing.style.reset.fontKerning.none2-expected.html": [
@@ -453488,6 +455222,18 @@
"ad55a2083a740c2eb188da37fbf8dbee60386ff0",
[]
],
+ "2d.text.measure.text-clusters-rendering-align.tentative-expected.html": [
+ "967ae7e46365ff181f4323b39f9ff13bb62a34c7",
+ []
+ ],
+ "2d.text.measure.text-clusters-rendering-baseline.tentative-expected.html": [
+ "2dffe90aadc57ae07067fa7decab24fd43fc8728",
+ []
+ ],
+ "2d.text.measure.text-clusters-rendering-font-change.tentative-expected.html": [
+ "9a9443962dfb988da61453159d02d953e620be6c",
+ []
+ ],
"WEB_FEATURES.yml": [
"1d9e4bab82191d72c374c7399e666bd6bfe42bc2",
[]
@@ -453558,7 +455304,7 @@
[]
],
"gentestutilsunion.py": [
- "2ec2e20886b5bb16c6443daf98e502c408f55c0c",
+ "629b596b51347f196407a11113cbdc3178eda167",
[]
],
"name2dir-canvas.yaml": [
@@ -453590,6 +455336,14 @@
"9147899efc0b08fa7a293a26d2f667a58b7ec4dc",
[]
],
+ "reftest_img.html": [
+ "c058406d49a9e7a1a19a68b43fff84a9dffacdf0",
+ []
+ ],
+ "reftest_img_grid.html": [
+ "20026c3e82c1e9c358f01b690bce9425501c189e",
+ []
+ ],
"reftest_offscreen.html": [
"9e29bd0a9da8bf3a3c6b3ef383ec7da4ae87095b",
[]
@@ -453655,7 +455409,7 @@
[]
],
"compositing.yaml": [
- "6bd0aaad8a51bb6d5eb90163886f8439f041a0b0",
+ "1db0c590db2bce8d1e3429e92ec1f7880cbb3cb9",
[]
],
"conformance_requirements.yaml": [
@@ -453703,7 +455457,7 @@
[]
],
"text.yaml": [
- "4c2ae798596ee9d1a20fd8220b29992b5c72bd05",
+ "78312640c08938cf81e38ca0671b82280093e43b",
[]
],
"the-canvas-state.yaml": [
@@ -459232,6 +460986,10 @@
[]
]
},
+ "table-align-float-ref.xhtml": [
+ "fc6b78605755f9096b51eaa4c6908176d212c720",
+ []
+ ],
"table-background-print-ref.html": [
"3aa0abd3207469be60d54475e92b4f882f69dcdc",
[]
@@ -467788,7 +469546,7 @@
[]
],
"turtledove.idl": [
- "ff48d311914e49e9de8a96f7ac3a26da144da818",
+ "0309f5047b36491be282892acb661bfda6562ae5",
[]
],
"ua-client-hints.idl": [
@@ -471329,6 +473087,14 @@
]
}
},
+ "state": {
+ "resources": {
+ "helpers.js": [
+ "658d267351bd568399d81cd720b6b0b9f0fbcbb5",
+ []
+ ]
+ }
+ },
"updateCurrentEntry-method": {
"resources": {
"opaque-origin-page.html": [
@@ -472407,7 +474173,7 @@
[]
],
"digital-credentials-get.html": [
- "489e42913592ae72641b6f4d55eb6d308b8e79ca",
+ "543417f230a59b3d09705b20775a38cbabaf7a22",
[]
],
"nested-sandbox.html": [
@@ -476140,6 +477906,10 @@
[]
],
"support": {
+ "html5lib-testcase-support.js": [
+ "4f15e46a7eb0498658417639aa8f61e3cc46d0c6",
+ []
+ ],
"testcases.sub.js": [
"7ce755ca060b951db57d41fdf0eccf4cf70eaa22",
[]
@@ -479819,7 +481589,7 @@
[]
],
"simple-module.js": [
- "11b650811dcc9cea02d541a72314ea84a335f3fb",
+ "eeb0ce95b040687a57a7eaa65be7c17a88b592fe",
[]
],
"simple-module.js.headers": [
@@ -480368,7 +482138,7 @@
[]
],
"csp-script-src-self.html": [
- "8dc382068a347990c91aeaafc8b509553cac8767",
+ "61a8f31396c89b3c29dfd593f961cb0b7c8b2e1e",
[]
],
"csp-script-src-strict-dynamic.html": [
@@ -481643,6 +483413,10 @@
"610a3ddb2d21da119fb4a53f5f351dff0190880c",
[]
],
+ "small-nested-viewbox-ref.html": [
+ "f737b09ff49ad1cbe252c7f7da707e37fb382c9d",
+ []
+ ],
"support": {
"resources.svg": [
"85b6833a6601a45d1847320efb7259080cba5359",
@@ -482353,11 +484127,11 @@
[]
],
"cacert.key": [
- "421cae4c51a6dae556ad586f54af40ab439346bc",
+ "dd47af3f939c7dd3479810a82670c4c3f3cd212e",
[]
],
"cacert.pem": [
- "cf16ae8aea3022ba7312a753e1d989ed0e2286b1",
+ "7b3fb3da14d0d228bfc83a58affd11b535ab0b69",
[]
],
"config.json": [
@@ -482365,11 +484139,11 @@
[]
],
"web-platform.test.key": [
- "0df3f579240d2c80e84804ebcc3a6812ef4a02d5",
+ "4f68bb3caa0ddaef5799966bb88477273bbdcc0d",
[]
],
"web-platform.test.pem": [
- "1c5859d2066ad96bfaea9231e2ccbae48c13dcb7",
+ "02a2d94e935ab6c760b282665d3ec409d51a739e",
[]
]
},
@@ -482493,7 +484267,7 @@
[]
],
"jobs.py": [
- "fe8eaae069eb3c548cf22af0fa5e7e65063a1b2a",
+ "a831d24bebec2cdaf05635a7f3f3250a7078bcd0",
[]
],
"macos_color_profile.py": [
@@ -493815,7 +495589,7 @@
[]
],
"chrome_spki_certs.py": [
- "08ff16145cc4564696262672a58ae07b307903f5",
+ "875ae3ea4a7ea7e1241023e9b31b097c1d44e2c4",
[]
],
"chromium.py": [
@@ -493911,11 +495685,11 @@
[]
],
"executorchrome.py": [
- "53c11f133e5e0197b86435a62b18442315cbbcc0",
+ "914c5d1c0e3c1acce82a7337e5c35fb4457959d0",
[]
],
"executoredge.py": [
- "75a3313c55c3dff4f63104953204b6095949703d",
+ "95b40bd8db14f6d59c1bdd2eed10f857b613dcc9",
[]
],
"executormarionette.py": [
@@ -493935,7 +495709,7 @@
[]
],
"executorwebdriver.py": [
- "3c1bdfd7a726e7359a9050ad840240c61a980fdf",
+ "f04d615ee11be079504209bc6c68fdacb1c71370",
[]
],
"executorwktr.py": [
@@ -493947,7 +495721,7 @@
[]
],
"protocol.py": [
- "75edc14676784a1cbaad702d4499077c026588c0",
+ "5b59482d9bd6e6960de8e8345247684c177f5a63",
[]
],
"pytestrunner": {
@@ -494805,7 +496579,7 @@
[]
],
"navigation-report-only-support.html": [
- "a16995ba903688327d5b58dc9d7c5457583ec758",
+ "791559f7a19bec50648245c15c1e92723034d5b9",
[]
],
"navigation-report-only-support.html.headers": [
@@ -494813,13 +496587,17 @@
[]
],
"navigation-support.html": [
- "c2c8a82f5145885f64e5ce99a9e8c6f039efa370",
+ "47f33c9fb6430cb0ded9f09facd8a3974901d1f5",
[]
],
"navigation-support.html.headers": [
"604e765da46d85fe8ab85d3097fe7c2cbe00a930",
[]
],
+ "navigation-support.js": [
+ "41dce761def94a328ac75f05699a6f079e0d0bee",
+ []
+ ],
"resolve-spv.js": [
"89e58b2a8b75e0200d145b028d032caa688f32cd",
[]
@@ -495513,7 +497291,7 @@
[]
],
"urltestdata.json": [
- "9dbe5456a96950085aa4ee11fe757b90350b6bad",
+ "0ebaf4cd4c42e785bcfafd4a49faec318c8fee4a",
[]
]
},
@@ -495782,20 +497560,30 @@
[]
]
},
+ "jspi": {
+ "README.txt": [
+ "c65b9893c6fd30b535009390b86d275e33085643",
+ []
+ ],
+ "testharness-additions.js": [
+ "e146c52f96dfbace060f135bdc047bf787a990b8",
+ []
+ ]
+ },
"memory": {
"assertions.js": [
- "b539513adcab7d84e67d65fcf97453e9bc22de43",
+ "1430c523882307d025c81788ac90322de5a9d66b",
[]
]
},
"table": {
"assertions.js": [
- "19cc5c3b92d6fa6748c3831f3629c92b62ed757f",
+ "4fcd3517a6a869545ab62ba7a757c6e432823ca4",
[]
]
},
"wasm-module-builder.js": [
- "90ccc954a5dba362f9ea2c57560bbe8d64002800",
+ "7fa196c58c17fd5e2bafe336b0182b754de09d6c",
[]
]
},
@@ -497793,7 +499581,7 @@
},
"network": {
"__init__.py": [
- "0c3338362d309f859fb660b043ed2c081e0db4dc",
+ "5decb28a1a97fb91ad832c1c0ef05cecd1fc2643",
[]
],
"add_intercept": {
@@ -498887,7 +500675,7 @@
],
"resources": {
"utils.js": [
- "460fe46115476b073c5e650e119a6f6dd263b9ee",
+ "973c16baca760264cd71dc8b28288a8b01a68d51",
[]
],
"utils_validation.js": [
@@ -505454,11 +507242,83 @@
}
]
],
- "cursor-overloads.htm": [
- "7beeaa2bb39cdedb01eb8b8d7a414c6a4b37e067",
+ "cursor-overloads.any.js": [
+ "dd80d2f40382407ac468028c5aa294374f4b561b",
[
- null,
- {}
+ "IndexedDB/cursor-overloads.any.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/cursor-overloads.any.serviceworker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/cursor-overloads.any.sharedworker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/cursor-overloads.any.worker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ]
+ ]
+ }
]
],
"database-names-by-origin.html": [
@@ -505503,18 +507363,162 @@
}
]
],
- "delete-request-queue.html": [
- "d8dfbf9a6061dd89244841e9edc42426b5f3e9bb",
+ "delete-request-queue.any.js": [
+ "6b2034c7f6b65380d5e15398676598759d084b5a",
[
- null,
- {}
+ "IndexedDB/delete-request-queue.any.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/delete-request-queue.any.serviceworker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/delete-request-queue.any.sharedworker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/delete-request-queue.any.worker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ]
+ ]
+ }
]
],
- "error-attributes.html": [
- "d65bf21790a16a81eae57f1f3fb1c85235e3890a",
+ "error-attributes.any.js": [
+ "9b5003040b273b14a086025425a4a0af06e73274",
[
- null,
- {}
+ "IndexedDB/error-attributes.any.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/error-attributes.any.serviceworker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/error-attributes.any.sharedworker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/error-attributes.any.worker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ]
+ ]
+ }
]
],
"event-dispatch-active-flag.html": [
@@ -510677,32 +512681,384 @@
{}
]
],
- "upgrade-transaction-deactivation-timing.html": [
- "8119c9ab261ee632b3ee4f9c08a4ce25ea626adc",
+ "upgrade-transaction-deactivation-timing.any.js": [
+ "d11f821201cb9d2ca4d7b1f8e69dc3ac61293445",
[
- null,
- {}
+ "IndexedDB/upgrade-transaction-deactivation-timing.any.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "Upgrade transaction deactivation timing"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ],
+ [
+ "script",
+ "resources/support-promises.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/upgrade-transaction-deactivation-timing.any.serviceworker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "Upgrade transaction deactivation timing"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ],
+ [
+ "script",
+ "resources/support-promises.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/upgrade-transaction-deactivation-timing.any.sharedworker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "Upgrade transaction deactivation timing"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ],
+ [
+ "script",
+ "resources/support-promises.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/upgrade-transaction-deactivation-timing.any.worker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "Upgrade transaction deactivation timing"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ],
+ [
+ "script",
+ "resources/support-promises.js"
+ ]
+ ]
+ }
]
],
- "upgrade-transaction-lifecycle-backend-aborted.html": [
- "862e85144d64a12eda04e0b48c6954ff996486a0",
+ "upgrade-transaction-lifecycle-backend-aborted.any.js": [
+ "841a83c6e0d1c214e6c63573657fe4011ae16aa6",
[
- null,
- {}
+ "IndexedDB/upgrade-transaction-lifecycle-backend-aborted.any.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB: backend-aborted versionchange transaction lifecycle"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ],
+ [
+ "script",
+ "resources/support-promises.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/upgrade-transaction-lifecycle-backend-aborted.any.serviceworker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB: backend-aborted versionchange transaction lifecycle"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ],
+ [
+ "script",
+ "resources/support-promises.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/upgrade-transaction-lifecycle-backend-aborted.any.sharedworker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB: backend-aborted versionchange transaction lifecycle"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ],
+ [
+ "script",
+ "resources/support-promises.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/upgrade-transaction-lifecycle-backend-aborted.any.worker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB: backend-aborted versionchange transaction lifecycle"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ],
+ [
+ "script",
+ "resources/support-promises.js"
+ ]
+ ]
+ }
]
],
- "upgrade-transaction-lifecycle-committed.html": [
- "347d940aeefae01f9a41c8c460ae29135ccee4d0",
+ "upgrade-transaction-lifecycle-committed.any.js": [
+ "85b447ea95131dad441ddd44cc66eec77ed7c156",
[
- null,
- {}
+ "IndexedDB/upgrade-transaction-lifecycle-committed.any.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB: committed versionchange transaction lifecycle"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ],
+ [
+ "script",
+ "resources/support-promises.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/upgrade-transaction-lifecycle-committed.any.serviceworker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB: committed versionchange transaction lifecycle"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ],
+ [
+ "script",
+ "resources/support-promises.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/upgrade-transaction-lifecycle-committed.any.sharedworker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB: committed versionchange transaction lifecycle"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ],
+ [
+ "script",
+ "resources/support-promises.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/upgrade-transaction-lifecycle-committed.any.worker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB: committed versionchange transaction lifecycle"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ],
+ [
+ "script",
+ "resources/support-promises.js"
+ ]
+ ]
+ }
]
],
- "upgrade-transaction-lifecycle-user-aborted.html": [
- "4094ce34f34aa06d8ce4433b963819cf4f39f6b6",
+ "upgrade-transaction-lifecycle-user-aborted.any.js": [
+ "4346e1a675dfa8ff1a8dea3f7f141a1971f92f8e",
[
- null,
- {}
+ "IndexedDB/upgrade-transaction-lifecycle-user-aborted.any.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB: user-abort()ed versionchange transaction lifecycle"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ],
+ [
+ "script",
+ "resources/support-promises.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/upgrade-transaction-lifecycle-user-aborted.any.serviceworker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB: user-abort()ed versionchange transaction lifecycle"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ],
+ [
+ "script",
+ "resources/support-promises.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/upgrade-transaction-lifecycle-user-aborted.any.sharedworker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB: user-abort()ed versionchange transaction lifecycle"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ],
+ [
+ "script",
+ "resources/support-promises.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "IndexedDB/upgrade-transaction-lifecycle-user-aborted.any.worker.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "IndexedDB: user-abort()ed versionchange transaction lifecycle"
+ ],
+ [
+ "global",
+ "window,worker"
+ ],
+ [
+ "script",
+ "resources/support.js"
+ ],
+ [
+ "script",
+ "resources/support-promises.js"
+ ]
+ ]
+ }
]
],
"value.any.js": [
@@ -519832,7 +522188,7 @@
]
},
"aggregatable-report-no-contributions.sub.https.html": [
- "b42a61b7bd50a2934b0b7f479618d466047146bc",
+ "b84f1905626fcfd2b3344abc3518c22aca9186b9",
[
null,
{
@@ -519982,7 +522338,7 @@
]
],
"simple-verbose-debug-report.sub.https.html": [
- "8a477f732f494a84e5802ace639d8cbec4e2a6c9",
+ "cc2e37cae8eb826b1182c40d7fa2ad81e789c12f",
[
null,
{
@@ -528636,7 +530992,7 @@
]
],
"async-navigator-clipboard-basics.https.html": [
- "5d6f701bdb751641343feda37cea44f31ecaf338",
+ "f7aed80b17ebd0af8f4c255ef83dfc85a7eb71ce",
[
null,
{
@@ -529393,6 +531749,24 @@
}
]
],
+ "y-dialog-disconnected.html": [
+ "0bd41b5bb2461c6add5c10def3507800547f15e0",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
+ "y-popover-disconnected.html": [
+ "22fbdbfe73b04a8cdd32dd96c505ce2bfddb5844",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
"y.html": [
"78c432de3888eed80fcaf1cdd3d3c03e1a2b3257",
[
@@ -542108,7 +544482,7 @@
]
],
"justify-self-block-in-inline.html": [
- "3a326016bc15914958600156c3a72b5bb77e41b8",
+ "0a3facf3ef7768797031796a93cdbb2424b23c99",
[
null,
{}
@@ -543579,7 +545953,7 @@
]
],
"anchor-scope-basic.html": [
- "147aef8c764863ae2bc305aa92a8e71ef0852be8",
+ "47cb3b8d86a106f37af3e32149b79fbd9c8c2056",
[
null,
{}
@@ -544381,7 +546755,7 @@
]
],
"try-tactic-wm.html": [
- "8dcf98f893979c0511d3bbf6675df16b331a62c9",
+ "69d9c2dff8889e3f6e619ede92f9623296a5e506",
[
null,
{}
@@ -547904,7 +550278,7 @@
]
],
"color-computed-relative-color.html": [
- "8407e527017ec0440e90d5cbacfc5bcc0569907d",
+ "23ee07d177ac525c2ce2b4e60cd1861a33cc23c5",
[
null,
{}
@@ -548051,7 +550425,7 @@
]
],
"color-valid-relative-color.html": [
- "2c4dc0f8e60bf0df1668f9f840b379fda18bd786",
+ "142f96bcf9b562e399b9b47b5cf1babadcb2ad72",
[
null,
{}
@@ -548274,20 +550648,6 @@
{}
]
],
- "at-container-overflowing-parsing.html": [
- "5c15a825853f7e545d43fe6f2c73cb0cc4bc45b4",
- [
- null,
- {}
- ]
- ],
- "at-container-overflowing-serialization.html": [
- "f55cfeb63433cda37e1dd3393fc990107679b522",
- [
- null,
- {}
- ]
- ],
"at-container-parsing.html": [
"5c9d8c1bb9ea63a34016ca1a4b9931186a9c2209",
[
@@ -548302,34 +550662,6 @@
{}
]
],
- "at-container-snapped-parsing.html": [
- "0a8fe50bc38e7bb297cb2f0e9092680918599472",
- [
- null,
- {}
- ]
- ],
- "at-container-snapped-serialization.html": [
- "59cc3d37f4f3fb9293568d5f82c5a060dc3fd456",
- [
- null,
- {}
- ]
- ],
- "at-container-stuck-parsing.html": [
- "a3a1f01458d1ce321b21089ba3f65ffa12ee34d4",
- [
- null,
- {}
- ]
- ],
- "at-container-stuck-serialization.html": [
- "d5abede45c25be5b6c191482dee9936785d48068",
- [
- null,
- {}
- ]
- ],
"at-container-style-parsing.html": [
"c63cc76560b4680d5a33863bda747c9fdde9cada",
[
@@ -548338,7 +550670,7 @@
]
],
"at-container-style-serialization.html": [
- "a30acef9ac21acadf3bddd7099709ffa032a43dc",
+ "bd9d23a4b705de1e842018e94c76b6431412b0cb",
[
null,
{}
@@ -548554,27 +550886,6 @@
{}
]
],
- "container-type-scroll-state-computed.html": [
- "4e80712beab2dc63f7d22bbe0973a5d8e84a56cf",
- [
- null,
- {}
- ]
- ],
- "container-type-scroll-state-containment.html": [
- "cc1af5a08ebb1454ef3ea8ae64fd27de4cbe446c",
- [
- null,
- {}
- ]
- ],
- "container-type-scroll-state-parsing.html": [
- "7f3779bc39d1850d423434fbe94f71e8dfb133cb",
- [
- null,
- {}
- ]
- ],
"container-units-animation.html": [
"79e59dc2a186fb3dc207547df9add7d327a357d5",
[
@@ -548981,73 +551292,159 @@
{}
]
],
- "scroll-state-initially-snapped.html": [
- "64a171c361e7c93f1339887ed224a305c980ef99",
- [
- null,
- {}
- ]
- ],
- "scroll-state-initially-stuck.html": [
- "c0d59b61e768d77afd44a3ae344718a6e83ef728",
- [
- null,
- {}
- ]
- ],
- "scroll-state-snapped-change.html": [
- "6e9843b8b755b163acaa6f8137a86566803044e9",
- [
- null,
- {}
- ]
- ],
- "scroll-state-snapped-container-type-change.html": [
- "556e4c2445b3f313f9bb83ff6beba015d780a260",
- [
- null,
- {}
- ]
- ],
- "scroll-state-snapped-none.html": [
- "8c7aae56bebf34adb9214a36b3779ff45d085dcd",
- [
- null,
- {}
- ]
- ],
- "scroll-state-snapped-snap-changing.html": [
- "161c2e1368dd2ba88442c367cd1f1a06ac9b8b3f",
- [
- null,
- {
- "testdriver": true
- }
- ]
- ],
- "scroll-state-snapped-wm.html": [
- "b6703e81142a3e22726ccd826aaab873b09b43a4",
- [
- null,
- {}
+ "scroll-state": {
+ "at-container-overflowing-parsing.html": [
+ "5c15a825853f7e545d43fe6f2c73cb0cc4bc45b4",
+ [
+ null,
+ {}
+ ]
+ ],
+ "at-container-overflowing-serialization.html": [
+ "f55cfeb63433cda37e1dd3393fc990107679b522",
+ [
+ null,
+ {}
+ ]
+ ],
+ "at-container-snapped-parsing.html": [
+ "0a8fe50bc38e7bb297cb2f0e9092680918599472",
+ [
+ null,
+ {}
+ ]
+ ],
+ "at-container-snapped-serialization.html": [
+ "59cc3d37f4f3fb9293568d5f82c5a060dc3fd456",
+ [
+ null,
+ {}
+ ]
+ ],
+ "at-container-stuck-parsing.html": [
+ "a3a1f01458d1ce321b21089ba3f65ffa12ee34d4",
+ [
+ null,
+ {}
+ ]
+ ],
+ "at-container-stuck-serialization.html": [
+ "d5abede45c25be5b6c191482dee9936785d48068",
+ [
+ null,
+ {}
+ ]
+ ],
+ "container-type-scroll-state-computed.html": [
+ "4e80712beab2dc63f7d22bbe0973a5d8e84a56cf",
+ [
+ null,
+ {}
+ ]
+ ],
+ "container-type-scroll-state-containment.html": [
+ "cc1af5a08ebb1454ef3ea8ae64fd27de4cbe446c",
+ [
+ null,
+ {}
+ ]
+ ],
+ "container-type-scroll-state-parsing.html": [
+ "7f3779bc39d1850d423434fbe94f71e8dfb133cb",
+ [
+ null,
+ {}
+ ]
+ ],
+ "scroll-state-initially-snapped.html": [
+ "64a171c361e7c93f1339887ed224a305c980ef99",
+ [
+ null,
+ {}
+ ]
+ ],
+ "scroll-state-initially-stuck.html": [
+ "c0d59b61e768d77afd44a3ae344718a6e83ef728",
+ [
+ null,
+ {}
+ ]
+ ],
+ "scroll-state-snapped-change.html": [
+ "6e9843b8b755b163acaa6f8137a86566803044e9",
+ [
+ null,
+ {}
+ ]
+ ],
+ "scroll-state-snapped-container-type-change.html": [
+ "4eb5de2679ef423ca3269d8e557d85ca609b20d4",
+ [
+ null,
+ {}
+ ]
+ ],
+ "scroll-state-snapped-none.html": [
+ "8c7aae56bebf34adb9214a36b3779ff45d085dcd",
+ [
+ null,
+ {}
+ ]
+ ],
+ "scroll-state-snapped-snap-changing.html": [
+ "161c2e1368dd2ba88442c367cd1f1a06ac9b8b3f",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
+ "scroll-state-snapped-wm.html": [
+ "b6703e81142a3e22726ccd826aaab873b09b43a4",
+ [
+ null,
+ {}
+ ]
+ ],
+ "scroll-state-stuck-container-type-change.html": [
+ "9c6df64832288706b6748dfdf2db9b3a907eab8c",
+ [
+ null,
+ {}
+ ]
+ ],
+ "scroll-state-stuck-writing-direction.html": [
+ "eb0c1c4a84ec54a1c167455c50f793711bdcffea",
+ [
+ null,
+ {}
+ ]
+ ],
+ "scroll-state-target-query-change.html": [
+ "33459f470b9920e81092a93bc82a72ef01c195b5",
+ [
+ null,
+ {}
+ ]
]
- ],
- "scroll-state-target-query-change.html": [
- "33459f470b9920e81092a93bc82a72ef01c195b5",
+ },
+ "sibling-layout-dependency.html": [
+ "eb3df2ba410d34b62686351fc6834287fbd73baa",
[
null,
{}
]
],
- "sibling-layout-dependency.html": [
- "eb3df2ba410d34b62686351fc6834287fbd73baa",
+ "size-container-no-principal-box.html": [
+ "730bb1d7361ae449d7c129a318d89cd6f9c6adb4",
[
null,
{}
]
],
- "size-container-no-principal-box.html": [
- "730bb1d7361ae449d7c129a318d89cd6f9c6adb4",
+ "size-container-writing-mode-change.html": [
+ "dd709388b7ddffb951f52b2c84d9bbb4e8b93bac",
[
null,
{}
@@ -562833,6 +565230,13 @@
{}
]
],
+ "the-check-pseudo-element.tentative.html": [
+ "70f35091bc9484ae6e6802e64aa18bab9b0b8610",
+ [
+ null,
+ {}
+ ]
+ ],
"tree-abiding-pseudo-elements.html": [
"7839a38049a190135149c0d3d3b35fbc2d29d207",
[
@@ -563131,7 +565535,7 @@
]
],
"has-slotted-functional-changing-001.tentative.html": [
- "209a47298e3554f59a0b02ae6f2d53a3aab20498",
+ "858a8e5abb75902048c3a343df71eed296c3b975",
[
null,
{
@@ -563140,7 +565544,7 @@
]
],
"has-slotted-functional-changing-002.tentative.html": [
- "36fafcb1dcc49b45d6380efdba33955ca294d34b",
+ "76b726a0a4fcc26bab56cf60803b263c042466c2",
[
null,
{
@@ -563149,7 +565553,7 @@
]
],
"has-slotted-functional-changing-003.tentative.html": [
- "9914e452088066d860fd57edb80ec865fba3bcf8",
+ "0b1d710d770d300fca10483e9840de2c6aedd398",
[
null,
{
@@ -563158,7 +565562,7 @@
]
],
"has-slotted-functional-changing-004.tentative.html": [
- "669162050aab4ec3f32c778d78b3f9ab7dae7f2b",
+ "f4fd54f3d487af230764b596298833af29ee3ee1",
[
null,
{
@@ -563768,7 +566172,7 @@
]
],
"start-edge-in-block-layout-direction.html": [
- "043844d05646a0955f21a24f65e7467dd9df632e",
+ "09b1655f86c2997182b22834148d9467ab3e4d17",
[
null,
{}
@@ -566448,7 +568852,7 @@
]
],
"height-interpolation.html": [
- "75e0977fa1164ae25c0c675523ab00599516712a",
+ "7539dcb0161cee5e3d254313e231541aad31a63c",
[
null,
{}
@@ -566893,7 +569297,7 @@
]
],
"keyword-sizes-on-inline-block.html": [
- "a66e118c203678bae777c1fbd572a30dde6e0a5f",
+ "d91d8e6ed9cd2ab7c7f0e418b7715fc88a03b4e1",
[
null,
{}
@@ -567076,6 +569480,29 @@
{}
]
],
+ "stretch": {
+ "block-height-1.html": [
+ "94960f15b96f9fbb6370e94fbbffb9336373c76c",
+ [
+ null,
+ {}
+ ]
+ ],
+ "block-height-2.html": [
+ "7028adf90543f4da49b5549fd4a62d777e92b180",
+ [
+ null,
+ {}
+ ]
+ ],
+ "parsing.html": [
+ "1f5bd39059ebffe59925dd616ad79e7d0a0f7f78",
+ [
+ null,
+ {}
+ ]
+ ]
+ },
"svg-intrinsic-size-001.html": [
"c0ba59819b7b2b14e847acc208456a5e48a40397",
[
@@ -575940,7 +578367,7 @@
]
],
"calc-serialization-002.html": [
- "28a7de5cdabfa2d84140106284921b4457fd9908",
+ "a3b99cf87bbe8bbb9b52b4b762abab979707880b",
[
null,
{}
@@ -575956,7 +578383,7 @@
"calc-size": {
"animation": {
"calc-size-height-interpolation.html": [
- "2126bd8faed1c263c0d3d4132f2c61664bf4fbb3",
+ "20b7b8ba317489feb23ec5191da3204e843e88fb",
[
null,
{
@@ -575981,7 +578408,7 @@
]
],
"interpolate-size-height-composition.html": [
- "22f62b8edac28fe1a6219926839c87660c3248ad",
+ "9a3caa747bbef04ae69a09017d0685235e4cc3a6",
[
null,
{}
@@ -576009,7 +578436,7 @@
]
],
"interpolate-size-max-height-composition.html": [
- "e356fb60746d4dae08dcf234dc843ecf07f4a11c",
+ "958022d4cd0b179da34b2f2e517d85276c4c6bf9",
[
null,
{}
@@ -576023,7 +578450,7 @@
]
],
"interpolate-size-max-width-composition.html": [
- "1e540eaee64a679a7d9d74d39a5b68a88531b6e5",
+ "852e1eed7935a253aef25a001e0036b2457c64bc",
[
null,
{}
@@ -576037,7 +578464,7 @@
]
],
"interpolate-size-min-height-composition.html": [
- "520ec75aaf8e4efa5bac81645913ee66dc034314",
+ "0c3b4d2c7e39174b29dae0e430f89270272fd5ff",
[
null,
{}
@@ -576051,7 +578478,7 @@
]
],
"interpolate-size-min-width-composition.html": [
- "4f9e91394a556a679b7ae369e1cdb350a1eb0315",
+ "2472f8055267bfcc6384cd94fc27b33252c79156",
[
null,
{}
@@ -576072,7 +578499,7 @@
]
],
"interpolate-size-width-composition.html": [
- "a84e0bec3d517a382067c98f3d234d6ecb078fcc",
+ "529eac2f7ff23452010c054e3660aa9fc5224983",
[
null,
{}
@@ -576480,7 +578907,7 @@
]
],
"minmax-length-percent-serialize.html": [
- "0a109d7c18ecfb30855cf6b147ea9b423385ac99",
+ "5d11b85046741b6665775cb5549e87c00d1fd477",
[
null,
{}
@@ -576627,7 +579054,7 @@
]
],
"round-function.html": [
- "338ecaed9044d9dc270557bc15c97b4531b74ace",
+ "fd35567a575b3dfee00fa2ff60cb9ebec163485e",
[
null,
{}
@@ -577229,6 +579656,31 @@
}
]
],
+ "layered-capture": {
+ "opacity-computed-style.tentative.html": [
+ "f370b7b03d268f9abdaa0e3782e2ef41d4a17f00",
+ [
+ null,
+ {}
+ ]
+ ],
+ "parsing": {
+ "view-transition-capture-mode-invalid.tentative.html": [
+ "6bcd77cdae03e0399a039c846caa273b7f054a0c",
+ [
+ null,
+ {}
+ ]
+ ],
+ "view-transition-capture-mode-valid.tentative.html": [
+ "2b739fcfe289127f6d88b9235d84417a0746d3a3",
+ [
+ null,
+ {}
+ ]
+ ]
+ }
+ },
"mix-blend-mode-only-on-transition.html": [
"4149142cf326e0de0deed808e99561ca89d9870a",
[
@@ -577482,15 +579934,6 @@
]
]
},
- "nested": {
- "opacity-computed-style.tentative.html": [
- "f370b7b03d268f9abdaa0e3782e2ef41d4a17f00",
- [
- null,
- {}
- ]
- ]
- },
"no-crash-set-exception.html": [
"bc0d764a590aaed95d2e6afe487f2477385a9c94",
[
@@ -583650,7 +586093,7 @@
]
],
"CustomElementRegistry.html": [
- "5b75fc651fcf74685e7f6cd6e753c9cbfd44de48",
+ "87da806bcab72e02c6c54bee8c1d0e5781700c1c",
[
null,
{}
@@ -584931,10 +587374,12 @@
},
"digital-credentials": {
"allow-attribute.https.html": [
- "412236268086d805fb74346c2411db91dcfdc459",
+ "d988e94cd23547803873616432359ebd572e1242",
[
null,
- {}
+ {
+ "testdriver": true
+ }
]
],
"create.tentative.https.html": [
@@ -588963,6 +591408,13 @@
{}
]
],
+ "custom-element-move-reactions.html": [
+ "ce0302cd7342d1222746645331f79a57099c0bec",
+ [
+ null,
+ {}
+ ]
+ ],
"focus-preserve.html": [
"a00e8b77880697a51d4418fc15637b1dcef6914b",
[
@@ -590426,6 +592878,37 @@
}
]
],
+ "delete-before-invisible-line-break.html": [
+ "ec88079d31e7f9fe819ee0e8f00156872cc5ea05",
+ [
+ "editing/other/delete-before-invisible-line-break.html?white-space=normal",
+ {
+ "testdriver": true,
+ "timeout": "long"
+ }
+ ],
+ [
+ "editing/other/delete-before-invisible-line-break.html?white-space=pre",
+ {
+ "testdriver": true,
+ "timeout": "long"
+ }
+ ],
+ [
+ "editing/other/delete-before-invisible-line-break.html?white-space=pre-line",
+ {
+ "testdriver": true,
+ "timeout": "long"
+ }
+ ],
+ [
+ "editing/other/delete-before-invisible-line-break.html?white-space=pre-wrap",
+ {
+ "testdriver": true,
+ "timeout": "long"
+ }
+ ]
+ ],
"delete-in-child-of-head.tentative.html": [
"978cf83d47add5ef754e588074844d0e624dfa27",
[
@@ -590620,6 +593103,24 @@
{}
]
],
+ "double-click-range-selection-in-floating-list-item.html": [
+ "898f42b9b0428a22287d11bb55819b77a6d13df4",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
+ "double-click-range-selection-in-list-item.html": [
+ "18dee19966a2d469d78fb1c4140ddf4b8ce52d76",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
"edit-in-textcontrol-immediately-after-hidden.tentative.html": [
"2cdffd6e2c07b93810e9ff115e2e92bdb4bc27f0",
[
@@ -590907,6 +593408,37 @@
}
]
],
+ "forwarddelete-before-invisible-line-break.html": [
+ "aebfdc2899eeda47600ecf6c1b0758dbd67ac064",
+ [
+ "editing/other/forwarddelete-before-invisible-line-break.html?white-space=normal",
+ {
+ "testdriver": true,
+ "timeout": "long"
+ }
+ ],
+ [
+ "editing/other/forwarddelete-before-invisible-line-break.html?white-space=pre",
+ {
+ "testdriver": true,
+ "timeout": "long"
+ }
+ ],
+ [
+ "editing/other/forwarddelete-before-invisible-line-break.html?white-space=pre-line",
+ {
+ "testdriver": true,
+ "timeout": "long"
+ }
+ ],
+ [
+ "editing/other/forwarddelete-before-invisible-line-break.html?white-space=pre-wrap",
+ {
+ "testdriver": true,
+ "timeout": "long"
+ }
+ ]
+ ],
"html-text-copy-paste-of-anchor-with-href-in-content-editable.html": [
"5724b59ada4bb34fe416cb0031643e1fd4973667",
[
@@ -593938,7 +596470,7 @@
]
],
"insertText.html": [
- "9045e04d368f3fa1b5bfac5f7d22a429d3c9701c",
+ "664b9befb8d33b81e28971d69345cc2142f21a0b",
[
"editing/plaintext-only/insertText.html?white-space=normal",
{
@@ -609051,6 +611583,24 @@
"testdriver": true
}
]
+ ],
+ "idlharness.https.window.js": [
+ "891d334e9f63128312448764a5c42126eba088d4",
+ [
+ "eyedropper/idlharness.https.window.html",
+ {
+ "script_metadata": [
+ [
+ "script",
+ "/resources/WebIDLParser.js"
+ ],
+ [
+ "script",
+ "/resources/idlharness.js"
+ ]
+ ]
+ }
+ ]
]
},
"feature-policy": {
@@ -610790,6 +613340,13 @@
{}
]
],
+ "http-localhost-url.https.html": [
+ "a8b16d75c858bdd7ebfa3d782754f0c2e878b11b",
+ [
+ null,
+ {}
+ ]
+ ],
"ignore-child-fenced-frame-onload-event.https.html": [
"a542c25909102e7b3ad8daf5837efb59f467f86e",
[
@@ -630997,7 +633554,7 @@
]
],
"get-interest-group-auction-data.https.window.js": [
- "3788045c8c21556114f91c432a5d4d4f3e74fd0e",
+ "453d0f8e64285694e8ff30cba41331d331151970",
[
"fledge/tentative/get-interest-group-auction-data.https.window.html?1-4",
{
@@ -658867,6 +661424,20 @@
{}
]
],
+ "2d.text.measure.text-clusters-position.tentative.html": [
+ "cc6f366e0722600d2a1775df27c1664f68e69191",
+ [
+ null,
+ {}
+ ]
+ ],
+ "2d.text.measure.text-clusters-range.tentative.html": [
+ "effa53c4c954b623d7d28b91cd3bfbe29cb490ef",
+ [
+ null,
+ {}
+ ]
+ ],
"2d.text.measure.text-clusters-split.tentative.html": [
"63c7cce72be7c1ede567c2f00001d7a57addadbc",
[
@@ -660515,6 +663086,90 @@
{}
]
],
+ "2d.composite.grid.filter.no_shadow.drawImage.worker.js": [
+ "45329fcd9c8b222abe33fff963358e4b8ae728d6",
+ [
+ "html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.worker.html",
+ {}
+ ]
+ ],
+ "2d.composite.grid.filter.no_shadow.fillRect.worker.js": [
+ "dff55436a40b07924332b17725d930f9c3956a4c",
+ [
+ "html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.worker.html",
+ {}
+ ]
+ ],
+ "2d.composite.grid.filter.no_shadow.pattern.worker.js": [
+ "d3e79cd2d156f65378c8e9ddeb4f7ee326a0c2c4",
+ [
+ "html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.worker.html",
+ {}
+ ]
+ ],
+ "2d.composite.grid.filter.shadow.drawImage.worker.js": [
+ "9a9c2f9363225722249284b1ac48709482b1f204",
+ [
+ "html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.worker.html",
+ {}
+ ]
+ ],
+ "2d.composite.grid.filter.shadow.fillRect.worker.js": [
+ "f495009b301eeb9c36286f6fe8dc6edcc835427c",
+ [
+ "html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.worker.html",
+ {}
+ ]
+ ],
+ "2d.composite.grid.filter.shadow.pattern.worker.js": [
+ "d960d0d54014226083b2d86e922048aea84a6db1",
+ [
+ "html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.worker.html",
+ {}
+ ]
+ ],
+ "2d.composite.grid.no_filter.no_shadow.drawImage.worker.js": [
+ "de1686a76e80b558ca3b9b40f86b9ea80a053a1d",
+ [
+ "html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.worker.html",
+ {}
+ ]
+ ],
+ "2d.composite.grid.no_filter.no_shadow.fillRect.worker.js": [
+ "cb60645b70402e4e97a34d78687e12365215613c",
+ [
+ "html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.worker.html",
+ {}
+ ]
+ ],
+ "2d.composite.grid.no_filter.no_shadow.pattern.worker.js": [
+ "e1479261ce22afe939a593343c1dcacc01dc0050",
+ [
+ "html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.worker.html",
+ {}
+ ]
+ ],
+ "2d.composite.grid.no_filter.shadow.drawImage.worker.js": [
+ "c7827238f6936c67f0a1a705008c38d4c75bc310",
+ [
+ "html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.worker.html",
+ {}
+ ]
+ ],
+ "2d.composite.grid.no_filter.shadow.fillRect.worker.js": [
+ "217fe38a8de678c2dc69b21faf5bc8abb6c2fd50",
+ [
+ "html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.worker.html",
+ {}
+ ]
+ ],
+ "2d.composite.grid.no_filter.shadow.pattern.worker.js": [
+ "f26657b521426a8773ef674b1be07c31411adbc8",
+ [
+ "html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.worker.html",
+ {}
+ ]
+ ],
"2d.composite.image.clear.html": [
"f001c4409c3e2c2ca59b64de64174cf6251624f6",
[
@@ -672563,6 +675218,34 @@
{}
]
],
+ "2d.text.measure.text-clusters-position.tentative.html": [
+ "780a4f52623252e4ecbda532fa18c7d1bf25884c",
+ [
+ null,
+ {}
+ ]
+ ],
+ "2d.text.measure.text-clusters-position.tentative.worker.js": [
+ "90ee50fa50f222975939362de77fdbea7afc468e",
+ [
+ "html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.worker.html",
+ {}
+ ]
+ ],
+ "2d.text.measure.text-clusters-range.tentative.html": [
+ "9bd2a026618c252d32141287f8d9c1d8b93300a9",
+ [
+ null,
+ {}
+ ]
+ ],
+ "2d.text.measure.text-clusters-range.tentative.worker.js": [
+ "db76d19edf362013e64a7609c42e37332e8eda07",
+ [
+ "html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.worker.html",
+ {}
+ ]
+ ],
"2d.text.measure.text-clusters-split.tentative.html": [
"6a5fd475795e140ff8b8533b8d070baf97f0ebfe",
[
@@ -678426,7 +681109,7 @@
]
],
"nameditem-names.html": [
- "3f76d85a1bca783df916b159409a94c30488a2dd",
+ "111738a1444652b9e7e1eed61bb55f2615445923",
[
null,
{}
@@ -678924,6 +681607,13 @@
{}
]
],
+ "innertext-whitespace-pre-line.html": [
+ "c5696df9de87fa86803b87ed95101d320f146197",
+ [
+ null,
+ {}
+ ]
+ ],
"multiple-text-nodes.window.js": [
"07c55e966933924d49ef82d98f35e639e5659669",
[
@@ -691243,6 +693933,15 @@
]
],
"customizable-select": {
+ "button-in-popover.tentative.html": [
+ "da217f03e15e521ca08265a6f069893c8b0d0a36",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
"nested-options.tenative.html": [
"7e89a5ad428f69b04d21d1ba7dbd56a8d06ff988",
[
@@ -691331,7 +694030,7 @@
]
],
"select-parsing.tentative.html": [
- "5aa4638f0be81919e01d53ea4bae5b0c1ba60cc5",
+ "1a5b059997bac428f70e406169d27684462cd5c6",
[
null,
{}
@@ -692354,6 +695053,15 @@
{}
]
],
+ "popover-dialog-does-not-block-mouse-events.html": [
+ "97f17410f70a9311b19a77dcb4496e1c654a41bd",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
"remove-dialog-should-unblock-document.html": [
"2f2fbad1fc65b02296fbc05ad4bc9c17e66f584e",
[
@@ -692392,7 +695100,7 @@
]
],
"toggle-events.tentative.html": [
- "b30433f4a92a3e043ccef6d75305408e6a75d6f0",
+ "555dc03b019e6293047322c278febf80d9e99cbe",
[
null,
{}
@@ -703330,7 +706038,7 @@
},
"update-rendering": {
"child-document-raf-order.html": [
- "eccc1bde7fb83449275ed61e0dacaeb13d684456",
+ "222c1af444e5c3f7aab2ac466b6bd1a7e2c93e3e",
[
null,
{}
@@ -712509,7 +715217,7 @@
]
],
"VideoTrackGenerator-with-window-tracks.https.html": [
- "36fc4135e23443c404c8255fbae1132effa9100d",
+ "dfe000fbddb6cddd52538dfdcb686c2357ca1ff7",
[
null,
{}
@@ -718101,9 +720809,13 @@
},
"state": {
"cross-document-away-and-back.html": [
- "cccaebdf7b9af3bf4f5715f1592b29f12ee12022",
+ "f531ec6771544f62a81c113f7a945cb6ac8b1066",
[
- null,
+ "navigation-api/state/cross-document-away-and-back.html?method=navigate",
+ {}
+ ],
+ [
+ "navigation-api/state/cross-document-away-and-back.html?method=updateCurrentEntry",
{}
]
],
@@ -718122,30 +720834,46 @@
]
],
"cross-document-location-api.html": [
- "395d95c6fbe64556e9de5869fd48e368190b66a7",
+ "5a22473e6bbfd1b3d3e8f5314e580fefcf032103",
[
- null,
+ "navigation-api/state/cross-document-location-api.html?method=navigate",
+ {}
+ ],
+ [
+ "navigation-api/state/cross-document-location-api.html?method=updateCurrentEntry",
{}
]
],
"history-pushState.html": [
- "7d3c79ba6ca2872754bdbf6073390405d9c13e99",
+ "8c63f72e53ba36071e599b81981fb9ffe3d6ed4d",
[
- null,
+ "navigation-api/state/history-pushState.html?method=navigate",
+ {}
+ ],
+ [
+ "navigation-api/state/history-pushState.html?method=updateCurrentEntry",
{}
]
],
"history-replaceState.html": [
- "bdf3561639321ff4d307544d8ca19fceadebbd93",
+ "7098201caa748ead09b7ca92b5d88560d6c76263",
[
- null,
+ "navigation-api/state/history-replaceState.html?method=navigate",
+ {}
+ ],
+ [
+ "navigation-api/state/history-replaceState.html?method=updateCurrentEntry",
{}
]
],
"location-reload.html": [
- "bf1bc105fbfc84885b9f5b47c0962b751271b3b0",
+ "5a566c66fd5a4da476b7215009f74fb92e34136e",
[
- null,
+ "navigation-api/state/location-reload.html?method=navigate",
+ {}
+ ],
+ [
+ "navigation-api/state/location-reload.html?method=updateCurrentEntry",
{}
]
],
@@ -718172,20 +720900,6 @@
{}
]
],
- "cross-document-away-and-back.html": [
- "c37d5e979a069f73faf7972801792bc36c5a6f01",
- [
- null,
- {}
- ]
- ],
- "cross-document-location-api.html": [
- "26191fb8761b6dfbca7881f5b5bb2e62d7690155",
- [
- null,
- {}
- ]
- ],
"exception-order-initial-about-blank-unserializablestate.html": [
"010632a40fcda3c98ff76965c61453919d6f42ba",
[
@@ -718200,20 +720914,6 @@
{}
]
],
- "history-pushState.html": [
- "852294c64f4e8fd596637032ecc363076ca86ee7",
- [
- null,
- {}
- ]
- ],
- "history-replaceState.html": [
- "3eb91a9a80cef8e1a2036181503867ec490c1168",
- [
- null,
- {}
- ]
- ],
"initial-about-blank.html": [
"c28137c082a3b30fd9f575abd797c107108d0851",
[
@@ -718221,13 +720921,6 @@
{}
]
],
- "location-reload.html": [
- "8589eeb694e73cb08852ec31c0577cb5d21e2a30",
- [
- null,
- {}
- ]
- ],
"no-args.html": [
"3fd011e3d37335cacc2c02c3d6649e9a3dc22fd8",
[
@@ -740169,6 +742862,13 @@
{}
]
],
+ "html5lib-basics.tentative.html": [
+ "1df4d49f704daa2e8f8370774df5d2b421972eff",
+ [
+ null,
+ {}
+ ]
+ ],
"idlharness.https.window.js": [
"384317b8e55bd318464c68e20ca737bfb5b2c966",
[
@@ -742428,7 +745128,7 @@
]
],
"animation-timeline-computed.html": [
- "1e621eee531c22e80d98fb3dc30517cf4153ce07",
+ "51454f6853d3a6dc04ef7cdfd0b71100ec6af952",
[
null,
{}
@@ -742477,7 +745177,7 @@
]
],
"animation-timeline-parsing.html": [
- "9e3c1078b5b416ac8402abe8901ca8e1c8d0a9fa",
+ "44e9caf002e5b5c05d5bd5653fe5fd81f3843900",
[
null,
{}
@@ -743021,7 +745721,7 @@
]
],
"setting-current-time.html": [
- "f6c826db6993663462727f8ec4629e62adf28f61",
+ "5daa459bbeb88523a8713afed25b5d35785a61f0",
[
null,
{}
@@ -743035,7 +745735,7 @@
]
],
"setting-start-time.html": [
- "aae1849565b15271105614d198b161f27d091940",
+ "d950eb8188de218be712b6fedbf0f7b312e7d27c",
[
null,
{}
@@ -743924,6 +746624,13 @@
]
]
},
+ "caret-position-should-be-correct-while-moveup-movedown.html": [
+ "45d95a96b040a6f168068f975fb203503024ac49",
+ [
+ null,
+ {}
+ ]
+ ],
"collapse-00.html": [
"6adaca4002dc7b4e103e72c75e8f44b0ffeefd70",
[
@@ -744321,7 +747028,25 @@
]
],
"Selection-getComposedRanges-collapsed.html": [
- "99ab82eb39cf44ac19cc32b42bd50eb1eef1b93a",
+ "3ea6e0c62c734a8b13f5737daca5c4684b4b0bfa",
+ [
+ null,
+ {}
+ ]
+ ],
+ "Selection-getComposedRanges-dom-mutations-removal.html": [
+ "d89dcb2ce9ddb9318c36a66b64b1abb3ce1aef7c",
+ [
+ "selection/shadow-dom/tentative/Selection-getComposedRanges-dom-mutations-removal.html?mode=closed",
+ {}
+ ],
+ [
+ "selection/shadow-dom/tentative/Selection-getComposedRanges-dom-mutations-removal.html?mode=open",
+ {}
+ ]
+ ],
+ "Selection-getComposedRanges-slot.html": [
+ "d9664b0e1505fad35444628d707de390fac0e11f",
[
null,
{}
@@ -748825,7 +751550,7 @@
]
],
"grid-order-across-scopes.html": [
- "76e5af8c74b24201bd73911c3f3720d6f5861292",
+ "629bfea2aff5c66a179d304e2a14c48c5426ec93",
[
null,
{
@@ -748853,7 +751578,7 @@
]
],
"grid-order-with-display-contents.html": [
- "b69f3d20799abdd562cff016818252818ceac8bc",
+ "6d012f49cea56be6d11f7249639c757d41e9878e",
[
null,
{
@@ -748912,7 +751637,7 @@
]
],
"grid-order-with-slots.html": [
- "f52c9ebdc817a4813d3f521c63caa447ddc87db6",
+ "eff412296d9627ff46bc7c298f91d78eb15d71c0",
[
null,
{
@@ -750037,6 +752762,13 @@
{}
]
],
+ "interest-groups.tentative.https.sub.html": [
+ "2889500be232ee2fbbc11ef379a96028cd150af0",
+ [
+ null,
+ {}
+ ]
+ ],
"run-operation-in-detached-frame.tentative.https.sub.html": [
"a7ef103d00fe8f707043be171acfc4d206fee749",
[
@@ -750416,6 +753148,13 @@
null,
{}
]
+ ],
+ "web-locks.tentative.https.sub.html": [
+ "49a039368a36322f0f0579015695aee15798529d",
+ [
+ null,
+ {}
+ ]
]
},
"shared-storage-selecturl-limit": {
@@ -754636,13 +757375,6 @@
}
]
],
- "quotachange-in-detached-iframe.tentative.https.html": [
- "123af50e3ce6a3f98756d0377a166dbecfa146fe",
- [
- null,
- {}
- ]
- ],
"storagemanager-estimate.https.any.js": [
"3b6f4d8edc4c2e51d6e9efbc2a2929e75d6b6725",
[
@@ -765376,7 +768108,7 @@
]
],
"block-string-assignment-to-Element-insertAdjacentHTML.html": [
- "e4fec3a8a70dbfbdb92668a8b84395163557d0b1",
+ "af1f982e5a1fa562be28f33783fa076467b389b0",
[
null,
{}
@@ -765674,7 +768406,7 @@
]
],
"trusted-types-navigation.html": [
- "2113711902ae787cb3ad5d0e44eaed0fc2e99b87",
+ "74a25fa3480c3779da87705812e26a3043edd2bc",
[
null,
{}
@@ -772783,6 +775515,118 @@
]
]
},
+ "jspi": {
+ "js-promise-integration.any.js": [
+ "19de3146f921f600046f68014290a9ef607e0a7f",
+ [
+ null,
+ {
+ "jsshell": true,
+ "script_metadata": [
+ [
+ "global",
+ "window,dedicatedworker,jsshell"
+ ],
+ [
+ "script",
+ "/wasm/jsapi/wasm-module-builder.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "wasm/jsapi/jspi/js-promise-integration.any.html",
+ {
+ "script_metadata": [
+ [
+ "global",
+ "window,dedicatedworker,jsshell"
+ ],
+ [
+ "script",
+ "/wasm/jsapi/wasm-module-builder.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "wasm/jsapi/jspi/js-promise-integration.any.worker.html",
+ {
+ "script_metadata": [
+ [
+ "global",
+ "window,dedicatedworker,jsshell"
+ ],
+ [
+ "script",
+ "/wasm/jsapi/wasm-module-builder.js"
+ ]
+ ]
+ }
+ ]
+ ],
+ "rejects.any.js": [
+ "3ec3b90592a2a829a226d8f5bdd0e84538fcdcca",
+ [
+ null,
+ {
+ "jsshell": true,
+ "script_metadata": [
+ [
+ "global",
+ "window,dedicatedworker,jsshell"
+ ],
+ [
+ "script",
+ "/wasm/jsapi/wasm-module-builder.js"
+ ],
+ [
+ "script",
+ "/wasm/jsapi/jspi/testharness-additions.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "wasm/jsapi/jspi/rejects.any.html",
+ {
+ "script_metadata": [
+ [
+ "global",
+ "window,dedicatedworker,jsshell"
+ ],
+ [
+ "script",
+ "/wasm/jsapi/wasm-module-builder.js"
+ ],
+ [
+ "script",
+ "/wasm/jsapi/jspi/testharness-additions.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "wasm/jsapi/jspi/rejects.any.worker.html",
+ {
+ "script_metadata": [
+ [
+ "global",
+ "window,dedicatedworker,jsshell"
+ ],
+ [
+ "script",
+ "/wasm/jsapi/wasm-module-builder.js"
+ ],
+ [
+ "script",
+ "/wasm/jsapi/jspi/testharness-additions.js"
+ ]
+ ]
+ }
+ ]
+ ]
+ },
"memory": {
"buffer.any.js": [
"fb1d1200b892be1eb7aea66db343db491e921a8d",
@@ -778262,6 +781106,15 @@
}
]
],
+ "test-analyser-resume-after-suspended.html": [
+ "82b17faa5a262c2b0e5d77310c5355754168aa26",
+ [
+ null,
+ {
+ "timeout": "long"
+ }
+ ]
+ ],
"test-analyser-scale.html": [
"904b14bede544ac63a08dc422df63fb59d53c048",
[
@@ -778551,7 +781404,7 @@
]
],
"processing-after-resume.https.html": [
- "a456f88e186c20b58856fdec2beb1493b0657a0d",
+ "e000ab124fefa6f0eea4e5517d04436428c0cd8c",
[
null,
{}
@@ -789847,7 +792700,7 @@
]
],
"byob_readtensor.https.any.js": [
- "b99c8704d236c0f18f006514eb65a64566a3369e",
+ "f43cca0ea4eb7de5cdd3070cf4581bf90c1ae6a2",
[
"webnn/conformance_tests/byob_readtensor.https.any.html?cpu",
{
@@ -792031,7 +794884,7 @@
]
],
"dequantizeLinear.https.any.js": [
- "c6acb042a2462605ae46b3e388a706081ff0670f",
+ "8a04d0e6b8a36f1f4b5e3a0a9b04feec1acf7ab3",
[
"webnn/conformance_tests/dequantizeLinear.https.any.html?cpu",
{
@@ -793783,7 +796636,7 @@
]
],
"gather.https.any.js": [
- "3cdd411ecb3fada629dd458cf51e5916bf1b322c",
+ "17c314137586e44c259292e46b64fd283e2e236f",
[
"webnn/conformance_tests/gather.https.any.html?cpu",
{
@@ -794221,7 +797074,7 @@
]
],
"gatherND.https.any.js": [
- "e8f31d5617b40879853fcd9df31aa1d51cfaf796",
+ "b40507d2dcebd95590a74e0279dea160e513ba5f",
[
"webnn/conformance_tests/gatherND.https.any.html?cpu",
{
@@ -796411,7 +799264,7 @@
]
],
"inputs-are-not-modified.https.any.js": [
- "ffd2d93a557f69798d5e975bad5f0db1f483690d",
+ "730941fbd8b6ec7f61a364b88a68ba84cb33d9b8",
[
"webnn/conformance_tests/inputs-are-not-modified.https.any.html?cpu",
{
@@ -798163,7 +801016,7 @@
]
],
"logical_and.https.any.js": [
- "be379de157c5d0406afd11b3d4ffc68b29676859",
+ "3d46c0b2406c7253ccc18ebc351a1bb5063f7855",
[
"webnn/conformance_tests/logical_and.https.any.html?cpu",
{
@@ -798601,7 +801454,7 @@
]
],
"logical_or.https.any.js": [
- "f5eb21de7295af5a67a516318f0bf02434896e81",
+ "3be3b0090f2435a28b81036c232a90baabbe43b0",
[
"webnn/conformance_tests/logical_or.https.any.html?cpu",
{
@@ -798820,7 +801673,7 @@
]
],
"logical_xor.https.any.js": [
- "b678b04065b2cfa57aaa7f17ebbd61309b57c9b9",
+ "cab96c27237f16e8773b9539e173271d3f335eb0",
[
"webnn/conformance_tests/logical_xor.https.any.html?cpu",
{
@@ -801010,7 +803863,7 @@
]
],
"parallel-dispatch.https.any.js": [
- "dfdf70a6aa46fed4aabc9d9db32f5f4c9912dfee",
+ "4051645771fa0c70531bff2fe4cd7132a20c5d26",
[
"webnn/conformance_tests/parallel-dispatch.https.any.html?cpu",
{
@@ -801886,7 +804739,7 @@
]
],
"quantizeLinear.https.any.js": [
- "0871c881b717b7eae1a8c016a363c4b39b59d63f",
+ "8aa9d7f3bcc407d92762ddbf67be894a7d17c34e",
[
"webnn/conformance_tests/quantizeLinear.https.any.html?cpu",
{
@@ -805170,6 +808023,225 @@
}
]
],
+ "scatterElements.https.any.js": [
+ "561260d47ecf66943cb8c3a463ba3f6dc7c22c06",
+ [
+ "webnn/conformance_tests/scatterElements.https.any.html?cpu",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "test WebNN API scatterElements operation"
+ ],
+ [
+ "global",
+ "window,dedicatedworker"
+ ],
+ [
+ "variant",
+ "?cpu"
+ ],
+ [
+ "variant",
+ "?gpu"
+ ],
+ [
+ "variant",
+ "?npu"
+ ],
+ [
+ "script",
+ "../resources/utils.js"
+ ],
+ [
+ "timeout",
+ "long"
+ ]
+ ],
+ "timeout": "long"
+ }
+ ],
+ [
+ "webnn/conformance_tests/scatterElements.https.any.html?gpu",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "test WebNN API scatterElements operation"
+ ],
+ [
+ "global",
+ "window,dedicatedworker"
+ ],
+ [
+ "variant",
+ "?cpu"
+ ],
+ [
+ "variant",
+ "?gpu"
+ ],
+ [
+ "variant",
+ "?npu"
+ ],
+ [
+ "script",
+ "../resources/utils.js"
+ ],
+ [
+ "timeout",
+ "long"
+ ]
+ ],
+ "timeout": "long"
+ }
+ ],
+ [
+ "webnn/conformance_tests/scatterElements.https.any.html?npu",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "test WebNN API scatterElements operation"
+ ],
+ [
+ "global",
+ "window,dedicatedworker"
+ ],
+ [
+ "variant",
+ "?cpu"
+ ],
+ [
+ "variant",
+ "?gpu"
+ ],
+ [
+ "variant",
+ "?npu"
+ ],
+ [
+ "script",
+ "../resources/utils.js"
+ ],
+ [
+ "timeout",
+ "long"
+ ]
+ ],
+ "timeout": "long"
+ }
+ ],
+ [
+ "webnn/conformance_tests/scatterElements.https.any.worker.html?cpu",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "test WebNN API scatterElements operation"
+ ],
+ [
+ "global",
+ "window,dedicatedworker"
+ ],
+ [
+ "variant",
+ "?cpu"
+ ],
+ [
+ "variant",
+ "?gpu"
+ ],
+ [
+ "variant",
+ "?npu"
+ ],
+ [
+ "script",
+ "../resources/utils.js"
+ ],
+ [
+ "timeout",
+ "long"
+ ]
+ ],
+ "timeout": "long"
+ }
+ ],
+ [
+ "webnn/conformance_tests/scatterElements.https.any.worker.html?gpu",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "test WebNN API scatterElements operation"
+ ],
+ [
+ "global",
+ "window,dedicatedworker"
+ ],
+ [
+ "variant",
+ "?cpu"
+ ],
+ [
+ "variant",
+ "?gpu"
+ ],
+ [
+ "variant",
+ "?npu"
+ ],
+ [
+ "script",
+ "../resources/utils.js"
+ ],
+ [
+ "timeout",
+ "long"
+ ]
+ ],
+ "timeout": "long"
+ }
+ ],
+ [
+ "webnn/conformance_tests/scatterElements.https.any.worker.html?npu",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "test WebNN API scatterElements operation"
+ ],
+ [
+ "global",
+ "window,dedicatedworker"
+ ],
+ [
+ "variant",
+ "?cpu"
+ ],
+ [
+ "variant",
+ "?gpu"
+ ],
+ [
+ "variant",
+ "?npu"
+ ],
+ [
+ "script",
+ "../resources/utils.js"
+ ],
+ [
+ "timeout",
+ "long"
+ ]
+ ],
+ "timeout": "long"
+ }
+ ]
+ ],
"scatterND.https.any.js": [
"002ee3e4914e7a2d4d2c4d68c27743ddd596a9ae",
[
@@ -808237,7 +811309,7 @@
]
],
"tensor.https.any.js": [
- "51905bbaf3c590ee3f5c2e801ae9988c5cb37152",
+ "0bc51614608f514dbb3879fcb0bb468c88af9bb7",
[
"webnn/conformance_tests/tensor.https.any.html?cpu",
{
@@ -810929,7 +814001,7 @@
]
],
"constant.https.any.js": [
- "b9b75e372b0169ca459def7a9152873c78c70bce",
+ "fc0243197dba43d5e53052ebc56cc9ce12f281fb",
[
"webnn/validation_tests/constant.https.any.html?cpu",
{
@@ -812063,7 +815135,7 @@
]
],
"destroyContext.https.any.js": [
- "b4027e23dba0f1d5fe527def8e3fa3a323049ff7",
+ "abed6b09bde43c10e33214129a0df5681d3739c2",
[
"webnn/validation_tests/destroyContext.https.any.html?cpu",
{
@@ -812258,7 +815330,7 @@
]
],
"destroyGraph.https.any.js": [
- "f7eb01eafef7ef57676c8b9d21a5579503da6d8a",
+ "4d883e9f3c3eaf5e28e6936980a8c399d0b537c6",
[
"webnn/validation_tests/destroyGraph.https.any.html?cpu",
{
@@ -815099,7 +818171,7 @@
]
],
"input.https.any.js": [
- "0649c67f086e16beb8665de28210573a55987034",
+ "b5b257d8bb02a2a93bf4af2c86d7944298530fc3",
[
"webnn/validation_tests/input.https.any.html?cpu",
{
@@ -818554,6 +821626,195 @@
}
]
],
+ "scatterElements.https.any.js": [
+ "15551b2bbe5b48bb50813ee02a69b75351aed8ba",
+ [
+ "webnn/validation_tests/scatterElements.https.any.html?cpu",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "validation tests for WebNN API scatterElements operation"
+ ],
+ [
+ "global",
+ "window,dedicatedworker"
+ ],
+ [
+ "variant",
+ "?cpu"
+ ],
+ [
+ "variant",
+ "?gpu"
+ ],
+ [
+ "variant",
+ "?npu"
+ ],
+ [
+ "script",
+ "../resources/utils_validation.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "webnn/validation_tests/scatterElements.https.any.html?gpu",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "validation tests for WebNN API scatterElements operation"
+ ],
+ [
+ "global",
+ "window,dedicatedworker"
+ ],
+ [
+ "variant",
+ "?cpu"
+ ],
+ [
+ "variant",
+ "?gpu"
+ ],
+ [
+ "variant",
+ "?npu"
+ ],
+ [
+ "script",
+ "../resources/utils_validation.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "webnn/validation_tests/scatterElements.https.any.html?npu",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "validation tests for WebNN API scatterElements operation"
+ ],
+ [
+ "global",
+ "window,dedicatedworker"
+ ],
+ [
+ "variant",
+ "?cpu"
+ ],
+ [
+ "variant",
+ "?gpu"
+ ],
+ [
+ "variant",
+ "?npu"
+ ],
+ [
+ "script",
+ "../resources/utils_validation.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "webnn/validation_tests/scatterElements.https.any.worker.html?cpu",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "validation tests for WebNN API scatterElements operation"
+ ],
+ [
+ "global",
+ "window,dedicatedworker"
+ ],
+ [
+ "variant",
+ "?cpu"
+ ],
+ [
+ "variant",
+ "?gpu"
+ ],
+ [
+ "variant",
+ "?npu"
+ ],
+ [
+ "script",
+ "../resources/utils_validation.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "webnn/validation_tests/scatterElements.https.any.worker.html?gpu",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "validation tests for WebNN API scatterElements operation"
+ ],
+ [
+ "global",
+ "window,dedicatedworker"
+ ],
+ [
+ "variant",
+ "?cpu"
+ ],
+ [
+ "variant",
+ "?gpu"
+ ],
+ [
+ "variant",
+ "?npu"
+ ],
+ [
+ "script",
+ "../resources/utils_validation.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "webnn/validation_tests/scatterElements.https.any.worker.html?npu",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "validation tests for WebNN API scatterElements operation"
+ ],
+ [
+ "global",
+ "window,dedicatedworker"
+ ],
+ [
+ "variant",
+ "?cpu"
+ ],
+ [
+ "variant",
+ "?gpu"
+ ],
+ [
+ "variant",
+ "?npu"
+ ],
+ [
+ "script",
+ "../resources/utils_validation.js"
+ ]
+ ]
+ }
+ ]
+ ],
"scatterND.https.any.js": [
"5e28471fffa47aa985bc2d6a681156a029f7661b",
[
@@ -821195,7 +824456,7 @@
]
],
"RTCPeerConnection-getStats-timestamp.https.html": [
- "9345d5838d126beccbe025bf32a45ada5a1d2b89",
+ "af97521901890e0fc7a4511010b44118c3679bfe",
[
null,
{
@@ -821534,6 +824795,13 @@
{}
]
],
+ "RTCRtpEncodingParameters-codec-opus-stereo.https.html": [
+ "49335eada4ff3548fcf9173ea93aef7a52f75955",
+ [
+ null,
+ {}
+ ]
+ ],
"RTCRtpParameters-codec.html": [
"9903776cceb7de610d0aa3d24625d1ee16206aba",
[
@@ -844975,7 +848243,7 @@
]
],
"constructor-submitter-coordinate.html": [
- "992f64b721749b85e6d60ed701883242e8faf0fd",
+ "b7bf128bd1207a7f52327216304794c2fb6d048d",
[
null,
{}
@@ -845215,6 +848483,15 @@
]
}
]
+ ],
+ "submitter-coordinate-value.html": [
+ "69bea0ac3f94f48fec9e201b6eda640870557756",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
]
},
"formdata.html": [
@@ -867842,7 +871119,7 @@
{}
]
],
- "frame.py": [
+ "frame_tentative.py": [
"bab97a31d209f30e0861e7ba768109c717523a4a",
[
null,
@@ -868186,7 +871463,14 @@
]
],
"context.py": [
- "f8074b71b43096ba3965f5c64002c4641fb7f0ac",
+ "2530eedb1b3cbf7b8555e6fbd8fe81c5dc2a30ad",
+ [
+ null,
+ {}
+ ]
+ ],
+ "frame_tentative.py": [
+ "98972d86245c8e5e261b6a2e4b53f454decbb3fb",
[
null,
{}
@@ -868728,7 +872012,7 @@
]
],
"before_request_sent_cached.py": [
- "4177d316c5157fa3b68e7a84dfb64619b18086ee",
+ "a042e7510b4914b4b2f07294eac6e45d1ec8170c",
[
null,
{}
@@ -868971,7 +872255,7 @@
]
],
"response_completed_cached.py": [
- "dac13abf61b9147cb4efa9dd95ac7ab8672e2c30",
+ "0a624dcfaedb72ff9c72a0e67700b9bbfaf258e4",
[
null,
{}
@@ -868987,7 +872271,7 @@
]
],
"response_started_cached.py": [
- "ccb7a97300d90874be06b5a6bed7af989209d828",
+ "db0a2514c9322776d19a9861cf3f905cdf4157f8",
[
null,
{}
diff --git a/tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.js.ini b/tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.js.ini
index 6615fe1a314..4908d521ddc 100644
--- a/tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.js.ini
+++ b/tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.js.ini
@@ -92,6 +92,99 @@
[Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), {name: Ed25519}, false, [sign, sign\])]
expected: FAIL
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), Ed25519, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), Ed25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), Ed25519, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(crv, d, x, kty), Ed25519, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(crv, d, x, kty), Ed25519, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, false, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, false, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, false, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, false, [sign, sign\])]
+ expected: FAIL
+
[okp_importKey_Ed25519.https.any.worker.html]
[Good parameters: Ed25519 bits (spki, buffer(44), {name: Ed25519}, true, [verify\])]
@@ -186,3 +279,96 @@
[Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), {name: Ed25519}, false, [sign, sign\])]
expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), Ed25519, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), Ed25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), Ed25519, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(crv, d, x, kty), Ed25519, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed25519 (jwk, object(crv, d, x, kty), Ed25519, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, false, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, false, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, false, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, false, [sign, sign\])]
+ expected: FAIL
diff --git a/tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_Ed448.https.any.js.ini b/tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_Ed448.https.any.js.ini
index 558ee948191..dae94493d3a 100644
--- a/tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_Ed448.https.any.js.ini
+++ b/tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_Ed448.https.any.js.ini
@@ -92,6 +92,99 @@
[Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), {name: Ed448}, false, [sign, sign\])]
expected: FAIL
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(kty, crv, x), Ed448, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, true, [\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(kty, crv, x), Ed448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(kty, crv, x), Ed448, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (pkcs8, buffer(73), Ed448, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), Ed448, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(crv, d, x, kty), Ed448, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (pkcs8, buffer(73), Ed448, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), Ed448, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(crv, d, x, kty), Ed448, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (pkcs8, buffer(73), Ed448, false, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), Ed448, false, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (pkcs8, buffer(73), Ed448, false, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), Ed448, false, [sign, sign\])]
+ expected: FAIL
+
[okp_importKey_Ed448.https.any.worker.html]
[Good parameters: Ed448 bits (spki, buffer(69), {name: Ed448}, true, [verify\])]
@@ -186,3 +279,96 @@
[Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), {name: Ed448}, false, [sign, sign\])]
expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(kty, crv, x), Ed448, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, true, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, true, [\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(kty, crv, x), Ed448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(kty, crv, x), Ed448, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, true, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (pkcs8, buffer(73), Ed448, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), Ed448, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(crv, d, x, kty), Ed448, true, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (pkcs8, buffer(73), Ed448, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), Ed448, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: Ed448 (jwk, object(crv, d, x, kty), Ed448, true, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, false, [verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (spki, buffer(69), Ed448, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(kty, crv, x), Ed448, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (raw, buffer(57), Ed448, false, [verify, verify\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (pkcs8, buffer(73), Ed448, false, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), Ed448, false, [sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (pkcs8, buffer(73), Ed448, false, [sign, sign\])]
+ expected: FAIL
+
+ [Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), Ed448, false, [sign, sign\])]
+ expected: FAIL
diff --git a/tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.js.ini b/tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.js.ini
index 809f315a565..d396d9eb1ac 100644
--- a/tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.js.ini
+++ b/tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.js.ini
@@ -80,6 +80,87 @@
[Good parameters: X25519 bits (jwk, object(crv, d, x, kty), {name: X25519}, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
expected: FAIL
+ [Good parameters: X25519 bits (spki, buffer(44), X25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(kty, crv, x), X25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(kty, crv, x), X25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (raw, buffer(32), X25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), X25519, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), X25519, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), X25519, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), X25519, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (spki, buffer(44), X25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(kty, crv, x), X25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (raw, buffer(32), X25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, false, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, false, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, false, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, false, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, false, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, false, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
[okp_importKey_X25519.https.any.html]
[Good parameters: X25519 bits (spki, buffer(44), {name: X25519}, true, [\])]
@@ -162,3 +243,84 @@
[Good parameters: X25519 bits (jwk, object(crv, d, x, kty), {name: X25519}, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
expected: FAIL
+
+ [Good parameters: X25519 bits (spki, buffer(44), X25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(kty, crv, x), X25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(kty, crv, x), X25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (raw, buffer(32), X25519, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), X25519, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), X25519, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), X25519, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), X25519, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (spki, buffer(44), X25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(kty, crv, x), X25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (raw, buffer(32), X25519, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, false, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, false, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, false, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, false, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, false, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, false, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (pkcs8, buffer(48), X25519, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X25519 bits (jwk, object(crv, d, x, kty), X25519, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
diff --git a/tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_X448.https.any.js.ini b/tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_X448.https.any.js.ini
index 327e034f189..56f2d119204 100644
--- a/tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_X448.https.any.js.ini
+++ b/tests/wpt/meta/WebCryptoAPI/import_export/okp_importKey_X448.https.any.js.ini
@@ -80,6 +80,87 @@
[Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
expected: FAIL
+ [Good parameters: X448 bits (spki, buffer(68), X448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(kty, crv, x), X448, true, [\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(kty, crv, x), X448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (raw, buffer(56), X448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), X448, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), X448, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), X448, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), X448, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (spki, buffer(68), X448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(kty, crv, x), X448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (raw, buffer(56), X448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, false, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, false, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, false, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, false, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, false, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, false, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
[okp_importKey_X448.https.any.worker.html]
[Good parameters: X448 bits (spki, buffer(68), {name: X448}, true, [\])]
@@ -162,3 +243,84 @@
[Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
expected: FAIL
+
+ [Good parameters: X448 bits (spki, buffer(68), X448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(kty, crv, x), X448, true, [\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(kty, crv, x), X448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (raw, buffer(56), X448, true, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), X448, true, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), X448, true, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), X448, true, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), X448, true, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (spki, buffer(68), X448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(kty, crv, x), X448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (raw, buffer(56), X448, false, [\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, false, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, false, [deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, false, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, false, [deriveBits, deriveKey\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, false, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, false, [deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (pkcs8, buffer(72), X448, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
+
+ [Good parameters: X448 bits (jwk, object(crv, d, x, kty), X448, false, [deriveKey, deriveBits, deriveKey, deriveBits\])]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-color/parsing/color-computed-relative-color.html.ini b/tests/wpt/meta/css/css-color/parsing/color-computed-relative-color.html.ini
index d4e0b6dccc5..70aa2015799 100644
--- a/tests/wpt/meta/css/css-color/parsing/color-computed-relative-color.html.ini
+++ b/tests/wpt/meta/css/css-color/parsing/color-computed-relative-color.html.ini
@@ -3697,3 +3697,9 @@
[Property background-color value 'hsl(from currentColor calc((h / 360) * 360deg) s l)']
expected: FAIL
+
+ [Property color value 'light-dark(rgb(from rebeccapurple r g b), rgb(from rebeccapurple r g b))']
+ expected: FAIL
+
+ [Property color value 'light-dark(color-mix(in srgb, rgb(from rebeccapurple none g b), rebeccapurple), color-mix(in srgb, rgb(from rebeccapurple none g b), rebeccapurple))']
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-color/parsing/color-valid-relative-color.html.ini b/tests/wpt/meta/css/css-color/parsing/color-valid-relative-color.html.ini
index 3d655cd0048..380c9a54f3f 100644
--- a/tests/wpt/meta/css/css-color/parsing/color-valid-relative-color.html.ini
+++ b/tests/wpt/meta/css/css-color/parsing/color-valid-relative-color.html.ini
@@ -3724,3 +3724,6 @@
[e.style['color'\] = "color(from color-mix(in xyz-d65, color(xyz-d65 0.7 0.5 0.3), color(xyz-d65 0.7 0.5 0.3)) xyz-d65 x y z / alpha)" should set the property value]
expected: FAIL
+
+ [e.style['color'\] = "oklch(from red calc(1 / l) c h)" should set the property value]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/at-container-overflowing-parsing.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-overflowing-parsing.html.ini
index 72f4601118a..72f4601118a 100644
--- a/tests/wpt/meta/css/css-conditional/container-queries/at-container-overflowing-parsing.html.ini
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-overflowing-parsing.html.ini
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/at-container-overflowing-serialization.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-overflowing-serialization.html.ini
index 18c1abafcc7..18c1abafcc7 100644
--- a/tests/wpt/meta/css/css-conditional/container-queries/at-container-overflowing-serialization.html.ini
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-overflowing-serialization.html.ini
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/at-container-snapped-parsing.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-snapped-parsing.html.ini
index 6ad6378fe26..6ad6378fe26 100644
--- a/tests/wpt/meta/css/css-conditional/container-queries/at-container-snapped-parsing.html.ini
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-snapped-parsing.html.ini
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/at-container-snapped-serialization.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-snapped-serialization.html.ini
index 35c90640507..35c90640507 100644
--- a/tests/wpt/meta/css/css-conditional/container-queries/at-container-snapped-serialization.html.ini
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-snapped-serialization.html.ini
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/at-container-stuck-parsing.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-stuck-parsing.html.ini
index 849d4af452a..849d4af452a 100644
--- a/tests/wpt/meta/css/css-conditional/container-queries/at-container-stuck-parsing.html.ini
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-stuck-parsing.html.ini
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/at-container-stuck-serialization.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-stuck-serialization.html.ini
index 95ca2e600cb..95ca2e600cb 100644
--- a/tests/wpt/meta/css/css-conditional/container-queries/at-container-stuck-serialization.html.ini
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/at-container-stuck-serialization.html.ini
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/container-type-scroll-state-computed.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-computed.html.ini
index bf71bdf192b..bf71bdf192b 100644
--- a/tests/wpt/meta/css/css-conditional/container-queries/container-type-scroll-state-computed.html.ini
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-computed.html.ini
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/container-type-scroll-state-containment.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-containment.html.ini
index 6816d82fe23..6816d82fe23 100644
--- a/tests/wpt/meta/css/css-conditional/container-queries/container-type-scroll-state-containment.html.ini
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-containment.html.ini
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/container-type-scroll-state-parsing.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-parsing.html.ini
index 77be49bdc31..77be49bdc31 100644
--- a/tests/wpt/meta/css/css-conditional/container-queries/container-type-scroll-state-parsing.html.ini
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-parsing.html.ini
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/scroll-state-initially-snapped.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-initially-snapped.html.ini
index 0b354083d7a..0b354083d7a 100644
--- a/tests/wpt/meta/css/css-conditional/container-queries/scroll-state-initially-snapped.html.ini
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-initially-snapped.html.ini
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/scroll-state-initially-stuck.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-initially-stuck.html.ini
index 7260020fd97..7260020fd97 100644
--- a/tests/wpt/meta/css/css-conditional/container-queries/scroll-state-initially-stuck.html.ini
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-initially-stuck.html.ini
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/scroll-state-snapped-change.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-change.html.ini
index 346d353eab5..346d353eab5 100644
--- a/tests/wpt/meta/css/css-conditional/container-queries/scroll-state-snapped-change.html.ini
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-change.html.ini
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/scroll-state-snapped-container-type-change.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-container-type-change.html.ini
index a1cd47a47cc..a1cd47a47cc 100644
--- a/tests/wpt/meta/css/css-conditional/container-queries/scroll-state-snapped-container-type-change.html.ini
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-container-type-change.html.ini
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/scroll-state-snapped-none.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-none.html.ini
index e5d314021fb..e5d314021fb 100644
--- a/tests/wpt/meta/css/css-conditional/container-queries/scroll-state-snapped-none.html.ini
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-none.html.ini
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/scroll-state-snapped-wm.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-wm.html.ini
index a91d853ebd3..a91d853ebd3 100644
--- a/tests/wpt/meta/css/css-conditional/container-queries/scroll-state-snapped-wm.html.ini
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-wm.html.ini
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-container-type-change.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-container-type-change.html.ini
new file mode 100644
index 00000000000..f0b3a1e7a8a
--- /dev/null
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-container-type-change.html.ini
@@ -0,0 +1,2 @@
+[scroll-state-stuck-container-type-change.html]
+ expected: ERROR
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-writing-direction.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-writing-direction.html.ini
new file mode 100644
index 00000000000..3caa58f120b
--- /dev/null
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-writing-direction.html.ini
@@ -0,0 +1,2 @@
+[scroll-state-stuck-writing-direction.html]
+ expected: ERROR
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/scroll-state-target-query-change.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-target-query-change.html.ini
index 8125d4e9608..8125d4e9608 100644
--- a/tests/wpt/meta/css/css-conditional/container-queries/scroll-state-target-query-change.html.ini
+++ b/tests/wpt/meta/css/css-conditional/container-queries/scroll-state/scroll-state-target-query-change.html.ini
diff --git a/tests/wpt/meta/css/css-conditional/container-queries/size-container-writing-mode-change.html.ini b/tests/wpt/meta/css/css-conditional/container-queries/size-container-writing-mode-change.html.ini
new file mode 100644
index 00000000000..7e0cf86879c
--- /dev/null
+++ b/tests/wpt/meta/css/css-conditional/container-queries/size-container-writing-mode-change.html.ini
@@ -0,0 +1,2 @@
+[size-container-writing-mode-change.html]
+ expected: ERROR
diff --git a/tests/wpt/meta/css/css-overflow/line-clamp/webkit-line-clamp-050.html.ini b/tests/wpt/meta/css/css-overflow/line-clamp/webkit-line-clamp-050.html.ini
new file mode 100644
index 00000000000..9a1676cf418
--- /dev/null
+++ b/tests/wpt/meta/css/css-overflow/line-clamp/webkit-line-clamp-050.html.ini
@@ -0,0 +1,2 @@
+[webkit-line-clamp-050.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-pseudo/first-line-below-float.html.ini b/tests/wpt/meta/css/css-pseudo/first-line-below-float.html.ini
new file mode 100644
index 00000000000..077242949df
--- /dev/null
+++ b/tests/wpt/meta/css/css-pseudo/first-line-below-float.html.ini
@@ -0,0 +1,2 @@
+[first-line-below-float.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-pseudo/parsing/the-check-pseudo-element.tentative.html.ini b/tests/wpt/meta/css/css-pseudo/parsing/the-check-pseudo-element.tentative.html.ini
new file mode 100644
index 00000000000..e06425a5209
--- /dev/null
+++ b/tests/wpt/meta/css/css-pseudo/parsing/the-check-pseudo-element.tentative.html.ini
@@ -0,0 +1,18 @@
+[the-check-pseudo-element.tentative.html]
+ ["::check" should be a valid selector]
+ expected: FAIL
+
+ ["*::check" should be a valid selector]
+ expected: FAIL
+
+ ["foo.bar[baz\]::check" should be a valid selector]
+ expected: FAIL
+
+ ["::check::marker" should be a valid selector]
+ expected: FAIL
+
+ ["::slotted(*)::check" should be a valid selector]
+ expected: FAIL
+
+ ["::part(foo)::check" should be a valid selector]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-sizing/animation/height-interpolation.html.ini b/tests/wpt/meta/css/css-sizing/animation/height-interpolation.html.ini
index 88ff05eb181..1797743c462 100644
--- a/tests/wpt/meta/css/css-sizing/animation/height-interpolation.html.ini
+++ b/tests/wpt/meta/css/css-sizing/animation/height-interpolation.html.ini
@@ -496,3 +496,27 @@
[CSS Transitions with transition-property:all and transition-behavor:allow-discrete: property <height> from [max-content\] to [stretch\] at (0.3) should be [max-content\]]
expected: FAIL
+
+ [CSS Animations: property <height> from neutral to [100px\] at (0.5) should be [100px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from neutral to [100px\] at (0.6) should be [100px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from neutral to [100px\] at (1) should be [100px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from neutral to [100px\] at (1.5) should be [100px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from neutral to [100px\] at (0.5) should be [100px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from neutral to [100px\] at (0.6) should be [100px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from neutral to [100px\] at (1) should be [100px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from neutral to [100px\] at (1.5) should be [100px\]]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-sizing/stretch/abspos-1.html.ini b/tests/wpt/meta/css/css-sizing/stretch/abspos-1.html.ini
new file mode 100644
index 00000000000..c57e026f684
--- /dev/null
+++ b/tests/wpt/meta/css/css-sizing/stretch/abspos-1.html.ini
@@ -0,0 +1,2 @@
+[abspos-1.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-sizing/stretch/abspos-2.html.ini b/tests/wpt/meta/css/css-sizing/stretch/abspos-2.html.ini
new file mode 100644
index 00000000000..c5dc50ec598
--- /dev/null
+++ b/tests/wpt/meta/css/css-sizing/stretch/abspos-2.html.ini
@@ -0,0 +1,2 @@
+[abspos-2.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-sizing/stretch/block-height-1.html.ini b/tests/wpt/meta/css/css-sizing/stretch/block-height-1.html.ini
new file mode 100644
index 00000000000..51f953f5c6a
--- /dev/null
+++ b/tests/wpt/meta/css/css-sizing/stretch/block-height-1.html.ini
@@ -0,0 +1,27 @@
+[block-height-1.html]
+ [[data-expected-height\] 1]
+ expected: FAIL
+
+ [[data-expected-height\] 2]
+ expected: FAIL
+
+ [[data-expected-height\] 3]
+ expected: FAIL
+
+ [[data-expected-height\] 7]
+ expected: FAIL
+
+ [[data-expected-height\] 8]
+ expected: FAIL
+
+ [[data-expected-height\] 9]
+ expected: FAIL
+
+ [[data-expected-height\] 13]
+ expected: FAIL
+
+ [[data-expected-height\] 14]
+ expected: FAIL
+
+ [[data-expected-height\] 15]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-sizing/stretch/block-height-2.html.ini b/tests/wpt/meta/css/css-sizing/stretch/block-height-2.html.ini
new file mode 100644
index 00000000000..9b6449c79e3
--- /dev/null
+++ b/tests/wpt/meta/css/css-sizing/stretch/block-height-2.html.ini
@@ -0,0 +1,6 @@
+[block-height-2.html]
+ [[data-expected-height\] 1]
+ expected: FAIL
+
+ [[data-expected-height\] 2]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-sizing/stretch/min-width-1.html.ini b/tests/wpt/meta/css/css-sizing/stretch/min-width-1.html.ini
new file mode 100644
index 00000000000..e3446c9bc89
--- /dev/null
+++ b/tests/wpt/meta/css/css-sizing/stretch/min-width-1.html.ini
@@ -0,0 +1,2 @@
+[min-width-1.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-sizing/stretch/positioned-non-replaced-1.html.ini b/tests/wpt/meta/css/css-sizing/stretch/positioned-non-replaced-1.html.ini
new file mode 100644
index 00000000000..025f23f9b67
--- /dev/null
+++ b/tests/wpt/meta/css/css-sizing/stretch/positioned-non-replaced-1.html.ini
@@ -0,0 +1,2 @@
+[positioned-non-replaced-1.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-sizing/stretch/positioned-replaced-1.html.ini b/tests/wpt/meta/css/css-sizing/stretch/positioned-replaced-1.html.ini
new file mode 100644
index 00000000000..062731ceee4
--- /dev/null
+++ b/tests/wpt/meta/css/css-sizing/stretch/positioned-replaced-1.html.ini
@@ -0,0 +1,2 @@
+[positioned-replaced-1.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-ui/text-overflow-ellipsis-multiline-001.html.ini b/tests/wpt/meta/css/css-ui/text-overflow-ellipsis-multiline-001.html.ini
new file mode 100644
index 00000000000..6f62710f6d1
--- /dev/null
+++ b/tests/wpt/meta/css/css-ui/text-overflow-ellipsis-multiline-001.html.ini
@@ -0,0 +1,2 @@
+[text-overflow-ellipsis-multiline-001.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/calc-serialization-002.html.ini b/tests/wpt/meta/css/css-values/calc-serialization-002.html.ini
new file mode 100644
index 00000000000..e933384770c
--- /dev/null
+++ b/tests/wpt/meta/css/css-values/calc-serialization-002.html.ini
@@ -0,0 +1,3 @@
+[calc-serialization-002.html]
+ [testing calc((min(10px, 20%) + max(1rem, 2%)) * 2)]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/calc-size/animation/calc-size-height-interpolation.html.ini b/tests/wpt/meta/css/css-values/calc-size/animation/calc-size-height-interpolation.html.ini
index 1ff5d2a7b72..a0f3ecf08a5 100644
--- a/tests/wpt/meta/css/css-values/calc-size/animation/calc-size-height-interpolation.html.ini
+++ b/tests/wpt/meta/css/css-values/calc-size/animation/calc-size-height-interpolation.html.ini
@@ -3796,3 +3796,123 @@
[Web Animations: property <height> from [calc-size(50px, size)\] to [calc-size(min-content, size)\] at (1) should be [100px\]]
expected: FAIL
+
+ [CSS Transitions: property <height> from [auto\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [auto\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [auto\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [auto\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [calc-size(any, 50px)\] to [calc-size(auto, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [calc-size(any, 50px)\] to [calc-size(auto, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(auto, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(auto, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [min-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [min-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [min-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [min-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [calc-size(any, 50px)\] to [calc-size(min-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [calc-size(any, 50px)\] to [calc-size(min-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(min-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(min-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [fit-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [fit-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [fit-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [fit-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [calc-size(any, 50px)\] to [calc-size(fit-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [calc-size(any, 50px)\] to [calc-size(fit-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(fit-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(fit-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [max-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [max-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [max-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [max-content\] to [calc-size(any, 50px)\] at (1.1) should be [45.00000000000001px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [calc-size(any, 50px)\] to [calc-size(max-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [calc-size(any, 50px)\] to [calc-size(max-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(max-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(max-content, size * 2)\] at (-0.05) should be [42.5px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [stretch\] to [calc-size(any, 50px)\] at (1.1) should be [25.000000000000007px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [stretch\] to [calc-size(any, 50px)\] at (1.1) should be [25.000000000000007px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [stretch\] to [calc-size(any, 50px)\] at (1.1) should be [25.000000000000007px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [stretch\] to [calc-size(any, 50px)\] at (1.1) should be [25.000000000000007px\]]
+ expected: FAIL
+
+ [CSS Transitions: property <height> from [calc-size(any, 50px)\] to [calc-size(stretch, size * 2)\] at (-0.05) should be [22.5px\]]
+ expected: FAIL
+
+ [CSS Transitions with transition: all: property <height> from [calc-size(any, 50px)\] to [calc-size(stretch, size * 2)\] at (-0.05) should be [22.5px\]]
+ expected: FAIL
+
+ [CSS Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(stretch, size * 2)\] at (-0.05) should be [22.5px\]]
+ expected: FAIL
+
+ [Web Animations: property <height> from [calc-size(any, 50px)\] to [calc-size(stretch, size * 2)\] at (-0.05) should be [22.5px\]]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-height-composition.html.ini b/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-height-composition.html.ini
index 96b318a33c0..2fee6654d57 100644
--- a/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-height-composition.html.ini
+++ b/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-height-composition.html.ini
@@ -25,3 +25,12 @@
[Compositing: property <height> underlying [fit-content\] from add [min-content\] to add [200px\] at (1.5) should be [275px\]]
expected: FAIL
+
+ [Compositing: property <height> underlying [fit-content\] from add [min-content\] to add [200px\] at (0.5) should be [250px\]]
+ expected: FAIL
+
+ [Compositing: property <height> underlying [fit-content\] from add [min-content\] to add [200px\] at (1) should be [250px\]]
+ expected: FAIL
+
+ [Compositing: property <height> underlying [fit-content\] from add [min-content\] to add [200px\] at (1.5) should be [250px\]]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-max-height-composition.html.ini b/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-max-height-composition.html.ini
index c480e928296..7b0fbe413b9 100644
--- a/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-max-height-composition.html.ini
+++ b/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-max-height-composition.html.ini
@@ -28,3 +28,33 @@
[Compositing: property <max-height> underlying [fit-content\] from add [min-content\] to add [200px\] at (1.5) should be [calc-size(min-content, 300px + size * -0.5)\]]
expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [100px\] to add [200px\] at (-0.3) should be [calc-size(fit-content, (100px + size) * 1.3 + (200px + size) * -0.3)\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [100px\] to add [200px\] at (0) should be [calc-size(fit-content, (100px + size) * 1 + (200px + size) * 0)\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [100px\] to add [200px\] at (0.5) should be [calc-size(fit-content, (100px + size) * 0.5 + (200px + size) * 0.5)\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [100px\] to add [200px\] at (1) should be [calc-size(fit-content, (100px + size) * 0 + (200px + size) * 1)\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [100px\] to add [200px\] at (1.5) should be [calc-size(fit-content, (100px + size) * -0.5 + (200px + size) * 1.5)\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [min-content\] to add [200px\] at (-0.3) should be [min-content\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [min-content\] to add [200px\] at (0) should be [min-content\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [min-content\] to add [200px\] at (0.5) should be [calc-size(fit-content, 200px + size)\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [min-content\] to add [200px\] at (1) should be [calc-size(fit-content, 200px + size)\]]
+ expected: FAIL
+
+ [Compositing: property <max-height> underlying [fit-content\] from add [min-content\] to add [200px\] at (1.5) should be [calc-size(fit-content, 200px + size)\]]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-max-width-composition.html.ini b/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-max-width-composition.html.ini
index 3a8389477a1..c8802fc001d 100644
--- a/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-max-width-composition.html.ini
+++ b/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-max-width-composition.html.ini
@@ -43,3 +43,33 @@
[Compositing: property <max-width> underlying [max-content\] from add [100px\] to add [min-content\] at (1.5) should be [calc-size(min-content, -50px + size * 1.5)\]]
expected: FAIL
+
+ [Compositing: property <max-width> underlying [100px\] from add [100px\] to add [fit-content\] at (-0.3) should be [calc-size(fit-content, 260px + (100px + size) * -0.3)\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [100px\] from add [100px\] to add [fit-content\] at (0) should be [calc-size(fit-content, 200px + (100px + size) * 0)\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [100px\] from add [100px\] to add [fit-content\] at (0.5) should be [calc-size(fit-content, 100px + (100px + size) * 0.5)\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [100px\] from add [100px\] to add [fit-content\] at (1) should be [calc-size(fit-content, 0px + (100px + size) * 1)\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [100px\] from add [100px\] to add [fit-content\] at (1.5) should be [calc-size(fit-content, -100px + (100px + size) * 1.5)\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [max-content\] from add [100px\] to add [min-content\] at (-0.3) should be [calc-size(max-content, 100px + size)\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [max-content\] from add [100px\] to add [min-content\] at (0) should be [calc-size(max-content, 100px + size)\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [max-content\] from add [100px\] to add [min-content\] at (0.5) should be [min-content\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [max-content\] from add [100px\] to add [min-content\] at (1) should be [min-content\]]
+ expected: FAIL
+
+ [Compositing: property <max-width> underlying [max-content\] from add [100px\] to add [min-content\] at (1.5) should be [min-content\]]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-min-height-composition.html.ini b/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-min-height-composition.html.ini
index 67c9993b16a..f973fc571e9 100644
--- a/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-min-height-composition.html.ini
+++ b/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-min-height-composition.html.ini
@@ -28,3 +28,33 @@
[Compositing: property <min-height> underlying [fit-content\] from add [200px\] to add [min-content\] at (1.5) should be [calc-size(min-content, -100px + size * 1.5)\]]
expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [100px\] to add [200px\] at (-0.3) should be [calc-size(fit-content, (100px + size) * 1.3 + (200px + size) * -0.3)\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [100px\] to add [200px\] at (0) should be [calc-size(fit-content, (100px + size) * 1 + (200px + size) * 0)\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [100px\] to add [200px\] at (0.5) should be [calc-size(fit-content, (100px + size) * 0.5 + (200px + size) * 0.5)\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [100px\] to add [200px\] at (1) should be [calc-size(fit-content, (100px + size) * 0 + (200px + size) * 1)\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [100px\] to add [200px\] at (1.5) should be [calc-size(fit-content, (100px + size) * -0.5 + (200px + size) * 1.5)\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [200px\] to add [min-content\] at (-0.3) should be [calc-size(fit-content, 200px + size)\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [200px\] to add [min-content\] at (0) should be [calc-size(fit-content, 200px + size)\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [200px\] to add [min-content\] at (0.5) should be [min-content\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [200px\] to add [min-content\] at (1) should be [min-content\]]
+ expected: FAIL
+
+ [Compositing: property <min-height> underlying [fit-content\] from add [200px\] to add [min-content\] at (1.5) should be [min-content\]]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-min-width-composition.html.ini b/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-min-width-composition.html.ini
index ab115e64efe..e3ee8af41b7 100644
--- a/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-min-width-composition.html.ini
+++ b/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-min-width-composition.html.ini
@@ -43,3 +43,33 @@
[Compositing: property <min-width> underlying [max-content\] from add [100px\] to add [min-content\] at (1.5) should be [calc-size(min-content, -50px + size * 1.5)\]]
expected: FAIL
+
+ [Compositing: property <min-width> underlying [100px\] from add [max-content\] to add [100px\] at (-0.3) should be [calc-size(max-content, (100px + size) * 1.3 + -60px)\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [100px\] from add [max-content\] to add [100px\] at (0) should be [calc-size(max-content, (100px + size) * 1 + 0px)\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [100px\] from add [max-content\] to add [100px\] at (0.5) should be [calc-size(max-content, (100px + size) * 0.5 + 100px)\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [100px\] from add [max-content\] to add [100px\] at (1) should be [calc-size(max-content, (100px + size) * 0 + 200px)\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [100px\] from add [max-content\] to add [100px\] at (1.5) should be [calc-size(max-content, (100px + size) * -0.5 + 300px)\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [max-content\] from add [100px\] to add [min-content\] at (-0.3) should be [calc-size(max-content, 100px + size)\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [max-content\] from add [100px\] to add [min-content\] at (0) should be [calc-size(max-content, 100px + size)\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [max-content\] from add [100px\] to add [min-content\] at (0.5) should be [min-content\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [max-content\] from add [100px\] to add [min-content\] at (1) should be [min-content\]]
+ expected: FAIL
+
+ [Compositing: property <min-width> underlying [max-content\] from add [100px\] to add [min-content\] at (1.5) should be [min-content\]]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-width-composition.html.ini b/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-width-composition.html.ini
index 7db347d1dc9..4c55fcb3f11 100644
--- a/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-width-composition.html.ini
+++ b/tests/wpt/meta/css/css-values/calc-size/animation/interpolate-size-width-composition.html.ini
@@ -40,3 +40,9 @@
[Compositing: property <width> underlying [max-content\] from add [100px\] to add [auto\] at (1.5) should be [250px\]]
expected: FAIL
+
+ [Compositing: property <width> underlying [max-content\] from add [200px\] to add [auto\] at (-0.3) should be [300px\]]
+ expected: FAIL
+
+ [Compositing: property <width> underlying [max-content\] from add [200px\] to add [auto\] at (0) should be [300px\]]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/minmax-length-percent-serialize.html.ini b/tests/wpt/meta/css/css-values/minmax-length-percent-serialize.html.ini
index 2028f309e92..0b7996ae56c 100644
--- a/tests/wpt/meta/css/css-values/minmax-length-percent-serialize.html.ini
+++ b/tests/wpt/meta/css/css-values/minmax-length-percent-serialize.html.ini
@@ -4,3 +4,9 @@
['max((min(10%, 30px) + 10px) * 2 + 10px, 5em + 5%)' as a computed value should serialize as 'max(10px + (10px + min(10%, 30px)) * 2, 5% + 80px)'.]
expected: FAIL
+
+ ['max((min(10%, 30px) + 10px) * 2 + 10px, 5em + 5%)' as a specified value should serialize as 'max(10px + (2 * (10px + min(10%, 30px))), 5% + 5em)'.]
+ expected: FAIL
+
+ ['max((min(10%, 30px) + 10px) * 2 + 10px, 5em + 5%)' as a computed value should serialize as 'max(10px + (2 * (10px + min(10%, 30px))), 5% + 80px)'.]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/round-function.html.ini b/tests/wpt/meta/css/css-values/round-function.html.ini
new file mode 100644
index 00000000000..819fbf742db
--- /dev/null
+++ b/tests/wpt/meta/css/css-values/round-function.html.ini
@@ -0,0 +1,3 @@
+[round-function.html]
+ [round(down, (7 - 1) / 3, 1) should be used-value-equivalent to 2]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/cssom-view/MediaQueryList-extends-EventTarget.html.ini b/tests/wpt/meta/css/cssom-view/MediaQueryList-extends-EventTarget.html.ini
deleted file mode 100644
index 23065cc9e36..00000000000
--- a/tests/wpt/meta/css/cssom-view/MediaQueryList-extends-EventTarget.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[MediaQueryList-extends-EventTarget.html]
- [onchange adds listener]
- expected: FAIL
diff --git a/tests/wpt/meta/custom-elements/CustomElementRegistry.html.ini b/tests/wpt/meta/custom-elements/CustomElementRegistry.html.ini
index 94fedb15835..7b862b2d71c 100644
--- a/tests/wpt/meta/custom-elements/CustomElementRegistry.html.ini
+++ b/tests/wpt/meta/custom-elements/CustomElementRegistry.html.ini
@@ -1,3 +1,6 @@
[CustomElementRegistry.html]
[customElements.define must upgrade elements in the shadow-including tree order]
expected: FAIL
+
+ [customElements.define must get "observedAttributes" property on the constructor prototype when "attributeChangedCallback" is present]
+ expected: FAIL
diff --git a/tests/wpt/meta/dom/nodes/moveBefore/tentative/custom-element-move-reactions.html.ini b/tests/wpt/meta/dom/nodes/moveBefore/tentative/custom-element-move-reactions.html.ini
new file mode 100644
index 00000000000..d8b66a385b9
--- /dev/null
+++ b/tests/wpt/meta/dom/nodes/moveBefore/tentative/custom-element-move-reactions.html.ini
@@ -0,0 +1,12 @@
+[custom-element-move-reactions.html]
+ [the disconnected/connected callbacks should be called when no other callback is defined]
+ expected: FAIL
+
+ [the element should stay connected during the callbacks]
+ expected: FAIL
+
+ [When connectedMoveCallback is defined, it is called instead of disconnectedCallback/connectedCallback]
+ expected: FAIL
+
+ [Reactions to atomic move are called in order of element, not in order of operation]
+ expected: FAIL
diff --git a/tests/wpt/meta/encoding/legacy-mb-tchinese/big5/big5-decode-csbig5.html.ini b/tests/wpt/meta/encoding/legacy-mb-tchinese/big5/big5-decode-csbig5.html.ini
deleted file mode 100644
index 1b45084ecc7..00000000000
--- a/tests/wpt/meta/encoding/legacy-mb-tchinese/big5/big5-decode-csbig5.html.ini
+++ /dev/null
@@ -1,29 +0,0 @@
-[big5-decode-csbig5.html?1-1000]
-
-[big5-decode-csbig5.html?5001-6000]
-
-[big5-decode-csbig5.html?4001-5000]
-
-[big5-decode-csbig5.html?6001-7000]
-
-[big5-decode-csbig5.html?3001-4000]
-
-[big5-decode-csbig5.html?11001-12000]
-
-[big5-decode-csbig5.html?14001-last]
-
-[big5-decode-csbig5.html?2001-3000]
-
-[big5-decode-csbig5.html?7001-8000]
-
-[big5-decode-csbig5.html?1001-2000]
-
-[big5-decode-csbig5.html?8001-9000]
-
-[big5-decode-csbig5.html?9001-10000]
-
-[big5-decode-csbig5.html?13001-14000]
-
-[big5-decode-csbig5.html?10001-11000]
-
-[big5-decode-csbig5.html?12001-13000]
diff --git a/tests/wpt/meta/fetch/metadata/generated/css-font-face.https.sub.tentative.html.ini b/tests/wpt/meta/fetch/metadata/generated/css-font-face.https.sub.tentative.html.ini
index 37454f3ed97..4dcac5c96b4 100644
--- a/tests/wpt/meta/fetch/metadata/generated/css-font-face.https.sub.tentative.html.ini
+++ b/tests/wpt/meta/fetch/metadata/generated/css-font-face.https.sub.tentative.html.ini
@@ -46,3 +46,6 @@
[sec-fetch-user]
expected: FAIL
+
+ [sec-fetch-dest]
+ expected: FAIL
diff --git a/tests/wpt/meta/fetch/metadata/generated/css-images.sub.tentative.html.ini b/tests/wpt/meta/fetch/metadata/generated/css-images.sub.tentative.html.ini
index 4b5c3e26586..7b4cf2c5ae7 100644
--- a/tests/wpt/meta/fetch/metadata/generated/css-images.sub.tentative.html.ini
+++ b/tests/wpt/meta/fetch/metadata/generated/css-images.sub.tentative.html.ini
@@ -185,3 +185,6 @@
[border-image sec-fetch-site - HTTPS downgrade (header not sent)]
expected: FAIL
+
+ [background-image sec-fetch-site - HTTPS downgrade (header not sent)]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage.html.ini
new file mode 100644
index 00000000000..a1927668778
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.drawImage.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect.html.ini
new file mode 100644
index 00000000000..ef9c00de33f
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.fillRect.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern.html.ini
new file mode 100644
index 00000000000..62eee6c2c0b
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.pattern.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage.html.ini
new file mode 100644
index 00000000000..39cfa83a2dc
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.drawImage.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect.html.ini
new file mode 100644
index 00000000000..fdb0e9a81f1
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.fillRect.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern.html.ini
new file mode 100644
index 00000000000..146aa84730e
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.pattern.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html.ini
new file mode 100644
index 00000000000..a195925f726
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.drawImage.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html.ini
new file mode 100644
index 00000000000..eb4b6f2408e
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.fillRect.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html.ini
new file mode 100644
index 00000000000..a6edb5e7c8e
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.pattern.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage.html.ini
new file mode 100644
index 00000000000..99c3038f22f
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.drawImage.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect.html.ini
new file mode 100644
index 00000000000..1167fcdd4df
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.fillRect.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern.html.ini
new file mode 100644
index 00000000000..8055e0e6233
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.pattern.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html.ini b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html.ini
index d7226bfed74..0420669cc09 100644
--- a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html.ini
+++ b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html.ini
@@ -1,5 +1,4 @@
[createImageBitmap-origin.sub.html]
- expected: TIMEOUT
[redirected to cross-origin HTMLVideoElement: origin unclear 2dContext.drawImage]
expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/text/2d.text.measure.text-clusters-position.tentative.html.ini b/tests/wpt/meta/html/canvas/element/text/2d.text.measure.text-clusters-position.tentative.html.ini
new file mode 100644
index 00000000000..142f3700afd
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/element/text/2d.text.measure.text-clusters-position.tentative.html.ini
@@ -0,0 +1,3 @@
+[2d.text.measure.text-clusters-position.tentative.html]
+ [Test that TextMetrics::getTextClusters() returns clusters that are positioned according to the target align and baseline passed as options.]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/text/2d.text.measure.text-clusters-range.tentative.html.ini b/tests/wpt/meta/html/canvas/element/text/2d.text.measure.text-clusters-range.tentative.html.ini
new file mode 100644
index 00000000000..ef0e5ba4fbd
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/element/text/2d.text.measure.text-clusters-range.tentative.html.ini
@@ -0,0 +1,3 @@
+[2d.text.measure.text-clusters-range.tentative.html]
+ [Test that getTextClusters() and fillTextCluster() correctly render different ranges of the input text.]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative.html.ini b/tests/wpt/meta/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative.html.ini
new file mode 100644
index 00000000000..034846a0a91
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative.html.ini
@@ -0,0 +1,2 @@
+[2d.text.measure.text-clusters-rendering-align.tentative.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html.ini b/tests/wpt/meta/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html.ini
new file mode 100644
index 00000000000..42e0bb131e5
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html.ini
@@ -0,0 +1,2 @@
+[2d.text.measure.text-clusters-rendering-baseline.tentative.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.html.ini
new file mode 100644
index 00000000000..a1927668778
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.drawImage.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.w.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.w.html.ini
new file mode 100644
index 00000000000..1d2295f3217
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.drawImage.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.worker.js.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.worker.js.ini
new file mode 100644
index 00000000000..b864accf02f
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.worker.js.ini
@@ -0,0 +1,78 @@
+[2d.composite.grid.filter.no_shadow.drawImage.worker.html]
+ [2d]
+ expected: FAIL
+
+ [2d 1]
+ expected: FAIL
+
+ [2d 2]
+ expected: FAIL
+
+ [2d 3]
+ expected: FAIL
+
+ [2d 4]
+ expected: FAIL
+
+ [2d 5]
+ expected: FAIL
+
+ [2d 6]
+ expected: FAIL
+
+ [2d 7]
+ expected: FAIL
+
+ [2d 8]
+ expected: FAIL
+
+ [2d 9]
+ expected: FAIL
+
+ [2d 10]
+ expected: FAIL
+
+ [2d 11]
+ expected: FAIL
+
+ [2d 12]
+ expected: FAIL
+
+ [2d 13]
+ expected: FAIL
+
+ [2d 14]
+ expected: FAIL
+
+ [2d 15]
+ expected: FAIL
+
+ [2d 16]
+ expected: FAIL
+
+ [2d 17]
+ expected: FAIL
+
+ [2d 18]
+ expected: FAIL
+
+ [2d 19]
+ expected: FAIL
+
+ [2d 20]
+ expected: FAIL
+
+ [2d 21]
+ expected: FAIL
+
+ [2d 22]
+ expected: FAIL
+
+ [2d 23]
+ expected: FAIL
+
+ [2d 24]
+ expected: FAIL
+
+ [2d 25]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.html.ini
new file mode 100644
index 00000000000..ef9c00de33f
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.fillRect.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.w.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.w.html.ini
new file mode 100644
index 00000000000..6a6e343494b
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.fillRect.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.worker.js.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.worker.js.ini
new file mode 100644
index 00000000000..0f37ae87455
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.worker.js.ini
@@ -0,0 +1,78 @@
+[2d.composite.grid.filter.no_shadow.fillRect.worker.html]
+ [2d]
+ expected: FAIL
+
+ [2d 1]
+ expected: FAIL
+
+ [2d 2]
+ expected: FAIL
+
+ [2d 3]
+ expected: FAIL
+
+ [2d 4]
+ expected: FAIL
+
+ [2d 5]
+ expected: FAIL
+
+ [2d 6]
+ expected: FAIL
+
+ [2d 7]
+ expected: FAIL
+
+ [2d 8]
+ expected: FAIL
+
+ [2d 9]
+ expected: FAIL
+
+ [2d 10]
+ expected: FAIL
+
+ [2d 11]
+ expected: FAIL
+
+ [2d 12]
+ expected: FAIL
+
+ [2d 13]
+ expected: FAIL
+
+ [2d 14]
+ expected: FAIL
+
+ [2d 15]
+ expected: FAIL
+
+ [2d 16]
+ expected: FAIL
+
+ [2d 17]
+ expected: FAIL
+
+ [2d 18]
+ expected: FAIL
+
+ [2d 19]
+ expected: FAIL
+
+ [2d 20]
+ expected: FAIL
+
+ [2d 21]
+ expected: FAIL
+
+ [2d 22]
+ expected: FAIL
+
+ [2d 23]
+ expected: FAIL
+
+ [2d 24]
+ expected: FAIL
+
+ [2d 25]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.html.ini
new file mode 100644
index 00000000000..62eee6c2c0b
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.pattern.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.w.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.w.html.ini
new file mode 100644
index 00000000000..0902ce494c4
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.no_shadow.pattern.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.worker.js.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.worker.js.ini
new file mode 100644
index 00000000000..47935a7a5d0
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.worker.js.ini
@@ -0,0 +1,78 @@
+[2d.composite.grid.filter.no_shadow.pattern.worker.html]
+ [2d]
+ expected: FAIL
+
+ [2d 1]
+ expected: FAIL
+
+ [2d 2]
+ expected: FAIL
+
+ [2d 3]
+ expected: FAIL
+
+ [2d 4]
+ expected: FAIL
+
+ [2d 5]
+ expected: FAIL
+
+ [2d 6]
+ expected: FAIL
+
+ [2d 7]
+ expected: FAIL
+
+ [2d 8]
+ expected: FAIL
+
+ [2d 9]
+ expected: FAIL
+
+ [2d 10]
+ expected: FAIL
+
+ [2d 11]
+ expected: FAIL
+
+ [2d 12]
+ expected: FAIL
+
+ [2d 13]
+ expected: FAIL
+
+ [2d 14]
+ expected: FAIL
+
+ [2d 15]
+ expected: FAIL
+
+ [2d 16]
+ expected: FAIL
+
+ [2d 17]
+ expected: FAIL
+
+ [2d 18]
+ expected: FAIL
+
+ [2d 19]
+ expected: FAIL
+
+ [2d 20]
+ expected: FAIL
+
+ [2d 21]
+ expected: FAIL
+
+ [2d 22]
+ expected: FAIL
+
+ [2d 23]
+ expected: FAIL
+
+ [2d 24]
+ expected: FAIL
+
+ [2d 25]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.html.ini
new file mode 100644
index 00000000000..39cfa83a2dc
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.drawImage.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.w.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.w.html.ini
new file mode 100644
index 00000000000..2ded60b14cb
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.drawImage.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.worker.js.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.worker.js.ini
new file mode 100644
index 00000000000..f430bd98558
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.worker.js.ini
@@ -0,0 +1,78 @@
+[2d.composite.grid.filter.shadow.drawImage.worker.html]
+ [2d]
+ expected: FAIL
+
+ [2d 1]
+ expected: FAIL
+
+ [2d 2]
+ expected: FAIL
+
+ [2d 3]
+ expected: FAIL
+
+ [2d 4]
+ expected: FAIL
+
+ [2d 5]
+ expected: FAIL
+
+ [2d 6]
+ expected: FAIL
+
+ [2d 7]
+ expected: FAIL
+
+ [2d 8]
+ expected: FAIL
+
+ [2d 9]
+ expected: FAIL
+
+ [2d 10]
+ expected: FAIL
+
+ [2d 11]
+ expected: FAIL
+
+ [2d 12]
+ expected: FAIL
+
+ [2d 13]
+ expected: FAIL
+
+ [2d 14]
+ expected: FAIL
+
+ [2d 15]
+ expected: FAIL
+
+ [2d 16]
+ expected: FAIL
+
+ [2d 17]
+ expected: FAIL
+
+ [2d 18]
+ expected: FAIL
+
+ [2d 19]
+ expected: FAIL
+
+ [2d 20]
+ expected: FAIL
+
+ [2d 21]
+ expected: FAIL
+
+ [2d 22]
+ expected: FAIL
+
+ [2d 23]
+ expected: FAIL
+
+ [2d 24]
+ expected: FAIL
+
+ [2d 25]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.html.ini
new file mode 100644
index 00000000000..fdb0e9a81f1
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.fillRect.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.w.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.w.html.ini
new file mode 100644
index 00000000000..322c7ef3429
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.fillRect.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.worker.js.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.worker.js.ini
new file mode 100644
index 00000000000..958c1fb9bea
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.worker.js.ini
@@ -0,0 +1,78 @@
+[2d.composite.grid.filter.shadow.fillRect.worker.html]
+ [2d]
+ expected: FAIL
+
+ [2d 1]
+ expected: FAIL
+
+ [2d 2]
+ expected: FAIL
+
+ [2d 3]
+ expected: FAIL
+
+ [2d 4]
+ expected: FAIL
+
+ [2d 5]
+ expected: FAIL
+
+ [2d 6]
+ expected: FAIL
+
+ [2d 7]
+ expected: FAIL
+
+ [2d 8]
+ expected: FAIL
+
+ [2d 9]
+ expected: FAIL
+
+ [2d 10]
+ expected: FAIL
+
+ [2d 11]
+ expected: FAIL
+
+ [2d 12]
+ expected: FAIL
+
+ [2d 13]
+ expected: FAIL
+
+ [2d 14]
+ expected: FAIL
+
+ [2d 15]
+ expected: FAIL
+
+ [2d 16]
+ expected: FAIL
+
+ [2d 17]
+ expected: FAIL
+
+ [2d 18]
+ expected: FAIL
+
+ [2d 19]
+ expected: FAIL
+
+ [2d 20]
+ expected: FAIL
+
+ [2d 21]
+ expected: FAIL
+
+ [2d 22]
+ expected: FAIL
+
+ [2d 23]
+ expected: FAIL
+
+ [2d 24]
+ expected: FAIL
+
+ [2d 25]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.html.ini
new file mode 100644
index 00000000000..146aa84730e
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.pattern.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.w.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.w.html.ini
new file mode 100644
index 00000000000..602d69c0f16
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.filter.shadow.pattern.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.worker.js.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.worker.js.ini
new file mode 100644
index 00000000000..79398738220
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.worker.js.ini
@@ -0,0 +1,78 @@
+[2d.composite.grid.filter.shadow.pattern.worker.html]
+ [2d]
+ expected: FAIL
+
+ [2d 1]
+ expected: FAIL
+
+ [2d 2]
+ expected: FAIL
+
+ [2d 3]
+ expected: FAIL
+
+ [2d 4]
+ expected: FAIL
+
+ [2d 5]
+ expected: FAIL
+
+ [2d 6]
+ expected: FAIL
+
+ [2d 7]
+ expected: FAIL
+
+ [2d 8]
+ expected: FAIL
+
+ [2d 9]
+ expected: FAIL
+
+ [2d 10]
+ expected: FAIL
+
+ [2d 11]
+ expected: FAIL
+
+ [2d 12]
+ expected: FAIL
+
+ [2d 13]
+ expected: FAIL
+
+ [2d 14]
+ expected: FAIL
+
+ [2d 15]
+ expected: FAIL
+
+ [2d 16]
+ expected: FAIL
+
+ [2d 17]
+ expected: FAIL
+
+ [2d 18]
+ expected: FAIL
+
+ [2d 19]
+ expected: FAIL
+
+ [2d 20]
+ expected: FAIL
+
+ [2d 21]
+ expected: FAIL
+
+ [2d 22]
+ expected: FAIL
+
+ [2d 23]
+ expected: FAIL
+
+ [2d 24]
+ expected: FAIL
+
+ [2d 25]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html.ini
new file mode 100644
index 00000000000..a195925f726
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.drawImage.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.w.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.w.html.ini
new file mode 100644
index 00000000000..cd15152caf6
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.drawImage.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.worker.js.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.worker.js.ini
new file mode 100644
index 00000000000..92758eb9bd1
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.worker.js.ini
@@ -0,0 +1,78 @@
+[2d.composite.grid.no_filter.no_shadow.drawImage.worker.html]
+ [2d]
+ expected: FAIL
+
+ [2d 1]
+ expected: FAIL
+
+ [2d 2]
+ expected: FAIL
+
+ [2d 3]
+ expected: FAIL
+
+ [2d 4]
+ expected: FAIL
+
+ [2d 5]
+ expected: FAIL
+
+ [2d 6]
+ expected: FAIL
+
+ [2d 7]
+ expected: FAIL
+
+ [2d 8]
+ expected: FAIL
+
+ [2d 9]
+ expected: FAIL
+
+ [2d 10]
+ expected: FAIL
+
+ [2d 11]
+ expected: FAIL
+
+ [2d 12]
+ expected: FAIL
+
+ [2d 13]
+ expected: FAIL
+
+ [2d 14]
+ expected: FAIL
+
+ [2d 15]
+ expected: FAIL
+
+ [2d 16]
+ expected: FAIL
+
+ [2d 17]
+ expected: FAIL
+
+ [2d 18]
+ expected: FAIL
+
+ [2d 19]
+ expected: FAIL
+
+ [2d 20]
+ expected: FAIL
+
+ [2d 21]
+ expected: FAIL
+
+ [2d 22]
+ expected: FAIL
+
+ [2d 23]
+ expected: FAIL
+
+ [2d 24]
+ expected: FAIL
+
+ [2d 25]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html.ini
new file mode 100644
index 00000000000..eb4b6f2408e
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.fillRect.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.w.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.w.html.ini
new file mode 100644
index 00000000000..eec2f16a70d
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.fillRect.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.worker.js.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.worker.js.ini
new file mode 100644
index 00000000000..e619d9eb9ee
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.worker.js.ini
@@ -0,0 +1,78 @@
+[2d.composite.grid.no_filter.no_shadow.fillRect.worker.html]
+ [2d]
+ expected: FAIL
+
+ [2d 1]
+ expected: FAIL
+
+ [2d 2]
+ expected: FAIL
+
+ [2d 3]
+ expected: FAIL
+
+ [2d 4]
+ expected: FAIL
+
+ [2d 5]
+ expected: FAIL
+
+ [2d 6]
+ expected: FAIL
+
+ [2d 7]
+ expected: FAIL
+
+ [2d 8]
+ expected: FAIL
+
+ [2d 9]
+ expected: FAIL
+
+ [2d 10]
+ expected: FAIL
+
+ [2d 11]
+ expected: FAIL
+
+ [2d 12]
+ expected: FAIL
+
+ [2d 13]
+ expected: FAIL
+
+ [2d 14]
+ expected: FAIL
+
+ [2d 15]
+ expected: FAIL
+
+ [2d 16]
+ expected: FAIL
+
+ [2d 17]
+ expected: FAIL
+
+ [2d 18]
+ expected: FAIL
+
+ [2d 19]
+ expected: FAIL
+
+ [2d 20]
+ expected: FAIL
+
+ [2d 21]
+ expected: FAIL
+
+ [2d 22]
+ expected: FAIL
+
+ [2d 23]
+ expected: FAIL
+
+ [2d 24]
+ expected: FAIL
+
+ [2d 25]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html.ini
new file mode 100644
index 00000000000..a6edb5e7c8e
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.pattern.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.w.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.w.html.ini
new file mode 100644
index 00000000000..087fd35298c
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.no_shadow.pattern.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.worker.js.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.worker.js.ini
new file mode 100644
index 00000000000..bee6d9d0775
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.worker.js.ini
@@ -0,0 +1,78 @@
+[2d.composite.grid.no_filter.no_shadow.pattern.worker.html]
+ [2d]
+ expected: FAIL
+
+ [2d 1]
+ expected: FAIL
+
+ [2d 2]
+ expected: FAIL
+
+ [2d 3]
+ expected: FAIL
+
+ [2d 4]
+ expected: FAIL
+
+ [2d 5]
+ expected: FAIL
+
+ [2d 6]
+ expected: FAIL
+
+ [2d 7]
+ expected: FAIL
+
+ [2d 8]
+ expected: FAIL
+
+ [2d 9]
+ expected: FAIL
+
+ [2d 10]
+ expected: FAIL
+
+ [2d 11]
+ expected: FAIL
+
+ [2d 12]
+ expected: FAIL
+
+ [2d 13]
+ expected: FAIL
+
+ [2d 14]
+ expected: FAIL
+
+ [2d 15]
+ expected: FAIL
+
+ [2d 16]
+ expected: FAIL
+
+ [2d 17]
+ expected: FAIL
+
+ [2d 18]
+ expected: FAIL
+
+ [2d 19]
+ expected: FAIL
+
+ [2d 20]
+ expected: FAIL
+
+ [2d 21]
+ expected: FAIL
+
+ [2d 22]
+ expected: FAIL
+
+ [2d 23]
+ expected: FAIL
+
+ [2d 24]
+ expected: FAIL
+
+ [2d 25]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.html.ini
new file mode 100644
index 00000000000..99c3038f22f
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.drawImage.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.w.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.w.html.ini
new file mode 100644
index 00000000000..5b9f81d55a7
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.drawImage.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.worker.js.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.worker.js.ini
new file mode 100644
index 00000000000..a798b37c417
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.worker.js.ini
@@ -0,0 +1,78 @@
+[2d.composite.grid.no_filter.shadow.drawImage.worker.html]
+ [2d]
+ expected: FAIL
+
+ [2d 1]
+ expected: FAIL
+
+ [2d 2]
+ expected: FAIL
+
+ [2d 3]
+ expected: FAIL
+
+ [2d 4]
+ expected: FAIL
+
+ [2d 5]
+ expected: FAIL
+
+ [2d 6]
+ expected: FAIL
+
+ [2d 7]
+ expected: FAIL
+
+ [2d 8]
+ expected: FAIL
+
+ [2d 9]
+ expected: FAIL
+
+ [2d 10]
+ expected: FAIL
+
+ [2d 11]
+ expected: FAIL
+
+ [2d 12]
+ expected: FAIL
+
+ [2d 13]
+ expected: FAIL
+
+ [2d 14]
+ expected: FAIL
+
+ [2d 15]
+ expected: FAIL
+
+ [2d 16]
+ expected: FAIL
+
+ [2d 17]
+ expected: FAIL
+
+ [2d 18]
+ expected: FAIL
+
+ [2d 19]
+ expected: FAIL
+
+ [2d 20]
+ expected: FAIL
+
+ [2d 21]
+ expected: FAIL
+
+ [2d 22]
+ expected: FAIL
+
+ [2d 23]
+ expected: FAIL
+
+ [2d 24]
+ expected: FAIL
+
+ [2d 25]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.html.ini
new file mode 100644
index 00000000000..1167fcdd4df
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.fillRect.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.w.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.w.html.ini
new file mode 100644
index 00000000000..d56ee6bbf95
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.fillRect.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.worker.js.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.worker.js.ini
new file mode 100644
index 00000000000..33a8dc42b8b
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.worker.js.ini
@@ -0,0 +1,78 @@
+[2d.composite.grid.no_filter.shadow.fillRect.worker.html]
+ [2d]
+ expected: FAIL
+
+ [2d 1]
+ expected: FAIL
+
+ [2d 2]
+ expected: FAIL
+
+ [2d 3]
+ expected: FAIL
+
+ [2d 4]
+ expected: FAIL
+
+ [2d 5]
+ expected: FAIL
+
+ [2d 6]
+ expected: FAIL
+
+ [2d 7]
+ expected: FAIL
+
+ [2d 8]
+ expected: FAIL
+
+ [2d 9]
+ expected: FAIL
+
+ [2d 10]
+ expected: FAIL
+
+ [2d 11]
+ expected: FAIL
+
+ [2d 12]
+ expected: FAIL
+
+ [2d 13]
+ expected: FAIL
+
+ [2d 14]
+ expected: FAIL
+
+ [2d 15]
+ expected: FAIL
+
+ [2d 16]
+ expected: FAIL
+
+ [2d 17]
+ expected: FAIL
+
+ [2d 18]
+ expected: FAIL
+
+ [2d 19]
+ expected: FAIL
+
+ [2d 20]
+ expected: FAIL
+
+ [2d 21]
+ expected: FAIL
+
+ [2d 22]
+ expected: FAIL
+
+ [2d 23]
+ expected: FAIL
+
+ [2d 24]
+ expected: FAIL
+
+ [2d 25]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.html.ini
new file mode 100644
index 00000000000..8055e0e6233
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.pattern.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.w.html.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.w.html.ini
new file mode 100644
index 00000000000..8108a9bc658
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.w.html.ini
@@ -0,0 +1,2 @@
+[2d.composite.grid.no_filter.shadow.pattern.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.worker.js.ini b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.worker.js.ini
new file mode 100644
index 00000000000..b5d883b658d
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.worker.js.ini
@@ -0,0 +1,78 @@
+[2d.composite.grid.no_filter.shadow.pattern.worker.html]
+ [2d]
+ expected: FAIL
+
+ [2d 1]
+ expected: FAIL
+
+ [2d 2]
+ expected: FAIL
+
+ [2d 3]
+ expected: FAIL
+
+ [2d 4]
+ expected: FAIL
+
+ [2d 5]
+ expected: FAIL
+
+ [2d 6]
+ expected: FAIL
+
+ [2d 7]
+ expected: FAIL
+
+ [2d 8]
+ expected: FAIL
+
+ [2d 9]
+ expected: FAIL
+
+ [2d 10]
+ expected: FAIL
+
+ [2d 11]
+ expected: FAIL
+
+ [2d 12]
+ expected: FAIL
+
+ [2d 13]
+ expected: FAIL
+
+ [2d 14]
+ expected: FAIL
+
+ [2d 15]
+ expected: FAIL
+
+ [2d 16]
+ expected: FAIL
+
+ [2d 17]
+ expected: FAIL
+
+ [2d 18]
+ expected: FAIL
+
+ [2d 19]
+ expected: FAIL
+
+ [2d 20]
+ expected: FAIL
+
+ [2d 21]
+ expected: FAIL
+
+ [2d 22]
+ expected: FAIL
+
+ [2d 23]
+ expected: FAIL
+
+ [2d 24]
+ expected: FAIL
+
+ [2d 25]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.html.ini b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.html.ini
new file mode 100644
index 00000000000..142f3700afd
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.html.ini
@@ -0,0 +1,3 @@
+[2d.text.measure.text-clusters-position.tentative.html]
+ [Test that TextMetrics::getTextClusters() returns clusters that are positioned according to the target align and baseline passed as options.]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.worker.js.ini b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.worker.js.ini
new file mode 100644
index 00000000000..4cc1c748611
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.worker.js.ini
@@ -0,0 +1,3 @@
+[2d.text.measure.text-clusters-position.tentative.worker.html]
+ [Test that TextMetrics::getTextClusters() returns clusters that are positioned according to the target align and baseline passed as options.]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.html.ini b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.html.ini
new file mode 100644
index 00000000000..ef0e5ba4fbd
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.html.ini
@@ -0,0 +1,3 @@
+[2d.text.measure.text-clusters-range.tentative.html]
+ [Test that getTextClusters() and fillTextCluster() correctly render different ranges of the input text.]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.worker.js.ini b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.worker.js.ini
new file mode 100644
index 00000000000..ca35bd126f7
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.worker.js.ini
@@ -0,0 +1,3 @@
+[2d.text.measure.text-clusters-range.tentative.worker.html]
+ [Test that getTextClusters() and fillTextCluster() correctly render different ranges of the input text.]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.html.ini b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.html.ini
new file mode 100644
index 00000000000..034846a0a91
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.html.ini
@@ -0,0 +1,2 @@
+[2d.text.measure.text-clusters-rendering-align.tentative.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.w.html.ini b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.w.html.ini
new file mode 100644
index 00000000000..16b4355c27f
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.w.html.ini
@@ -0,0 +1,2 @@
+[2d.text.measure.text-clusters-rendering-align.tentative.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html.ini b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html.ini
new file mode 100644
index 00000000000..42e0bb131e5
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html.ini
@@ -0,0 +1,2 @@
+[2d.text.measure.text-clusters-rendering-baseline.tentative.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.w.html.ini b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.w.html.ini
new file mode 100644
index 00000000000..3d7dd3b6b3a
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.w.html.ini
@@ -0,0 +1,2 @@
+[2d.text.measure.text-clusters-rendering-baseline.tentative.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative.w.html.ini b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative.w.html.ini
new file mode 100644
index 00000000000..2150f92957f
--- /dev/null
+++ b/tests/wpt/meta/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative.w.html.ini
@@ -0,0 +1,2 @@
+[2d.text.measure.text-clusters-rendering-font-change.tentative.w.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/dom/elements/the-innertext-and-outertext-properties/innertext-whitespace-pre-line.html.ini b/tests/wpt/meta/html/dom/elements/the-innertext-and-outertext-properties/innertext-whitespace-pre-line.html.ini
new file mode 100644
index 00000000000..5ce7adc27b8
--- /dev/null
+++ b/tests/wpt/meta/html/dom/elements/the-innertext-and-outertext-properties/innertext-whitespace-pre-line.html.ini
@@ -0,0 +1,3 @@
+[innertext-whitespace-pre-line.html]
+ [innerText has collapsed whitespace but preserved newlines with pre-line]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini
index d7d0d3ef89d..f455bb20528 100644
--- a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini
+++ b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini
@@ -1,4 +1,4 @@
[iframe_sandbox_popups_escaping-1.html]
- expected: TIMEOUT
+ expected: CRASH
[Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
expected: FAIL
diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini
index 96d866bf3cc..e8872b3585b 100644
--- a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini
+++ b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini
@@ -1,4 +1,4 @@
[iframe_sandbox_popups_nonescaping-1.html]
expected: TIMEOUT
[Check that popups from a sandboxed iframe do not escape the sandbox]
- expected: FAIL
+ expected: NOTRUN
diff --git a/tests/wpt/meta/html/semantics/forms/form-submission-0/reparent-form-during-planned-navigation-task.html.ini b/tests/wpt/meta/html/semantics/forms/form-submission-0/reparent-form-during-planned-navigation-task.html.ini
new file mode 100644
index 00000000000..7682a4830bf
--- /dev/null
+++ b/tests/wpt/meta/html/semantics/forms/form-submission-0/reparent-form-during-planned-navigation-task.html.ini
@@ -0,0 +1,4 @@
+[reparent-form-during-planned-navigation-task.html]
+ expected: TIMEOUT
+ [reparent-form-during-planned-navigation-task]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html.ini b/tests/wpt/meta/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html.ini
index 19b3d41fe42..373ba604823 100644
--- a/tests/wpt/meta/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html.ini
+++ b/tests/wpt/meta/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html.ini
@@ -16,3 +16,6 @@
[Divs and imgs should be allowed as direct children of select and within options without a datalist.]
expected: FAIL
+
+ [Input tags should parse inside select instead of closing the select.]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html.ini b/tests/wpt/meta/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html.ini
index f7b6c87f9c5..d566064c0e0 100644
--- a/tests/wpt/meta/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html.ini
+++ b/tests/wpt/meta/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html.ini
@@ -16,3 +16,18 @@
[dialog.showModal() should coalesce asynchronous toggle events.]
expected: FAIL
+
+ [dialog.show() should not open if beforetoggle removes]
+ expected: FAIL
+
+ [dialog.show() should not open if beforetoggle calls showPopover]
+ expected: FAIL
+
+ [dialog.showModal() should not double-set open/close if beforetoggle re-opens]
+ expected: FAIL
+
+ [dialog.showModal() should not open if beforetoggle removes]
+ expected: FAIL
+
+ [dialog.showModal() should not open if beforetoggle calls showPopover]
+ expected: FAIL
diff --git a/tests/wpt/meta/selection/caret-position-should-be-correct-while-moveup-movedown.html.ini b/tests/wpt/meta/selection/caret-position-should-be-correct-while-moveup-movedown.html.ini
new file mode 100644
index 00000000000..32a129e1440
--- /dev/null
+++ b/tests/wpt/meta/selection/caret-position-should-be-correct-while-moveup-movedown.html.ini
@@ -0,0 +1,72 @@
+[caret-position-should-be-correct-while-moveup-movedown.html]
+ [Caret position should be correct in moving up horizontal div when selection was left to right with line granularity]
+ expected: FAIL
+
+ [Caret position should be correct in moving up horizontal div when selection was right to left with line granularity]
+ expected: FAIL
+
+ [Caret position should be correct in moving down horizontal div when selection was left to right with line granularity]
+ expected: FAIL
+
+ [Caret position should be correct in moving down horizontal div when selection was right to left with line granularity]
+ expected: FAIL
+
+ [Caret position should be correct in moving up horizontal div when selection was left to right with paragraph granularity]
+ expected: FAIL
+
+ [Caret position should be correct in moving up horizontal div when selection was right to left with paragraph granularity]
+ expected: FAIL
+
+ [Caret position should be correct in moving down horizontal div when selection was left to right with paragraph granularity]
+ expected: FAIL
+
+ [Caret position should be correct in moving down horizontal div when selection was right to left with paragraph granularity]
+ expected: FAIL
+
+ [Caret position should be correct in move right with line granularity for vertical-lr div when selection was top to bottom]
+ expected: FAIL
+
+ [Caret position should be correct in move right with line granularity for vertical-lr div when selection was bottom to top]
+ expected: FAIL
+
+ [Caret position should be correct in move left with line granularity for vertical-lr div when selection was top to bottom]
+ expected: FAIL
+
+ [Caret position should be correct in move left with line granularity for vertical-lr div when selection was bottom to top]
+ expected: FAIL
+
+ [Caret position should be correct in move right with paragraph granularity for vertical-lr div when selection was top to bottom]
+ expected: FAIL
+
+ [Caret position should be correct in move right with paragraph granularity for vertical-lr div when selection was bottom to top]
+ expected: FAIL
+
+ [Caret position should be correct in move left with paragraph granularity for vertical-lr div when selection was top to bottom]
+ expected: FAIL
+
+ [Caret position should be correct in move left with paragraph granularity for vertical-lr div when selection was bottom to top]
+ expected: FAIL
+
+ [Caret position should be correct in move left with line granularity for vertical-rl div when selection was top to bottom]
+ expected: FAIL
+
+ [Caret position should be correct in move left with line granularity for vertical-rl div when selection was bottom to top]
+ expected: FAIL
+
+ [Caret position should be correct in move right with line granularity for vertical-rl div when selection was top to bottom]
+ expected: FAIL
+
+ [Caret position should be correct in move right with line granularity for vertical-rl div when selection was bottom to top]
+ expected: FAIL
+
+ [Caret position should be correct in move left with paragraph granularity for vertical-rl div when selection was top to bottom]
+ expected: FAIL
+
+ [Caret position should be correct in move left with paragraph granularity for vertical-rl div when selection was bottom to top]
+ expected: FAIL
+
+ [Caret position should be correct in move right with paragraph granularity for vertical-rl div when selection was top to bottom]
+ expected: FAIL
+
+ [Caret position should be correct in move right with paragraph granularity for vertical-rl div when selection was bottom to top]
+ expected: FAIL
diff --git a/tests/wpt/meta/selection/shadow-dom/tentative/Selection-getComposedRanges-dom-mutations-removal.html.ini b/tests/wpt/meta/selection/shadow-dom/tentative/Selection-getComposedRanges-dom-mutations-removal.html.ini
new file mode 100644
index 00000000000..f257677237d
--- /dev/null
+++ b/tests/wpt/meta/selection/shadow-dom/tentative/Selection-getComposedRanges-dom-mutations-removal.html.ini
@@ -0,0 +1,32 @@
+[Selection-getComposedRanges-dom-mutations-removal.html?mode=open]
+ [Range is fully in shadow tree. Removing shadow host collapses composed StaticRange. Note it does not update previously returned composed StaticRange.]
+ expected: FAIL
+
+ [Range is fully in shadow tree. Removing parent of shadow host collapses composed StaticRange.]
+ expected: FAIL
+
+ [Range is in light DOM. Removing startContainer rescopes new composed range to its parent.]
+ expected: FAIL
+
+ [Range is across shadow trees. Replacing shadowRoot content rescopes new composed range to the shadowRoot.]
+ expected: FAIL
+
+ [Range is between two light slotted contents. Removing start container rescopes to its parent in light tree.]
+ expected: FAIL
+
+
+[Selection-getComposedRanges-dom-mutations-removal.html?mode=closed]
+ [Range is fully in shadow tree. Removing shadow host collapses composed StaticRange. Note it does not update previously returned composed StaticRange.]
+ expected: FAIL
+
+ [Range is fully in shadow tree. Removing parent of shadow host collapses composed StaticRange.]
+ expected: FAIL
+
+ [Range is in light DOM. Removing startContainer rescopes new composed range to its parent.]
+ expected: FAIL
+
+ [Range is across shadow trees. Replacing shadowRoot content rescopes new composed range to the shadowRoot.]
+ expected: FAIL
+
+ [Range is between two light slotted contents. Removing start container rescopes to its parent in light tree.]
+ expected: FAIL
diff --git a/tests/wpt/meta/selection/shadow-dom/tentative/Selection-getComposedRanges-slot.html.ini b/tests/wpt/meta/selection/shadow-dom/tentative/Selection-getComposedRanges-slot.html.ini
new file mode 100644
index 00000000000..97d7f6316fd
--- /dev/null
+++ b/tests/wpt/meta/selection/shadow-dom/tentative/Selection-getComposedRanges-slot.html.ini
@@ -0,0 +1,9 @@
+[Selection-getComposedRanges-slot.html]
+ [Setting the range to start on slotted content and end in shadow tree, should follow DOM tree order.]
+ expected: FAIL
+
+ [Setting the range to start and end on slotted content, should follow DOM tree order.]
+ expected: FAIL
+
+ [Setting the range to start on unslotted content and end in shadow tree, should follow DOM tree order.]
+ expected: FAIL
diff --git a/tests/wpt/meta/url/failure.html.ini b/tests/wpt/meta/url/failure.html.ini
index a3abebff51e..e49fb61f308 100644
--- a/tests/wpt/meta/url/failure.html.ini
+++ b/tests/wpt/meta/url/failure.html.ini
@@ -724,3 +724,6 @@
[Location's href: stun://[:1\] should throw]
expected: FAIL
+
+ [Location's href: non-special://host\\a should throw]
+ expected: FAIL
diff --git a/tests/wpt/meta/wasm/jsapi/jspi/js-promise-integration.any.js.ini b/tests/wpt/meta/wasm/jsapi/jspi/js-promise-integration.any.js.ini
new file mode 100644
index 00000000000..0d5f0447d7e
--- /dev/null
+++ b/tests/wpt/meta/wasm/jsapi/jspi/js-promise-integration.any.js.ini
@@ -0,0 +1,63 @@
+[js-promise-integration.any.worker.html]
+ [Promising function always entered]
+ expected: FAIL
+
+ [Always get a Promise]
+ expected: FAIL
+
+ [Suspend once]
+ expected: FAIL
+
+ [Suspend/resume in a loop]
+ expected: FAIL
+
+ [Suspending with mismatched args and via Proxy]
+ expected: FAIL
+
+ [Make sure we actually suspend]
+ expected: FAIL
+
+ [Do not suspend if the import's return value is not a Promise]
+ expected: FAIL
+
+ [Catch rejected promise]
+ expected: FAIL
+
+ [Promising with no return]
+ expected: FAIL
+
+ [Suspend two modules]
+ expected: FAIL
+
+
+[js-promise-integration.any.html]
+ expected: ERROR
+ [Promising function always entered]
+ expected: FAIL
+
+ [Always get a Promise]
+ expected: FAIL
+
+ [Suspend once]
+ expected: FAIL
+
+ [Suspend/resume in a loop]
+ expected: FAIL
+
+ [Suspending with mismatched args and via Proxy]
+ expected: FAIL
+
+ [Make sure we actually suspend]
+ expected: FAIL
+
+ [Do not suspend if the import's return value is not a Promise]
+ expected: FAIL
+
+ [Catch rejected promise]
+ expected: FAIL
+
+ [Promising with no return]
+ expected: FAIL
+
+ [Suspend two modules]
+ expected: FAIL
diff --git a/tests/wpt/meta/wasm/jsapi/jspi/rejects.any.js.ini b/tests/wpt/meta/wasm/jsapi/jspi/rejects.any.js.ini
new file mode 100644
index 00000000000..5fc1ddb57d1
--- /dev/null
+++ b/tests/wpt/meta/wasm/jsapi/jspi/rejects.any.js.ini
@@ -0,0 +1,32 @@
+[rejects.any.html]
+ [Throw after the first suspension]
+ expected: FAIL
+
+ [Throw before suspending]
+ expected: FAIL
+
+ [Throw and propagate via Promise]
+ expected: FAIL
+
+ [Stack overflow]
+ expected: FAIL
+
+ [Try to suspend JS]
+ expected: FAIL
+
+
+[rejects.any.worker.html]
+ [Throw after the first suspension]
+ expected: FAIL
+
+ [Throw before suspending]
+ expected: FAIL
+
+ [Throw and propagate via Promise]
+ expected: FAIL
+
+ [Stack overflow]
+ expected: FAIL
+
+ [Try to suspend JS]
+ expected: FAIL
diff --git a/tests/wpt/meta/webxr/render_state_update.https.html.ini b/tests/wpt/meta/webxr/render_state_update.https.html.ini
new file mode 100644
index 00000000000..0e57356683e
--- /dev/null
+++ b/tests/wpt/meta/webxr/render_state_update.https.html.ini
@@ -0,0 +1,2 @@
+[render_state_update.https.html]
+ expected: ERROR
diff --git a/tests/wpt/tests/.github/workflows/safari-wptrunner.yml b/tests/wpt/tests/.github/workflows/safari-wptrunner.yml
new file mode 100644
index 00000000000..0860533dc92
--- /dev/null
+++ b/tests/wpt/tests/.github/workflows/safari-wptrunner.yml
@@ -0,0 +1,115 @@
+name: Run Safari Tests
+
+on:
+ workflow_call:
+ inputs:
+ artifact-name:
+ description: "Prefix for the artifact uploaded"
+ required: true
+ type: string
+ safari-technology-preview:
+ description: "Run Safari Technology Preview rather than the system Safari"
+ required: true
+ type: boolean
+ safaridriver-diagnose:
+ description: "Run safaridriver capturing diagnostics"
+ required: true
+ type: boolean
+
+# We never interact with the GitHub API, thus we can simply disable all
+# permissions the GitHub token would have.
+permissions: {}
+
+jobs:
+ safari-results:
+ name: ${{ inputs.safari-technology-preview && 'Safari Technology Preview' || 'Safari' }}
+ runs-on:
+ - self-hosted
+ - webkit-ews
+ timeout-minutes: 180
+ strategy:
+ matrix:
+ current-chunk: [1, 2, 3, 4, 5, 6, 7, 8]
+ total-chunks: [8]
+ steps:
+ - name: checkout
+ uses: actions/checkout@v4.1.0
+ with:
+ fetch-depth: 1
+ - name: Set display color profile
+ run: |-
+ ./wpt macos-color-profile
+ - name: Enable safaridriver diagnostics
+ if: inputs.safaridriver-diagnose
+ run: |-
+ rm -rf ~/Library/Logs/com.apple.WebDriver/
+ defaults write com.apple.WebDriver DiagnosticsEnabled 1
+ - name: Enable safaridriver (Safari)
+ if: ${{ !inputs.safari-technology-preview }}
+ run: |-
+ set -eux -o pipefail
+ sudo safaridriver --enable
+ - name: Enable safaridriver (Safari Technology Preview)
+ if: ${{ inputs.safari-technology-preview }}
+ run: |-
+ set -eux -o pipefail
+ export SYSTEM_VERSION_COMPAT=0
+ ./wpt install --channel preview --download-only -d . --rename STP safari browser
+ sudo installer -pkg STP.pkg -target LocalSystem
+ sudo /Applications/Safari\ Technology\ Preview.app/Contents/MacOS/safaridriver --enable
+ - name: Update hosts
+ run: |-
+ set -eux -o pipefail
+ ./wpt make-hosts-file | sudo tee -a /etc/hosts
+ - name: Update manifest
+ run: ./wpt manifest
+ - name: Run tests
+ run: |-
+ set -eux -o pipefail
+ export SYSTEM_VERSION_COMPAT=0
+ ./wpt run \
+ --no-manifest-update \
+ --no-restart-on-unexpected \
+ --no-fail-on-unexpected \
+ --this-chunk=${{ matrix.current-chunk }} \
+ --total-chunks=${{ matrix.total-chunks }} \
+ --chunk-type hash \
+ --log-wptreport ${{ runner.temp }}/wpt_report_${{ matrix.current-chunk }}.json \
+ --log-wptscreenshot ${{ runner.temp }}/wpt_screenshot_${{ matrix.current-chunk }}.txt \
+ --log-mach - \
+ --log-mach-level info \
+ --channel ${{ inputs.safari-technology-preview && 'preview' || 'stable' }} \
+ --kill-safari \
+ --max-restarts 100 \
+ safari
+ - name: Publish results
+ uses: actions/upload-artifact@v4.1.0
+ with:
+ name: ${{ inputs.artifact-name }}-${{ matrix.current-chunk }}
+ path: |
+ ${{ runner.temp }}/wpt_report_*.json
+ ${{ runner.temp }}/wpt_screenshot_*.txt
+ if-no-files-found: "error"
+ - name: Publish safaridriver logs
+ if: inputs.safaridriver-diagnose
+ uses: actions/upload-artifact@v4.1.0
+ with:
+ name: ${{ inputs.artifact-name }}-safaridriver-logs-${{ matrix.current-chunk }}
+ path: ~/Library/Logs/com.apple.WebDriver/
+ if-no-files-found: warn
+ - name: Disable safaridriver diagnostics
+ if: inputs.safaridriver-diagnose
+ run: |-
+ defaults write com.apple.WebDriver DiagnosticsEnabled 0
+ rm -rf ~/Library/Logs/com.apple.WebDriver/
+ - name: Cleanup
+ if: always()
+ run: |-
+ set -ux
+ sudo sed -i '' '/^# Start web-platform-tests hosts$/,/^# End web-platform-tests hosts$/d' /etc/hosts
+
+ safari-notify:
+ needs: safari-results
+ uses: ./.github/workflows/wpt_fyi_notify.yml
+ with:
+ artifact-name: "${{ inputs.artifact-name }}-*"
diff --git a/tests/wpt/tests/.github/workflows/safari_stable.yml b/tests/wpt/tests/.github/workflows/safari_stable.yml
index 0df13f43d44..7c344fe667f 100644
--- a/tests/wpt/tests/.github/workflows/safari_stable.yml
+++ b/tests/wpt/tests/.github/workflows/safari_stable.yml
@@ -15,12 +15,6 @@ on:
- epochs/daily
- triggers/safari_stable
-env:
- # Set SAFARIDRIVER_DIAGNOSE to true to enable safaridriver diagnostics. The
- # logs won't appear in `./wpt run` output but will be uploaded as an
- # artifact.
- SAFARIDRIVER_DIAGNOSE: false
-
jobs:
check-workflow-run:
name: "Check for appropriate epochs"
@@ -35,81 +29,8 @@ jobs:
needs: check-workflow-run
if: |
github.event_name != 'workflow_run' || fromJSON(needs.check-workflow-run.outputs.updated-refs)[0] != null
- runs-on:
- - self-hosted
- - webkit-ews
- timeout-minutes: 180
- strategy:
- matrix:
- current-chunk: [1, 2, 3, 4, 5, 6, 7, 8]
- total-chunks: [8]
- steps:
- - name: checkout
- uses: actions/checkout@v4.1.0
- with:
- fetch-depth: 1
- - name: Enable safaridriver diagnostics
- if: env.SAFARIDRIVER_DIAGNOSE == true
- run: |-
- rm -rf ~/Library/Logs/com.apple.WebDriver/
- defaults write com.apple.WebDriver DiagnosticsEnabled 1
- - name: Enable safaridriver
- run: |-
- set -eux -o pipefail
- sudo safaridriver --enable
- - name: Update hosts
- run: |-
- set -eux -o pipefail
- ./wpt make-hosts-file | sudo tee -a /etc/hosts
- - name: Update manifest
- run: ./wpt manifest
- - name: Run tests
- run: |-
- set -eux -o pipefail
- export SYSTEM_VERSION_COMPAT=0
- ./wpt run \
- --no-manifest-update \
- --no-restart-on-unexpected \
- --no-fail-on-unexpected \
- --this-chunk=${{ matrix.current-chunk }} \
- --total-chunks=${{ matrix.total-chunks }} \
- --chunk-type hash \
- --log-wptreport ${{ runner.temp }}/wpt_report_${{ matrix.current-chunk }}.json \
- --log-wptscreenshot ${{ runner.temp }}/wpt_screenshot_${{ matrix.current-chunk }}.txt \
- --log-mach - \
- --log-mach-level info \
- --channel stable \
- --kill-safari \
- --max-restarts 100 \
- safari
- - name: Publish results
- uses: actions/upload-artifact@v4.1.0
- with:
- name: safari-results-${{ matrix.current-chunk }}
- path: |
- ${{ runner.temp }}/wpt_report_*.json
- ${{ runner.temp }}/wpt_screenshot_*.txt
- if-no-files-found: "error"
- - name: Publish safaridriver logs
- if: env.SAFARIDRIVER_DIAGNOSE == true
- uses: actions/upload-artifact@v4.1.0
- with:
- name: safaridriver-logs-${{ matrix.current-chunk }}
- path: ~/Library/Logs/com.apple.WebDriver/
- if-no-files-found: warn
- - name: Disable safaridriver diagnostics
- if: env.SAFARIDRIVER_DIAGNOSE == true
- run: |-
- defaults write com.apple.WebDriver DiagnosticsEnabled 0
- rm -rf ~/Library/Logs/com.apple.WebDriver/
- - name: Cleanup
- if: always()
- run: |-
- set -ux
- sudo sed -i '' '/^# Start web-platform-tests hosts$/,/^# End web-platform-tests hosts$/d' /etc/hosts
-
- safari-stable-results-notify:
- needs: safari-stable-results
- uses: ./.github/workflows/wpt_fyi_notify.yml
+ uses: ./.github/workflows/safari-wptrunner.yml
with:
- artifact-name: 'safari-results-*'
+ artifact-name: "safari-results"
+ safari-technology-preview: false
+ safaridriver-diagnose: false
diff --git a/tests/wpt/tests/.github/workflows/safari_technology_preview.yml b/tests/wpt/tests/.github/workflows/safari_technology_preview.yml
index 01380aa718e..70827a365ac 100644
--- a/tests/wpt/tests/.github/workflows/safari_technology_preview.yml
+++ b/tests/wpt/tests/.github/workflows/safari_technology_preview.yml
@@ -15,12 +15,6 @@ on:
- epochs/three_hourly
- triggers/safari_preview
-env:
- # Set SAFARIDRIVER_DIAGNOSE to true to enable safaridriver diagnostics. The
- # logs won't appear in `./wpt run` output but will be uploaded as an
- # artifact.
- SAFARIDRIVER_DIAGNOSE: false
-
jobs:
check-workflow-run:
name: "Check for appropriate epochs"
@@ -35,84 +29,8 @@ jobs:
needs: check-workflow-run
if: |
github.event_name != 'workflow_run' || fromJSON(needs.check-workflow-run.outputs.updated-refs)[0] != null
- runs-on:
- - self-hosted
- - webkit-ews
- timeout-minutes: 180
- strategy:
- matrix:
- current-chunk: [1, 2, 3, 4, 5, 6, 7, 8]
- total-chunks: [8]
- steps:
- - name: checkout
- uses: actions/checkout@v4.1.0
- with:
- fetch-depth: 1
- - name: Enable safaridriver diagnostics
- if: env.SAFARIDRIVER_DIAGNOSE == true
- run: |-
- rm -rf ~/Library/Logs/com.apple.WebDriver/
- defaults write com.apple.WebDriver DiagnosticsEnabled 1
- - name: Enable safaridriver
- run: |-
- set -eux -o pipefail
- export SYSTEM_VERSION_COMPAT=0
- ./wpt install --channel preview --download-only -d . --rename STP safari browser
- sudo installer -pkg STP.pkg -target LocalSystem
- sudo /Applications/Safari\ Technology\ Preview.app/Contents/MacOS/safaridriver --enable
- - name: Update hosts
- run: |-
- set -eux -o pipefail
- ./wpt make-hosts-file | sudo tee -a /etc/hosts
- - name: Update manifest
- run: ./wpt manifest
- - name: Run tests
- run: |-
- set -eux -o pipefail
- export SYSTEM_VERSION_COMPAT=0
- ./wpt run \
- --no-manifest-update \
- --no-restart-on-unexpected \
- --no-fail-on-unexpected \
- --this-chunk=${{ matrix.current-chunk }} \
- --total-chunks=${{ matrix.total-chunks }} \
- --chunk-type hash \
- --log-wptreport ${{ runner.temp }}/wpt_report_${{ matrix.current-chunk }}.json \
- --log-wptscreenshot ${{ runner.temp }}/wpt_screenshot_${{ matrix.current-chunk }}.txt \
- --log-mach - \
- --log-mach-level info \
- --channel experimental \
- --kill-safari \
- --max-restarts 100 \
- safari
- - name: Publish results
- uses: actions/upload-artifact@v4.1.0
- with:
- name: safari-technology-preview-results-${{ matrix.current-chunk }}
- path: |
- ${{ runner.temp }}/wpt_report_*.json
- ${{ runner.temp }}/wpt_screenshot_*.txt
- if-no-files-found: "error"
- - name: Publish safaridriver logs
- if: env.SAFARIDRIVER_DIAGNOSE == true
- uses: actions/upload-artifact@v4.1.0
- with:
- name: safaridriver-logs-${{ matrix.current-chunk }}
- path: ~/Library/Logs/com.apple.WebDriver/
- if-no-files-found: warn
- - name: Disable safaridriver diagnostics
- if: env.SAFARIDRIVER_DIAGNOSE == true
- run: |-
- defaults write com.apple.WebDriver DiagnosticsEnabled 0
- rm -rf ~/Library/Logs/com.apple.WebDriver/
- - name: Cleanup
- if: always()
- run: |-
- set -ux
- sudo sed -i '' '/^# Start web-platform-tests hosts$/,/^# End web-platform-tests hosts$/d' /etc/hosts
-
- safari-technology-preview-results-notify:
- needs: safari-technology-preview-results
- uses: ./.github/workflows/wpt_fyi_notify.yml
+ uses: ./.github/workflows/safari-wptrunner.yml
with:
- artifact-name: 'safari-technology-preview-results-*'
+ artifact-name: "safari-technology-preview-results"
+ safari-technology-preview: true
+ safaridriver-diagnose: false
diff --git a/tests/wpt/tests/IndexedDB/cursor-overloads.any.js b/tests/wpt/tests/IndexedDB/cursor-overloads.any.js
new file mode 100644
index 00000000000..dd80d2f4038
--- /dev/null
+++ b/tests/wpt/tests/IndexedDB/cursor-overloads.any.js
@@ -0,0 +1,87 @@
+// META: title=IndexedDB
+// META: global=window,worker
+// META: script=resources/support.js
+
+'use strict';
+
+async_test(t => {
+ let db;
+ let trans;
+ let store;
+ let index;
+ let request = createdb(t);
+
+ request.onupgradeneeded = function(e) {
+ db = e.target.result;
+ store = db.createObjectStore('store');
+ index = store.createIndex('index', 'value');
+ store.put({value: 0}, 0);
+ trans = request.transaction;
+ trans.oncomplete = verifyOverloads;
+ };
+
+ function verifyOverloads() {
+ trans = db.transaction('store', 'readonly', {durability: 'relaxed'});
+ store = trans.objectStore('store');
+ index = store.index('index');
+
+ checkCursorDirection(store.openCursor(), 'next');
+ checkCursorDirection(store.openCursor(0), 'next');
+ checkCursorDirection(store.openCursor(0, 'next'), 'next');
+ checkCursorDirection(store.openCursor(0, 'nextunique'), 'nextunique');
+ checkCursorDirection(store.openCursor(0, 'prev'), 'prev');
+ checkCursorDirection(store.openCursor(0, 'prevunique'), 'prevunique');
+
+ checkCursorDirection(store.openCursor(IDBKeyRange.only(0)), 'next');
+ checkCursorDirection(store.openCursor(IDBKeyRange.only(0), 'next'), 'next');
+ checkCursorDirection(
+ store.openCursor(IDBKeyRange.only(0), 'nextunique'), 'nextunique');
+ checkCursorDirection(store.openCursor(IDBKeyRange.only(0), 'prev'), 'prev');
+ checkCursorDirection(
+ store.openCursor(IDBKeyRange.only(0), 'prevunique'), 'prevunique');
+
+ checkCursorDirection(index.openCursor(), 'next');
+ checkCursorDirection(index.openCursor(0), 'next');
+ checkCursorDirection(index.openCursor(0, 'next'), 'next');
+ checkCursorDirection(index.openCursor(0, 'nextunique'), 'nextunique');
+ checkCursorDirection(index.openCursor(0, 'prev'), 'prev');
+ checkCursorDirection(index.openCursor(0, 'prevunique'), 'prevunique');
+
+ checkCursorDirection(index.openCursor(IDBKeyRange.only(0)), 'next');
+ checkCursorDirection(index.openCursor(IDBKeyRange.only(0), 'next'), 'next');
+ checkCursorDirection(
+ index.openCursor(IDBKeyRange.only(0), 'nextunique'), 'nextunique');
+ checkCursorDirection(index.openCursor(IDBKeyRange.only(0), 'prev'), 'prev');
+ checkCursorDirection(
+ index.openCursor(IDBKeyRange.only(0), 'prevunique'), 'prevunique');
+
+ checkCursorDirection(index.openKeyCursor(), 'next');
+ checkCursorDirection(index.openKeyCursor(0), 'next');
+ checkCursorDirection(index.openKeyCursor(0, 'next'), 'next');
+ checkCursorDirection(index.openKeyCursor(0, 'nextunique'), 'nextunique');
+ checkCursorDirection(index.openKeyCursor(0, 'prev'), 'prev');
+ checkCursorDirection(index.openKeyCursor(0, 'prevunique'), 'prevunique');
+
+ checkCursorDirection(index.openKeyCursor(IDBKeyRange.only(0)), 'next');
+ checkCursorDirection(
+ index.openKeyCursor(IDBKeyRange.only(0), 'next'), 'next');
+ checkCursorDirection(
+ index.openKeyCursor(IDBKeyRange.only(0), 'nextunique'), 'nextunique');
+ checkCursorDirection(
+ index.openKeyCursor(IDBKeyRange.only(0), 'prev'), 'prev');
+ checkCursorDirection(
+ index.openKeyCursor(IDBKeyRange.only(0), 'prevunique'), 'prevunique');
+
+ t.done();
+ }
+
+ function checkCursorDirection(request, direction) {
+ request.onsuccess = function(event) {
+ assert_not_equals(
+ event.target.result, null, 'Check the result is not null')
+ assert_equals(
+ event.target.result.direction, direction,
+ 'Check the result direction');
+ };
+ }
+}, 'Validate the overloads of IDBObjectStore.openCursor(), IDBIndex.openCursor() and IDBIndex.openKeyCursor()');
diff --git a/tests/wpt/tests/IndexedDB/cursor-overloads.htm b/tests/wpt/tests/IndexedDB/cursor-overloads.htm
deleted file mode 100644
index 7beeaa2bb39..00000000000
--- a/tests/wpt/tests/IndexedDB/cursor-overloads.htm
+++ /dev/null
@@ -1,88 +0,0 @@
-<!--
-Test converted from WebKit:
-http://trac.webkit.org/browser/trunk/LayoutTests/storage/indexeddb/cursor-overloads.html
--->
-
-<!DOCTYPE html>
-<!-- Submitted from TestTWF Paris -->
-<meta charset=utf-8>
-<title>Validate the overloads of IDBObjectStore.openCursor(), IDBIndex.openCursor() and IDBIndex.openKeyCursor()</title>
-<link rel=author href="mailto:romain.huet@gmail.com" title="Romain Huet">
-
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<script src=resources/support.js></script>
-
-<script>
-
- var db, trans, store, index;
- var t = async_test();
-
- var request = createdb(t);
- request.onupgradeneeded = function(e) {
- db = request.result;
- store = db.createObjectStore('store');
- index = store.createIndex('index', 'value');
- store.put({value: 0}, 0);
- trans = request.transaction;
- trans.oncomplete = verifyOverloads;
- };
-
- function verifyOverloads() {
- trans = db.transaction('store', 'readonly', {durability: 'relaxed'});
- store = trans.objectStore('store');
- index = store.index('index');
-
- checkCursorDirection("store.openCursor()", "next");
- checkCursorDirection("store.openCursor(0)", "next");
- checkCursorDirection("store.openCursor(0, 'next')", "next");
- checkCursorDirection("store.openCursor(0, 'nextunique')", "nextunique");
- checkCursorDirection("store.openCursor(0, 'prev')", "prev");
- checkCursorDirection("store.openCursor(0, 'prevunique')", "prevunique");
-
- checkCursorDirection("store.openCursor(IDBKeyRange.only(0))", "next");
- checkCursorDirection("store.openCursor(IDBKeyRange.only(0), 'next')", "next");
- checkCursorDirection("store.openCursor(IDBKeyRange.only(0), 'nextunique')", "nextunique");
- checkCursorDirection("store.openCursor(IDBKeyRange.only(0), 'prev')", "prev");
- checkCursorDirection("store.openCursor(IDBKeyRange.only(0), 'prevunique')", "prevunique");
-
- checkCursorDirection("index.openCursor()", "next");
- checkCursorDirection("index.openCursor(0)", "next");
- checkCursorDirection("index.openCursor(0, 'next')", "next");
- checkCursorDirection("index.openCursor(0, 'nextunique')", "nextunique");
- checkCursorDirection("index.openCursor(0, 'prev')", "prev");
- checkCursorDirection("index.openCursor(0, 'prevunique')", "prevunique");
-
- checkCursorDirection("index.openCursor(IDBKeyRange.only(0))", "next");
- checkCursorDirection("index.openCursor(IDBKeyRange.only(0), 'next')", "next");
- checkCursorDirection("index.openCursor(IDBKeyRange.only(0), 'nextunique')", "nextunique");
- checkCursorDirection("index.openCursor(IDBKeyRange.only(0), 'prev')", "prev");
- checkCursorDirection("index.openCursor(IDBKeyRange.only(0), 'prevunique')", "prevunique");
-
- checkCursorDirection("index.openKeyCursor()", "next");
- checkCursorDirection("index.openKeyCursor(0)", "next");
- checkCursorDirection("index.openKeyCursor(0, 'next')", "next");
- checkCursorDirection("index.openKeyCursor(0, 'nextunique')", "nextunique");
- checkCursorDirection("index.openKeyCursor(0, 'prev')", "prev");
- checkCursorDirection("index.openKeyCursor(0, 'prevunique')", "prevunique");
-
- checkCursorDirection("index.openKeyCursor(IDBKeyRange.only(0))", "next");
- checkCursorDirection("index.openKeyCursor(IDBKeyRange.only(0), 'next')", "next");
- checkCursorDirection("index.openKeyCursor(IDBKeyRange.only(0), 'nextunique')", "nextunique");
- checkCursorDirection("index.openKeyCursor(IDBKeyRange.only(0), 'prev')", "prev");
- checkCursorDirection("index.openKeyCursor(IDBKeyRange.only(0), 'prevunique')", "prevunique");
-
- t.done();
- }
-
- function checkCursorDirection(statement, direction) {
- request = eval(statement);
- request.onsuccess = function(event) {
- assert_not_equals(event.target.result, null, "Check the result is not null")
- assert_equals(event.target.result.direction, direction, "Check the result direction");
- };
- }
-
-</script>
-
-<div id=log></div>
diff --git a/tests/wpt/tests/IndexedDB/delete-request-queue.any.js b/tests/wpt/tests/IndexedDB/delete-request-queue.any.js
new file mode 100644
index 00000000000..6b2034c7f6b
--- /dev/null
+++ b/tests/wpt/tests/IndexedDB/delete-request-queue.any.js
@@ -0,0 +1,23 @@
+// META: title=IndexedDB
+// META: global=window,worker
+// META: script=resources/support.js
+
+'use strict';
+
+let saw;
+indexeddb_test(
+ (t, db) => {
+ this.saw = expect(t, ['delete1', 'delete2']);
+ let r = indexedDB.deleteDatabase(db.name);
+ r.onerror = t.unreached_func('delete should succeed');
+ r.onsuccess = t.step_func(e => saw('delete1'));
+ },
+ (t, db) => {
+ let r = indexedDB.deleteDatabase(db.name);
+ r.onerror = t.unreached_func('delete should succeed');
+ r.onsuccess = t.step_func(e => saw('delete2'));
+
+ db.close();
+ t.done();
+ },
+ 'Deletes are processed as a FIFO queue');
diff --git a/tests/wpt/tests/IndexedDB/delete-request-queue.html b/tests/wpt/tests/IndexedDB/delete-request-queue.html
deleted file mode 100644
index d8dfbf9a606..00000000000
--- a/tests/wpt/tests/IndexedDB/delete-request-queue.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<title>IndexedDB: delete requests are processed as a FIFO queue</title>
-<link rel="help" href="https://w3c.github.io/IndexedDB/#request-connection-queue">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="resources/support.js"></script>
-<script>
-
-let saw;
-indexeddb_test(
- (t, db) => {
- saw = expect(t, ['delete1', 'delete2']);
- let r = indexedDB.deleteDatabase(db.name);
- r.onerror = t.unreached_func('delete should succeed');
- r.onsuccess = t.step_func(e => saw('delete1'));
- },
- (t, db) => {
- let r = indexedDB.deleteDatabase(db.name);
- r.onerror = t.unreached_func('delete should succeed');
- r.onsuccess = t.step_func(e => saw('delete2'));
-
- db.close();
- },
- 'Deletes are processed in order');
-
-</script>
diff --git a/tests/wpt/tests/IndexedDB/error-attributes.any.js b/tests/wpt/tests/IndexedDB/error-attributes.any.js
new file mode 100644
index 00000000000..9b5003040b2
--- /dev/null
+++ b/tests/wpt/tests/IndexedDB/error-attributes.any.js
@@ -0,0 +1,32 @@
+// META: title=IndexedDB
+// META: global=window,worker
+// META: script=resources/support.js
+
+'use strict';
+
+indexeddb_test(
+ function(t, db) {
+ db.createObjectStore('store');
+ },
+ function(t, db) {
+ let tx = db.transaction('store', 'readwrite', {durability: 'relaxed'});
+ let store = tx.objectStore('store');
+ let r1 = store.add('value', 'key');
+ r1.onerror = t.unreached_func('first add should succeed');
+
+ let r2 = store.add('value', 'key');
+ r2.onsuccess = t.unreached_func('second add should fail');
+
+ r2.onerror = t.step_func(function() {
+ assert_true(r2.error instanceof DOMException);
+ assert_equals(r2.error.name, 'ConstraintError');
+ });
+
+ tx.oncomplete = t.unreached_func('transaction should not complete');
+ tx.onabort = t.step_func(function() {
+ assert_true(tx.error instanceof DOMException);
+ assert_equals(tx.error.name, 'ConstraintError');
+ t.done();
+ });
+ },
+ 'IDBRequest and IDBTransaction error properties should be DOMExceptions');
diff --git a/tests/wpt/tests/IndexedDB/error-attributes.html b/tests/wpt/tests/IndexedDB/error-attributes.html
deleted file mode 100644
index d65bf21790a..00000000000
--- a/tests/wpt/tests/IndexedDB/error-attributes.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<title>IndexedDB: Error attributes are DOMExceptions</title>
-<link rel="help" href="https://w3c.github.io/IndexedDB/#idbrequest">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="resources/support.js"></script>
-<script>
-
-indexeddb_test(
- function(t, db) {
- db.createObjectStore('store');
- },
- function(t, db) {
- var tx = db.transaction('store', 'readwrite', {durability: 'relaxed'});
- var store = tx.objectStore('store');
- var r1 = store.add('value', 'key');
- r1.onerror = t.unreached_func('first add should succeed');
-
- var r2 = store.add('value', 'key');
- r2.onsuccess = t.unreached_func('second add should fail');
-
- r2.onerror = t.step_func(function() {
- assert_true(r2.error instanceof DOMException);
- assert_equals(r2.error.name, 'ConstraintError');
- });
-
- tx.oncomplete = t.unreached_func('transaction should not complete');
- tx.onabort = t.step_func(function() {
- assert_true(tx.error instanceof DOMException);
- assert_equals(tx.error.name, 'ConstraintError');
- t.done();
- });
- },
- 'IDBRequest and IDBTransaction error properties should be DOMExceptions'
-);
-
-</script>
diff --git a/tests/wpt/tests/IndexedDB/upgrade-transaction-deactivation-timing.any.js b/tests/wpt/tests/IndexedDB/upgrade-transaction-deactivation-timing.any.js
new file mode 100644
index 00000000000..d11f821201c
--- /dev/null
+++ b/tests/wpt/tests/IndexedDB/upgrade-transaction-deactivation-timing.any.js
@@ -0,0 +1,46 @@
+// META: title=Upgrade transaction deactivation timing
+// META: global=window,worker
+// META: script=resources/support.js
+// META: script=resources/support-promises.js
+
+// Spec: "https://w3c.github.io/IndexedDB/#upgrade-transaction-steps"
+
+'use strict';
+
+indexeddb_test(
+ (t, db, tx) => {
+ db.createObjectStore('store');
+ assert_true(is_transaction_active(tx, 'store'),
+ 'Transaction should be active in upgradeneeded callback');
+ },
+ (t, db) => { t.done(); },
+ 'Upgrade transactions are active in upgradeneeded callback');
+
+indexeddb_test(
+ (t, db, tx) => {
+ db.createObjectStore('store');
+ assert_true(is_transaction_active(tx, 'store'),
+ 'Transaction should be active in upgradeneeded callback');
+
+ Promise.resolve().then(t.step_func(() => {
+ assert_true(is_transaction_active(tx, 'store'),
+ 'Transaction should be active in microtask checkpoint');
+ }));
+ },
+ (t, db) => { t.done(); },
+ 'Upgrade transactions are active in upgradeneeded callback and microtasks');
+
+
+indexeddb_test(
+ (t, db, tx) => {
+ db.createObjectStore('store');
+ const release_tx = keep_alive(tx, 'store');
+
+ setTimeout(t.step_func(() => {
+ assert_false(is_transaction_active(tx, 'store'),
+ 'Transaction should be inactive in next task');
+ release_tx();
+ }), 0);
+ },
+ (t, db) => { t.done(); },
+ 'Upgrade transactions are deactivated before next task'); \ No newline at end of file
diff --git a/tests/wpt/tests/IndexedDB/upgrade-transaction-deactivation-timing.html b/tests/wpt/tests/IndexedDB/upgrade-transaction-deactivation-timing.html
deleted file mode 100644
index 8119c9ab261..00000000000
--- a/tests/wpt/tests/IndexedDB/upgrade-transaction-deactivation-timing.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>Upgrade transaction deactivation timing</title>
-<link rel="help" href="http://localhost:4201/#upgrade-transaction-steps">
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<script src=resources/support.js></script>
-<script>
-
-indexeddb_test(
- (t, db, tx) => {
- db.createObjectStore('store');
- assert_true(is_transaction_active(tx, 'store'),
- 'Transaction should be active in upgradeneeded callback');
- },
- (t, db) => { t.done(); },
- 'Upgrade transactions are active in upgradeneeded callback');
-
-indexeddb_test(
- (t, db, tx) => {
- db.createObjectStore('store');
- assert_true(is_transaction_active(tx, 'store'),
- 'Transaction should be active in upgradeneeded callback');
-
- Promise.resolve().then(t.step_func(() => {
- assert_true(is_transaction_active(tx, 'store'),
- 'Transaction should be active in microtask checkpoint');
- }));
- },
- (t, db) => { t.done(); },
- 'Upgrade transactions are active in upgradeneeded callback and microtasks');
-
-
-indexeddb_test(
- (t, db, tx) => {
- db.createObjectStore('store');
- const release_tx = keep_alive(tx, 'store');
-
- setTimeout(t.step_func(() => {
- assert_false(is_transaction_active(tx, 'store'),
- 'Transaction should be inactive in next task');
- release_tx();
- }), 0);
- },
- (t, db) => { t.done(); },
- 'Upgrade transactions are deactivated before next task');
-
-</script>
diff --git a/tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-backend-aborted.any.js b/tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-backend-aborted.any.js
new file mode 100644
index 00000000000..841a83c6e0d
--- /dev/null
+++ b/tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-backend-aborted.any.js
@@ -0,0 +1,76 @@
+// META: title=IndexedDB: backend-aborted versionchange transaction lifecycle
+// META: global=window,worker
+// META: script=resources/support.js
+// META: script=resources/support-promises.js
+
+// Spec: "https://w3c.github.io/IndexedDB/#upgrade-transaction-steps"
+// "https://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore"
+// "https://w3c.github.io/IndexedDB/#dom-idbdatabase-deleteobjectstore"
+'use strict';
+
+promise_test(t => {
+ return createDatabase(t, database => {
+ createBooksStore(t, database);
+ }).then(database => {
+ database.close();
+ }).then(() => migrateDatabase(t, 2, (database, transaction, request) => {
+ return new Promise((resolve, reject) => {
+ transaction.addEventListener('abort', () => {
+ resolve(new Promise((resolve, reject) => {
+ assert_equals(
+ request.transaction, transaction,
+ "The open request's transaction should be reset after onabort");
+ assert_throws_dom(
+ 'InvalidStateError',
+ () => { database.createObjectStore('books2'); },
+ 'createObjectStore exception should reflect that the ' +
+ 'transaction is no longer running');
+ assert_throws_dom(
+ 'InvalidStateError',
+ () => { database.deleteObjectStore('books'); },
+ 'deleteObjectStore exception should reflect that the ' +
+ 'transaction is no longer running');
+ resolve();
+ }));
+ }, false);
+ transaction.objectStore('books').add(BOOKS_RECORD_DATA[0]);
+ transaction._willBeAborted();
+ });
+ }));
+}, 'in the abort event handler for a transaction aborted due to an unhandled ' +
+'request error');
+
+promise_test(t => {
+ return createDatabase(t, database => {
+ createBooksStore(t, database);
+ }).then(database => {
+ database.close();
+ }).then(() => migrateDatabase(t, 2, (database, transaction, request) => {
+ return new Promise((resolve, reject) => {
+ transaction.addEventListener('abort', () => {
+ setTimeout(() => {
+ resolve(new Promise((resolve, reject) => {
+ assert_equals(
+ request.transaction, null,
+ "The open request's transaction should be reset after " +
+ 'onabort microtasks');
+ assert_throws_dom(
+ 'InvalidStateError',
+ () => { database.createObjectStore('books2'); },
+ 'createObjectStore exception should reflect that the ' +
+ 'transaction is no longer running');
+ assert_throws_dom(
+ 'InvalidStateError',
+ () => { database.deleteObjectStore('books'); },
+ 'deleteObjectStore exception should reflect that the ' +
+ 'transaction is no longer running');
+ resolve();
+ }));
+ }, 0);
+ }, false);
+ transaction.objectStore('books').add(BOOKS_RECORD_DATA[0]);
+ transaction._willBeAborted();
+ });
+ }));
+}, 'in a setTimeout(0) callback after the abort event is fired for a ' +
+'transaction aborted due to an unhandled request failure'); \ No newline at end of file
diff --git a/tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-backend-aborted.html b/tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-backend-aborted.html
deleted file mode 100644
index 862e85144d6..00000000000
--- a/tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-backend-aborted.html
+++ /dev/null
@@ -1,84 +0,0 @@
-<!doctype html>
-<meta charset="utf8">
-<title>IndexedDB: backend-aborted versionchange transaction lifecycle</title>
-<link rel="help"
- href="https://w3c.github.io/IndexedDB/#upgrade-transaction-steps">
-<link rel="help"
- href="https://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore">
-<link rel="help"
- href="https://w3c.github.io/IndexedDB/#dom-idbdatabase-deleteobjectstore">
-<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="resources/support-promises.js"></script>
-<script>
-'use strict';
-
-promise_test(t => {
- return createDatabase(t, database => {
- createBooksStore(t, database);
- }).then(database => {
- database.close();
- }).then(() => migrateDatabase(t, 2, (database, transaction, request) => {
- return new Promise((resolve, reject) => {
- transaction.addEventListener('abort', () => {
- resolve(new Promise((resolve, reject) => {
- assert_equals(
- request.transaction, transaction,
- "The open request's transaction should be reset after onabort");
- assert_throws_dom(
- 'InvalidStateError',
- () => { database.createObjectStore('books2'); },
- 'createObjectStore exception should reflect that the ' +
- 'transaction is no longer running');
- assert_throws_dom(
- 'InvalidStateError',
- () => { database.deleteObjectStore('books'); },
- 'deleteObjectStore exception should reflect that the ' +
- 'transaction is no longer running');
- resolve();
- }));
- }, false);
- transaction.objectStore('books').add(BOOKS_RECORD_DATA[0]);
- transaction._willBeAborted();
- });
- }));
-}, 'in the abort event handler for a transaction aborted due to an unhandled ' +
- 'request error');
-
-promise_test(t => {
- return createDatabase(t, database => {
- createBooksStore(t, database);
- }).then(database => {
- database.close();
- }).then(() => migrateDatabase(t, 2, (database, transaction, request) => {
- return new Promise((resolve, reject) => {
- transaction.addEventListener('abort', () => {
- setTimeout(() => {
- resolve(new Promise((resolve, reject) => {
- assert_equals(
- request.transaction, null,
- "The open request's transaction should be reset after " +
- 'onabort microtasks');
- assert_throws_dom(
- 'InvalidStateError',
- () => { database.createObjectStore('books2'); },
- 'createObjectStore exception should reflect that the ' +
- 'transaction is no longer running');
- assert_throws_dom(
- 'InvalidStateError',
- () => { database.deleteObjectStore('books'); },
- 'deleteObjectStore exception should reflect that the ' +
- 'transaction is no longer running');
- resolve();
- }));
- }, 0);
- }, false);
- transaction.objectStore('books').add(BOOKS_RECORD_DATA[0]);
- transaction._willBeAborted();
- });
- }));
-}, 'in a setTimeout(0) callback after the abort event is fired for a ' +
- 'transaction aborted due to an unhandled request failure');
-
-</script>
diff --git a/tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-committed.any.js b/tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-committed.any.js
new file mode 100644
index 00000000000..85b447ea951
--- /dev/null
+++ b/tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-committed.any.js
@@ -0,0 +1,73 @@
+// META: title=IndexedDB: committed versionchange transaction lifecycle
+// META: global=window,worker
+// META: script=resources/support.js
+// META: script=resources/support-promises.js
+
+// Spec: "https://w3c.github.io/IndexedDB/#upgrade-transaction-steps"
+// "https://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore"
+// "https://w3c.github.io/IndexedDB/#dom-idbdatabase-deleteobjectstore"
+
+'use strict';
+
+promise_test(t => {
+ return createDatabase(t, database => {
+ createBooksStore(t, database);
+ }).then(database => {
+ database.close();
+ }).then(() => migrateDatabase(t, 2, (database, transaction, request) => {
+ return new Promise((resolve, reject) => {
+ transaction.addEventListener('complete', () => {
+ resolve(new Promise((resolve, reject) => {
+ assert_equals(
+ request.transaction, transaction,
+ "The open request's transaction should be reset after " +
+ 'oncomplete');
+ assert_throws_dom(
+ 'InvalidStateError',
+ () => { database.createObjectStore('books2'); },
+ 'createObjectStore exception should reflect that the ' +
+ 'transaction is no longer running');
+ assert_throws_dom(
+ 'InvalidStateError',
+ () => { database.deleteObjectStore('books'); },
+ 'deleteObjectStore exception should reflect that the ' +
+ 'transaction is no longer running');
+ resolve();
+ }));
+ }, false);
+ });
+ })).then(database => { database.close(); });
+}, 'in the complete event handler for a committed transaction');
+
+promise_test(t => {
+ return createDatabase(t, database => {
+ createBooksStore(t, database);
+ }).then(database => {
+ database.close();
+ }).then(() => migrateDatabase(t, 2, (database, transaction, request) => {
+ return new Promise((resolve, reject) => {
+ transaction.addEventListener('complete', () => {
+ setTimeout(() => {
+ resolve(new Promise((resolve, reject) => {
+ assert_equals(
+ request.transaction, null,
+ "The open request's transaction should be reset after " +
+ 'oncomplete microtasks');
+ assert_throws_dom(
+ 'InvalidStateError',
+ () => { database.createObjectStore('books2'); },
+ 'createObjectStore exception should reflect that the ' +
+ 'transaction is no longer running');
+ assert_throws_dom(
+ 'InvalidStateError',
+ () => { database.deleteObjectStore('books'); },
+ 'deleteObjectStore exception should reflect that the ' +
+ 'transaction is no longer running');
+ resolve();
+ }));
+ }, 0);
+ }, false);
+ });
+ })).then(database => { database.close(); });
+}, 'in a setTimeout(0) callback after the complete event is fired for a ' +
+'committed transaction'); \ No newline at end of file
diff --git a/tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-committed.html b/tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-committed.html
deleted file mode 100644
index 347d940aeef..00000000000
--- a/tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-committed.html
+++ /dev/null
@@ -1,80 +0,0 @@
-<!doctype html>
-<meta charset="utf8">
-<title>IndexedDB: committed versionchange transaction lifecycle</title>
-<link rel="help"
- href="https://w3c.github.io/IndexedDB/#upgrade-transaction-steps">
-<link rel="help"
- href="https://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore">
-<link rel="help"
- href="https://w3c.github.io/IndexedDB/#dom-idbdatabase-deleteobjectstore">
-<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="resources/support-promises.js"></script>
-<script>
-'use strict';
-
-promise_test(t => {
- return createDatabase(t, database => {
- createBooksStore(t, database);
- }).then(database => {
- database.close();
- }).then(() => migrateDatabase(t, 2, (database, transaction, request) => {
- return new Promise((resolve, reject) => {
- transaction.addEventListener('complete', () => {
- resolve(new Promise((resolve, reject) => {
- assert_equals(
- request.transaction, transaction,
- "The open request's transaction should be reset after " +
- 'oncomplete');
- assert_throws_dom(
- 'InvalidStateError',
- () => { database.createObjectStore('books2'); },
- 'createObjectStore exception should reflect that the ' +
- 'transaction is no longer running');
- assert_throws_dom(
- 'InvalidStateError',
- () => { database.deleteObjectStore('books'); },
- 'deleteObjectStore exception should reflect that the ' +
- 'transaction is no longer running');
- resolve();
- }));
- }, false);
- });
- })).then(database => { database.close(); });
-}, 'in the complete event handler for a committed transaction');
-
-promise_test(t => {
- return createDatabase(t, database => {
- createBooksStore(t, database);
- }).then(database => {
- database.close();
- }).then(() => migrateDatabase(t, 2, (database, transaction, request) => {
- return new Promise((resolve, reject) => {
- transaction.addEventListener('complete', () => {
- setTimeout(() => {
- resolve(new Promise((resolve, reject) => {
- assert_equals(
- request.transaction, null,
- "The open request's transaction should be reset after " +
- 'oncomplete microtasks');
- assert_throws_dom(
- 'InvalidStateError',
- () => { database.createObjectStore('books2'); },
- 'createObjectStore exception should reflect that the ' +
- 'transaction is no longer running');
- assert_throws_dom(
- 'InvalidStateError',
- () => { database.deleteObjectStore('books'); },
- 'deleteObjectStore exception should reflect that the ' +
- 'transaction is no longer running');
- resolve();
- }));
- }, 0);
- }, false);
- });
- })).then(database => { database.close(); });
-}, 'in a setTimeout(0) callback after the complete event is fired for a ' +
- 'committed transaction');
-
-</script>
diff --git a/tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-user-aborted.html b/tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-user-aborted.any.js
index 4094ce34f34..4346e1a675d 100644
--- a/tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-user-aborted.html
+++ b/tests/wpt/tests/IndexedDB/upgrade-transaction-lifecycle-user-aborted.any.js
@@ -1,17 +1,12 @@
-<!doctype html>
-<meta charset="utf8">
-<title>IndexedDB: user-abort()ed versionchange transaction lifecycle</title>
-<link rel="help"
- href="https://w3c.github.io/IndexedDB/#upgrade-transaction-steps">
-<link rel="help"
- href="https://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore">
-<link rel="help"
- href="https://w3c.github.io/IndexedDB/#dom-idbdatabase-deleteobjectstore">
-<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="resources/support-promises.js"></script>
-<script>
+// META: title=IndexedDB: user-abort()ed versionchange transaction lifecycle
+// META: global=window,worker
+// META: script=resources/support.js
+// META: script=resources/support-promises.js
+
+// Spec: "https://w3c.github.io/IndexedDB/#upgrade-transaction-steps"
+// "https://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore"
+// "https://w3c.github.io/IndexedDB/#dom-idbdatabase-deleteobjectstore"
+
'use strict';
promise_test(t => {
@@ -138,6 +133,4 @@ promise_test(t => {
});
}));
}, 'in a setTimeout(0) callback after the abort event is fired for a ' +
- 'transaction aborted due to an abort() call');
-
-</script>
+ 'transaction aborted due to an abort() call'); \ No newline at end of file
diff --git a/tests/wpt/tests/WebCryptoAPI/import_export/okp_importKey.js b/tests/wpt/tests/WebCryptoAPI/import_export/okp_importKey.js
index 5699341d9e4..0e6a016fe20 100644
--- a/tests/wpt/tests/WebCryptoAPI/import_export/okp_importKey.js
+++ b/tests/wpt/tests/WebCryptoAPI/import_export/okp_importKey.js
@@ -40,51 +40,55 @@ function runTests(algorithmName) {
// Test importKey with a given key format and other parameters. If
// extrable is true, export the key and verify that it matches the input.
function testFormat(format, algorithm, keyData, keySize, usages, extractable) {
- promise_test(function(test) {
- return subtle.importKey(format, keyData[format], algorithm, extractable, usages).
- then(function(key) {
- assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object");
- assert_goodCryptoKey(key, algorithm, extractable, usages, (format === 'pkcs8' || (format === 'jwk' && keyData[format].d)) ? 'private' : 'public');
- if (!extractable) {
- return;
- }
+ [algorithm, algorithm.name].forEach((alg) => {
+ promise_test(function(test) {
+ return subtle.importKey(format, keyData[format], alg, extractable, usages).
+ then(function(key) {
+ assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object");
+ assert_goodCryptoKey(key, algorithm, extractable, usages, (format === 'pkcs8' || (format === 'jwk' && keyData[format].d)) ? 'private' : 'public');
+ if (!extractable) {
+ return;
+ }
- return subtle.exportKey(format, key).
- then(function(result) {
- if (format !== "jwk") {
- assert_true(equalBuffers(keyData[format], result), "Round trip works");
- } else {
- assert_true(equalJwk(keyData[format], result), "Round trip works");
- }
- }, function(err) {
- assert_unreached("Threw an unexpected error: " + err.toString());
- });
- }, function(err) {
- assert_unreached("Threw an unexpected error: " + err.toString());
- });
- }, "Good parameters: " + keySize.toString() + " bits " + parameterString(format, keyData[format], algorithm, extractable, usages));
+ return subtle.exportKey(format, key).
+ then(function(result) {
+ if (format !== "jwk") {
+ assert_true(equalBuffers(keyData[format], result), "Round trip works");
+ } else {
+ assert_true(equalJwk(keyData[format], result), "Round trip works");
+ }
+ }, function(err) {
+ assert_unreached("Threw an unexpected error: " + err.toString());
+ });
+ }, function(err) {
+ assert_unreached("Threw an unexpected error: " + err.toString());
+ });
+ }, "Good parameters: " + keySize.toString() + " bits " + parameterString(format, keyData[format], alg, extractable, usages));
+ });
}
// Test importKey/exportKey "alg" behaviours, alg is ignored upon import and alg is missing for Ed25519 and Ed448 JWK export
// https://github.com/WICG/webcrypto-secure-curves/pull/24
function testJwkAlgBehaviours(algorithm, keyData, crv, usages) {
- promise_test(function(test) {
- return subtle.importKey('jwk', { ...keyData, alg: 'this is ignored' }, algorithm, true, usages).
- then(function(key) {
- assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object");
-
- return subtle.exportKey('jwk', key).
- then(function(result) {
- assert_equals(Object.keys(result).length, keyData.d ? 6 : 5, "Correct number of JWK members");
- assert_equals(result.alg, undefined, 'No JWK "alg" member is present');
- assert_true(equalJwk(keyData, result), "Round trip works");
- }, function(err) {
+ [algorithm, algorithm.name].forEach((alg) => {
+ promise_test(function(test) {
+ return subtle.importKey('jwk', { ...keyData, alg: 'this is ignored' }, alg, true, usages).
+ then(function(key) {
+ assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object");
+
+ return subtle.exportKey('jwk', key).
+ then(function(result) {
+ assert_equals(Object.keys(result).length, keyData.d ? 6 : 5, "Correct number of JWK members");
+ assert_equals(result.alg, undefined, 'No JWK "alg" member is present');
+ assert_true(equalJwk(keyData, result), "Round trip works");
+ }, function(err) {
assert_unreached("Threw an unexpected error: " + err.toString());
- });
- }, function(err) {
- assert_unreached("Threw an unexpected error: " + err.toString());
- });
- }, "Good parameters with ignored JWK alg: " + crv.toString() + " " + parameterString('jwk', keyData, algorithm, true, usages));
+ });
+ }, function(err) {
+ assert_unreached("Threw an unexpected error: " + err.toString());
+ });
+ }, "Good parameters with ignored JWK alg: " + crv.toString() + " " + parameterString('jwk', keyData, alg, true, usages));
+ });
}
diff --git a/tests/wpt/tests/attribution-reporting/aggregatable-report-no-contributions.sub.https.html b/tests/wpt/tests/attribution-reporting/aggregatable-report-no-contributions.sub.https.html
index b42a61b7bd5..b84f1905626 100644
--- a/tests/wpt/tests/attribution-reporting/aggregatable-report-no-contributions.sub.https.html
+++ b/tests/wpt/tests/attribution-reporting/aggregatable-report-no-contributions.sub.https.html
@@ -14,7 +14,6 @@ attribution_reporting_promise_test(async t => {
registerAttributionSrcByImg(createRedirectChain([
{
- cookie: attributionDebugCookie,
source: {
aggregation_keys: {
campaignCounts: '0x159',
diff --git a/tests/wpt/tests/attribution-reporting/resources/helpers.js b/tests/wpt/tests/attribution-reporting/resources/helpers.js
index 0f20a71237c..56e2a2812b6 100644
--- a/tests/wpt/tests/attribution-reporting/resources/helpers.js
+++ b/tests/wpt/tests/attribution-reporting/resources/helpers.js
@@ -35,8 +35,6 @@ const verboseDebugReportsUrl =
const aggregatableDebugReportsUrl =
'/.well-known/attribution-reporting/debug/report-aggregate-debug';
-const attributionDebugCookie = 'ar_debug=1;Secure;HttpOnly;SameSite=None;Path=/';
-
const pipeHeaderPattern = /[,)]/g;
// , and ) in pipe values must be escaped with \
@@ -86,7 +84,7 @@ const redirectReportsTo = origin => {
]);
};
-const getFetchParams = (origin, cookie) => {
+const getFetchParams = (origin) => {
let credentials;
const headers = [];
@@ -95,25 +93,10 @@ const getFetchParams = (origin, cookie) => {
}
// https://fetch.spec.whatwg.org/#http-cors-protocol
-
- const allowOriginHeader = 'Access-Control-Allow-Origin';
-
- if (cookie) {
- credentials = 'include';
- headers.push({
- name: 'Access-Control-Allow-Credentials',
- value: 'true',
- });
- headers.push({
- name: allowOriginHeader,
- value: `${location.origin}`,
- });
- } else {
- headers.push({
- name: allowOriginHeader,
- value: '*',
- });
- }
+ headers.push({
+ name: 'Access-Control-Allow-Origin',
+ value: '*',
+ });
return {credentials, headers};
};
@@ -127,7 +110,7 @@ const createRedirectChain = (redirects) => {
let redirectTo;
for (let i = redirects.length - 1; i >= 0; i--) {
- const {source, trigger, cookie, reportingOrigin} = redirects[i];
+ const {source, trigger, reportingOrigin} = redirects[i];
const headers = [];
if (source) {
@@ -144,10 +127,6 @@ const createRedirectChain = (redirects) => {
});
}
- if (cookie) {
- headers.push({name: 'Set-Cookie', value: cookie});
- }
-
let status;
if (redirectTo) {
headers.push({name: 'Location', value: redirectTo.toString()});
@@ -169,7 +148,6 @@ const registerAttributionSrcByImg = (attributionSrc) => {
const registerAttributionSrc = ({
source,
trigger,
- cookie,
method = 'img',
extraQueryParams = {},
reportingOrigin,
@@ -200,14 +178,9 @@ const registerAttributionSrc = ({
});
}
- if (cookie) {
- const name = 'Set-Cookie';
- headers.push({name, value: cookie});
- }
-
let credentials;
if (method === 'fetch') {
- const params = getFetchParams(reportingOrigin, cookie);
+ const params = getFetchParams(reportingOrigin);
credentials = params.credentials;
headers = headers.concat(params.headers);
}
diff --git a/tests/wpt/tests/attribution-reporting/simple-verbose-debug-report.sub.https.html b/tests/wpt/tests/attribution-reporting/simple-verbose-debug-report.sub.https.html
index 8a477f732f4..cc2e37cae8e 100644
--- a/tests/wpt/tests/attribution-reporting/simple-verbose-debug-report.sub.https.html
+++ b/tests/wpt/tests/attribution-reporting/simple-verbose-debug-report.sub.https.html
@@ -11,7 +11,6 @@ attribution_reporting_promise_test(async t => {
registerAttributionSrcByImg(createRedirectChain([
{
- cookie: attributionDebugCookie,
trigger: {
debug_reporting: true,
debug_key: expectedTriggerDebugKey,
diff --git a/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-basics.https.html b/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-basics.https.html
index 5d6f701bdb7..f7aed80b17e 100644
--- a/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-basics.https.html
+++ b/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-basics.https.html
@@ -28,13 +28,51 @@ promise_test(async t => {
await getPermissions();
const text_plain = "This text was copied using `Clipboard.prototype.write`.";
const html_text = "<p style='color: red; font-style: oblique;'>Test</p>";
- await promise_rejects_dom(t, "NotAllowedError", navigator.clipboard.write([
+ await navigator.clipboard.write([
new ClipboardItem({
"text/plain": text_plain,
"text/html" : html_text
}),
- ]));
- }, 'navigator.clipboard.write(Promise<DOMString>) fails');
+ ]);
+ }, 'navigator.clipboard.write(DOMString) succeeds');
+
+promise_test(async () => {
+ await getPermissions();
+ const promise_text_string = Promise.resolve('hello');
+ const promise_html_string = Promise.resolve("<p style='color: red; font-style: oblique;'>hello</p>");
+ const item = new ClipboardItem({
+ 'text/plain': promise_text_string,
+ 'text/html': promise_html_string
+ });
+ await navigator.clipboard.write([item]);
+}, 'navigator.clipboard.write(Promise<DOMString>) succeeds');
+
+promise_test(async t => {
+ await getPermissions();
+ const text_plain = 'hello';
+ const html_text = "<p style='color: red; font-style: oblique;'>hello</p>";
+ const image = await fetch("/clipboard-apis/resources/greenbox.png");
+ const item = new ClipboardItem({
+ 'text/plain': text_plain,
+ 'text/html': new Blob([html_text], {type: 'text/html'}),
+ 'image/png': image.blob(), // Promise<Blob>
+ 'web text/csv': 'hello,world'
+ });
+ await navigator.clipboard.write([item]);
+}, 'navigator.clipboard.write(web_custom_format) succeeds');
+
+promise_test(async () => {
+ await getPermissions();
+ const html_text = "<p style='color: red; font-style: oblique;'>Test</p>";
+ const item = new ClipboardItem({
+ 'text/plain': 'hello',
+ 'text/html': new Blob([html_text], {type: 'text/html'})
+ });
+ const text = await item.getType('text/plain');
+ const blob = await item.getType('text/html');
+ assert_true(text instanceof Blob, "item.getType('text/plain') didn't return a Blob");
+ assert_true(blob instanceof Blob, "item.getType('text/html') didn't return a Blob");
+}, 'validate GetType(type) on a contructed ClipboardItem returns Blob');
promise_test(async () => {
await getPermissions();
diff --git a/tests/wpt/tests/close-watcher/user-activation/y-dialog-disconnected.html b/tests/wpt/tests/close-watcher/user-activation/y-dialog-disconnected.html
new file mode 100644
index 00000000000..0bd41b5bb24
--- /dev/null
+++ b/tests/wpt/tests/close-watcher/user-activation/y-dialog-disconnected.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=author href="mailto:wpt@keithcirkel.co.uk">
+<link rel=help href="https://github.com/whatwg/html/pull/9462">
+<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>
+<script src="../resources/helpers.js"></script>
+
+<button id=b0>b0</button>
+
+<dialog id=d1>
+ <button id=b1>b1</button>
+
+ <dialog id=d2>d2</dialog>
+</dialog>
+
+<script>
+promise_test(async () => {
+ const d1 = document.getElementById('d1');
+ const d2 = document.getElementById('d2');
+ await test_driver.click(b0);
+ d1.showModal();
+ await test_driver.click(b1);
+ d2.showModal();
+
+ assert_true(d1.matches(':modal'), 'd1 should be open.');
+ assert_true(d2.matches(':modal'), 'd2 should be open.');
+
+ d2.remove()
+
+ assert_false(d2.matches(':modal'), 'd2 should now be closed.');
+ await sendCloseRequest();
+ assert_false(d2.matches(':modal'), 'd2 still now be closed.');
+ assert_false(d1.matches(':modal'), 'd1 should now be closed.');
+
+ await sendCloseRequest();
+ assert_false(d2.matches(':modal'), 'd2 still now be closed.');
+ assert_false(d1.matches(':modal'), 'd1 still now be closed.');
+}, 'Disconnect dialog with close request');
+</script>
diff --git a/tests/wpt/tests/close-watcher/user-activation/y-popover-disconnected.html b/tests/wpt/tests/close-watcher/user-activation/y-popover-disconnected.html
new file mode 100644
index 00000000000..22fbdbfe73b
--- /dev/null
+++ b/tests/wpt/tests/close-watcher/user-activation/y-popover-disconnected.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=author href="mailto:wpt@keithcirkel.co.uk">
+<link rel=help href="https://github.com/whatwg/html/pull/9462">
+<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>
+<script src="../resources/helpers.js"></script>
+
+<button id=b0>b0</button>
+
+<div id=p1 popover=auto>
+ <button id=b1>b1</button>
+
+ <div id=p2 popover=auto>p2</div>
+</div>
+
+<script>
+promise_test(async () => {
+ const p1 = document.getElementById('p1');
+ const p2 = document.getElementById('p2');
+ await test_driver.click(b0);
+ p1.showPopover();
+ await test_driver.click(b1);
+ p2.showPopover();
+
+ assert_true(p1.matches(':popover-open'), 'p1 should be open.');
+ assert_true(p2.matches(':popover-open'), 'p2 should be open.');
+
+ p2.remove()
+
+ assert_false(p2.matches(':popover-open'), 'p2 should now be closed.');
+ await sendCloseRequest();
+ assert_false(p2.matches(':popover-open'), 'p2 still now be closed.');
+ assert_false(p1.matches(':popover-open'), 'p1 should now be closed.');
+
+ await sendCloseRequest();
+ assert_false(p2.matches(':popover-open'), 'p2 still now be closed.');
+ assert_false(p1.matches(':popover-open'), 'p1 still now be closed.');
+}, 'Disconnect popover with close request');
+</script>
diff --git a/tests/wpt/tests/css/CSS2/ui/overflow-applies-to-009.xht b/tests/wpt/tests/css/CSS2/ui/overflow-applies-to-009.xht
index 5867a68b7a5..1a82a080654 100644
--- a/tests/wpt/tests/css/CSS2/ui/overflow-applies-to-009.xht
+++ b/tests/wpt/tests/css/CSS2/ui/overflow-applies-to-009.xht
@@ -12,7 +12,7 @@
<meta name="assert" content="The 'overflow' property applies to elements with 'display' set to 'block'." />
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style type="text/css">
- span
+ #blockoverflow
{
border: 5px solid transparent;
color: white;
@@ -30,7 +30,7 @@
<body>
<p>Test passes if there is <strong>no red</strong>.</p>
<div>
- <span><b>XXXXX</b><b id="test">XXXXX</b></span>
+ <span id="blockoverflow"><span>XXXXX</span><span id="test">XXXXX</span></span>
</div>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/tests/wpt/tests/css/css-align/blocks/justify-self-block-in-inline.html b/tests/wpt/tests/css/css-align/blocks/justify-self-block-in-inline.html
index 3a326016bc1..0a3facf3ef7 100644
--- a/tests/wpt/tests/css/css-align/blocks/justify-self-block-in-inline.html
+++ b/tests/wpt/tests/css/css-align/blocks/justify-self-block-in-inline.html
@@ -1,5 +1,6 @@
<!DOCTYPE html>
-<link rel="help" href="https://drafts.csswg.org/css-align-3/#justify-abspos">
+<link rel="help" href="https://drafts.csswg.org/css-align/#justify-self-property">
+<link rel="help" href="https://crbug.com/374034249">
<meta name="assert"
content="block-in-inline width is stretched to its parent width, not sized as 'fit-content'" />
@@ -24,4 +25,13 @@
<span class="inline-block" style="width: 100px;">inline-block</span>
</div>
+<div style="width: 100px; justify-self: left;">
+ <span>
+ <div class="block-in-inline"
+ style="height: 100px; background: green;"
+ data-expected-width="100">
+ </div>
+ </span>
+</div>
+
<script>checkLayout('.block-in-inline')</script>
diff --git a/tests/wpt/tests/css/css-anchor-position/anchor-scope-basic.html b/tests/wpt/tests/css/css-anchor-position/anchor-scope-basic.html
index 147aef8c764..47cb3b8d86a 100644
--- a/tests/wpt/tests/css/css-anchor-position/anchor-scope-basic.html
+++ b/tests/wpt/tests/css/css-anchor-position/anchor-scope-basic.html
@@ -37,9 +37,7 @@
</style>
<script>
function inflate(t, template_element) {
- if (!template_element.hasAttribute('debug')) {
- t.add_cleanup(() => main.replaceChildren());
- }
+ t.add_cleanup(() => main.replaceChildren());
main.append(template_element.content.cloneNode(true));
}
</script>
@@ -47,6 +45,32 @@
<main id=main>
</main>
+<template id=test_inclusive_subtree>
+ <div class="scope-a anchor-a"> <!--A-->
+ <div class=anchored-a></div>
+ </div>
+</template>
+<script>
+ test((t) => {
+ inflate(t, test_inclusive_subtree);
+ assert_equals(getComputedStyle(main.querySelector('.anchored-a')).top, '10px');
+ }, 'Can anchor to a name both defined and scoped by the same element');
+</script>
+
+<template id=test_skips_named_anchor_with_scope>
+ <div class="anchor-a"></div>
+ <div class="anchor-a"></div>
+ <div class="anchor-a"></div> <!--A-->
+ <div class="scope-a anchor-a"></div>
+ <div class=anchored-a></div>
+</template>
+<script>
+ test((t) => {
+ inflate(t, test_skips_named_anchor_with_scope);
+ assert_equals(getComputedStyle(main.querySelector('.anchored-a')).top, '30px');
+ }, 'Sibling can not anchor into anchor-scope, even when anchor-name present');
+</script>
+
<template id=test_scope_all_common_ancestor>
<div class=scope-all>
<div class=anchor-a></div>
diff --git a/tests/wpt/tests/css/css-anchor-position/try-tactic-wm.html b/tests/wpt/tests/css/css-anchor-position/try-tactic-wm.html
index 8dcf98f8939..69d9c2dff88 100644
--- a/tests/wpt/tests/css/css-anchor-position/try-tactic-wm.html
+++ b/tests/wpt/tests/css/css-anchor-position/try-tactic-wm.html
@@ -46,6 +46,10 @@
// Effectively flips top:20px to bottom:20px:
test_try_tactic_wm('flip-inline', 'vertical-lr', 'ltr', {left:10, top:340, width:30, height:40});
+ test_try_tactic_wm('flip-inline', 'sideways-lr', 'ltr', {left:10, top:340, width:30, height:40});
+
+ // Effectively flips left:10px to right:10px:
+ test_try_tactic_wm('flip-block', 'sideways-rl', 'ltr', {left:360, top:20, width:30, height:40});
// Mirror across the [left,top]=>[bottom,right] diagonal:
test_try_tactic_wm('flip-start', 'horizontal-tb', 'ltr', {left:20, top:10, width:40, height:30});
diff --git a/tests/wpt/tests/css/css-break/text-indent-and-wide-float.html b/tests/wpt/tests/css/css-break/text-indent-and-wide-float.html
new file mode 100644
index 00000000000..59885e7c2c0
--- /dev/null
+++ b/tests/wpt/tests/css/css-break/text-indent-and-wide-float.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="http://crbug.com/365814218">
+<meta name="assert" content="Floats are not part of lines, so if a float is too wide to fit any inline content beside it, the first formatted line goes below it, or even into the next fragmentainer if there's insufficient room below.">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width:100px; height:100px; background:red;">
+ <div style="columns:2; column-fill:auto; gap:0; height:110px; font:25px/25px Ahem; text-indent:25px;">
+ <span style="color:green;">
+ <div style="float:left; width:100%; height:100px; background:green;">
+ <!-- Bleed into the next column, to cover the text indentation there. -->
+ <div style="width:150%; height:25px; background:green;"></div>
+ </div>
+ x xx xx xx
+ </span>
+ </div>
+</div>
diff --git a/tests/wpt/tests/css/css-break/transform-025.html b/tests/wpt/tests/css/css-break/transform-025.html
new file mode 100644
index 00000000000..58020065dc1
--- /dev/null
+++ b/tests/wpt/tests/css/css-break/transform-025.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-break-3/#transforms">
+<link rel="help" href="https://crbug.com/40501131">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="display:flow-root; writing-mode:sideways-rl; width:100px; height:100px; background:red;">
+ <div style="columns:3; column-fill:auto; gap:0; inline-size:150px; block-size:100px; margin-block-start:100px; margin-inline-start:-50px;">
+ <div style="transform:rotate(180deg); transform-origin:middle left; block-size:77px;">
+ <div style="position:absolute; inset-block-start:100px; inline-size:100%; block-size:200px; background:green;"></div>
+ </div>
+ </div>
+</div>
diff --git a/tests/wpt/tests/css/css-color/parsing/color-computed-relative-color.html b/tests/wpt/tests/css/css-color/parsing/color-computed-relative-color.html
index 8407e527017..23ee07d177a 100644
--- a/tests/wpt/tests/css/css-color/parsing/color-computed-relative-color.html
+++ b/tests/wpt/tests/css/css-color/parsing/color-computed-relative-color.html
@@ -120,12 +120,12 @@
// Testing with 'none'. Missing components are resolved to zero during color space conversion.
// https://drafts.csswg.org/css-color-4/#missing
- fuzzy_test_computed_color(`rgb(from rebeccapurple none none none)`, `color(srgb 0 0 0)`);
- fuzzy_test_computed_color(`rgb(from rebeccapurple none none none / none)`, `color(srgb 0 0 0 / none)`);
- fuzzy_test_computed_color(`rgb(from rebeccapurple r g none)`, `color(srgb 0.4 0.2 0)`);
- fuzzy_test_computed_color(`rgb(from rebeccapurple r g none / alpha)`, `color(srgb 0.4 0.2 0)`);
+ fuzzy_test_computed_color(`rgb(from rebeccapurple none none none)`, `color(srgb none none none)`);
+ fuzzy_test_computed_color(`rgb(from rebeccapurple none none none / none)`, `color(srgb none none none / none)`);
+ fuzzy_test_computed_color(`rgb(from rebeccapurple r g none)`, `color(srgb 0.4 0.2 none)`);
+ fuzzy_test_computed_color(`rgb(from rebeccapurple r g none / alpha)`, `color(srgb 0.4 0.2 none)`);
fuzzy_test_computed_color(`rgb(from rebeccapurple r g b / none)`, `color(srgb 0.4 0.2 0.6 / none)`);
- fuzzy_test_computed_color(`rgb(from rgb(20% 40% 60% / 80%) r g none / alpha)`, `color(srgb 0.2 0.4 0 / 0.8)`);
+ fuzzy_test_computed_color(`rgb(from rgb(20% 40% 60% / 80%) r g none / alpha)`, `color(srgb 0.2 0.4 none / 0.8)`);
fuzzy_test_computed_color(`rgb(from rgb(20% 40% 60% / 80%) r g b / none)`, `color(srgb 0.2 0.4 0.6 / none)`);
fuzzy_test_computed_color(`rgb(from rgb(none none none) r g b)`, `color(srgb 0 0 0)`);
fuzzy_test_computed_color(`rgb(from rgb(none none none / none) r g b / alpha)`, `color(srgb 0 0 0 / 0)`);
@@ -145,6 +145,10 @@
// Nesting combined with 'currentColor'
fuzzy_test_computed_color_using_currentcolor(`rgb(from rgb(from currentColor r g b) r g b)`, `color(srgb 0.4 0.2 0.6)`, `rebeccapurple`);
+ // Nesting inside light-dark()
+ fuzzy_test_computed_color(`light-dark(rgb(from rebeccapurple r g b), rgb(from rebeccapurple r g b))`, `color(srgb 0.4 0.2 0.6)`);
+ fuzzy_test_computed_color(`light-dark(color-mix(in srgb, rgb(from rebeccapurple none g b), rebeccapurple), color-mix(in srgb, rgb(from rebeccapurple none g b), rebeccapurple))`, `color(srgb 0.4 0.2 0.6)`);
+
// hsl(from ...)
// Testing no modifications.
diff --git a/tests/wpt/tests/css/css-color/parsing/color-valid-relative-color.html b/tests/wpt/tests/css/css-color/parsing/color-valid-relative-color.html
index 2c4dc0f8e60..142f96bcf9b 100644
--- a/tests/wpt/tests/css/css-color/parsing/color-valid-relative-color.html
+++ b/tests/wpt/tests/css/css-color/parsing/color-valid-relative-color.html
@@ -560,6 +560,7 @@
fuzzy_test_valid_color(`oklch(from oklch(0.7 0.2 300) calc(l - 0.2) c h)`, `oklch(from oklch(0.7 0.2 300) calc(-0.2 + l) c h)`);
fuzzy_test_valid_color(`oklch(from oklch(0.7 0.2 300) l calc(c / 2) h)`, `oklch(from oklch(0.7 0.2 300) l calc(0.5 * c) h)`);
fuzzy_test_valid_color(`oklch(from oklch(0.7 0.2 300) l c calc(h * 2.5))`, `oklch(from oklch(0.7 0.2 300) l c calc(2.5 * h))`);
+ fuzzy_test_valid_color(`oklch(from red calc(1 / l) c h)`);
// Testing with 'none'.
fuzzy_test_valid_color(`oklch(from oklch(0.7 0.45 30) none none none)`);
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/at-container-style-serialization.html b/tests/wpt/tests/css/css-conditional/container-queries/at-container-style-serialization.html
index a30acef9ac2..bd9d23a4b70 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/at-container-style-serialization.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/at-container-style-serialization.html
@@ -26,7 +26,7 @@
["style(--foo: )", "Empty declaration value - spaces"],
["style(--foo: )", "Empty declaration value"],
["style(--foo)", "No declaration value"],
- ["style((--FOO: BAR) or ( prop: val ))", "Unknown CSS property after 'or'"],
+ ["style((--FOO: BAR) or ( prop: val ))", "Unknown CSS property after 'or'"],
["style (--foo: bar)", "Not a style function with space before '('"],
["style(--foo: bar baz)", "Spaces preserved in custom property value"],
["style(--foo: 2.100)", "Original string number in custom property value"]
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/at-container-overflowing-parsing.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-overflowing-parsing.html
index 5c15a825853..5c15a825853 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/at-container-overflowing-parsing.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-overflowing-parsing.html
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/at-container-overflowing-serialization.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-overflowing-serialization.html
index f55cfeb6343..f55cfeb6343 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/at-container-overflowing-serialization.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-overflowing-serialization.html
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/at-container-snapped-parsing.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-snapped-parsing.html
index 0a8fe50bc38..0a8fe50bc38 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/at-container-snapped-parsing.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-snapped-parsing.html
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/at-container-snapped-serialization.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-snapped-serialization.html
index 59cc3d37f4f..59cc3d37f4f 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/at-container-snapped-serialization.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-snapped-serialization.html
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/at-container-stuck-parsing.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-stuck-parsing.html
index a3a1f01458d..a3a1f01458d 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/at-container-stuck-parsing.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-stuck-parsing.html
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/at-container-stuck-serialization.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-stuck-serialization.html
index d5abede45c2..d5abede45c2 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/at-container-stuck-serialization.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/at-container-stuck-serialization.html
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/container-type-scroll-state-computed.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-computed.html
index 4e80712beab..4e80712beab 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/container-type-scroll-state-computed.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-computed.html
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/container-type-scroll-state-containment.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-containment.html
index cc1af5a08eb..cc1af5a08eb 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/container-type-scroll-state-containment.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-containment.html
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/container-type-scroll-state-parsing.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-parsing.html
index 7f3779bc39d..7f3779bc39d 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/container-type-scroll-state-parsing.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/container-type-scroll-state-parsing.html
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state-initially-snapped.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-initially-snapped.html
index 64a171c361e..64a171c361e 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state-initially-snapped.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-initially-snapped.html
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state-initially-stuck.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-initially-stuck.html
index c0d59b61e76..c0d59b61e76 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state-initially-stuck.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-initially-stuck.html
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state-snapped-change.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-change.html
index 6e9843b8b75..6e9843b8b75 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state-snapped-change.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-change.html
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state-snapped-container-type-change.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-container-type-change.html
index 556e4c2445b..4eb5de2679e 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state-snapped-container-type-change.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-container-type-change.html
@@ -1,6 +1,6 @@
<!DOCTYPE html>
<title>@container: scroll-state(snapped) property changes</title>
-<link rel="help" href="https://drafts.csswg.org/css-conditional-5/#container-rule">
+<link rel="help" href="https://drafts.csswg.org/css-conditional-5/#snapped">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/css-conditional/container-queries/support/cq-testcommon.js"></script>
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state-snapped-none.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-none.html
index 8c7aae56beb..8c7aae56beb 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state-snapped-none.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-none.html
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state-snapped-snap-changing.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-snap-changing.html
index 161c2e1368d..161c2e1368d 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state-snapped-snap-changing.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-snap-changing.html
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state-snapped-wm.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-wm.html
index b6703e81142..b6703e81142 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state-snapped-wm.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-snapped-wm.html
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-container-type-change.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-container-type-change.html
new file mode 100644
index 00000000000..9c6df648322
--- /dev/null
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-container-type-change.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<title>@container: scroll-state(stuck) matching changes with container-type changes</title>
+<link rel="help" href="https://drafts.csswg.org/css-conditional-5/#stuck">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-conditional/container-queries/support/cq-testcommon.js"></script>
+<script src="/css/css-transitions/support/helper.js"></script>
+<style>
+ #filler {
+ height: 10000px;
+ }
+ #stuck {
+ container-name: initially-stuck;
+ container-type: scroll-state;
+ position: sticky;
+ bottom: 0;
+ }
+
+ span {
+ --stuck: no;
+ @container initially-stuck scroll-state(stuck: bottom) {
+ --stuck: yes;
+ }
+ }
+</style>
+<div id="filler"></div>
+<div id="stuck">
+ <span id="target">My container is stuck</span>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ promise_test(async t => {
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(target).getPropertyValue("--stuck"), "yes",
+ "Initially stuck");
+
+ stuck.style.containerType = "initial";
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(target).getPropertyValue("--stuck"), "no",
+ "container-type removed");
+
+ stuck.style.containerType = "";
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(target).getPropertyValue("--stuck"), "yes",
+ "container-type back to scroll-state");
+ }, "Check that scroll-state(stuck: bottom) evaluation changes with container-type changes");
+</script>
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-writing-direction.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-writing-direction.html
new file mode 100644
index 00000000000..eb0c1c4a84e
--- /dev/null
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-stuck-writing-direction.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<title>@container: scroll-state(stuck) matching writing-direction of query container</title>
+<link rel="help" href="https://drafts.csswg.org/css-conditional-5/#stuck">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-conditional/container-queries/support/cq-testcommon.js"></script>
+<script src="/css/css-transitions/support/helper.js"></script>
+<style>
+ #filler {
+ height: 10000px;
+ }
+ #stuck {
+ container-type: scroll-state;
+ position: sticky;
+ bottom: 0;
+ width: 100px;
+ height: 100px;
+ background: lime;
+ }
+ #target {
+ writing-mode: horizontal-tb;
+ direction: ltr;
+ width: 100px;
+ height: 100px;
+ background: orange;
+ }
+ @container scroll-state(stuck: inline-start) {
+ #target { --stuck: inline-start }
+ }
+ @container scroll-state(stuck: inline-end) {
+ #target { --stuck: inline-end }
+ }
+ @container scroll-state(stuck: block-start) {
+ #target { --stuck: block-start }
+ }
+ @container scroll-state(stuck: block-end) {
+ #target { --stuck: block-end }
+ }
+</style>
+<div id="filler"></div>
+<div id="stuck">
+ <div id="target"></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ promise_test(async t => {
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(target).getPropertyValue("--stuck"), "block-end");
+ }, "bottom edge matching block-end for horizontal-tb/ltr");
+
+ promise_test(async t => {
+ stuck.style.writingMode = "vertical-lr";
+ stuck.style.direction = "ltr";
+ assert_equals(getComputedStyle(target).getPropertyValue("--stuck"), "inline-end");
+ }, "bottom edge matching inline-end for vertical-lr/ltr");
+
+ promise_test(async t => {
+ stuck.style.writingMode = "vertical-rl";
+ stuck.style.direction = "ltr";
+ assert_equals(getComputedStyle(target).getPropertyValue("--stuck"), "inline-end");
+ }, "bottom edge matching inline-end for vertical-rl/ltr");
+
+ promise_test(async t => {
+ stuck.style.writingMode = "vertical-lr";
+ stuck.style.direction = "rtl";
+ assert_equals(getComputedStyle(target).getPropertyValue("--stuck"), "inline-start");
+ }, "bottom edge matching inline-start for vertical-lr/rtl");
+
+ promise_test(async t => {
+ stuck.style.writingMode = "vertical-rl";
+ stuck.style.direction = "rtl";
+ assert_equals(getComputedStyle(target).getPropertyValue("--stuck"), "inline-start");
+ }, "bottom edge matching inline-start for vertical-rl/rtl");
+
+ promise_test(async t => {
+ stuck.style.writingMode = "horizontal-tb";
+ stuck.style.direction = "rtl";
+ assert_equals(getComputedStyle(target).getPropertyValue("--stuck"), "block-end");
+ }, "bottom edge matching block-end for horizontal-tb/rtl");
+
+</script>
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state-target-query-change.html b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-target-query-change.html
index 33459f470b9..33459f470b9 100644
--- a/tests/wpt/tests/css/css-conditional/container-queries/scroll-state-target-query-change.html
+++ b/tests/wpt/tests/css/css-conditional/container-queries/scroll-state/scroll-state-target-query-change.html
diff --git a/tests/wpt/tests/css/css-conditional/container-queries/size-container-writing-mode-change.html b/tests/wpt/tests/css/css-conditional/container-queries/size-container-writing-mode-change.html
new file mode 100644
index 00000000000..dd709388b7d
--- /dev/null
+++ b/tests/wpt/tests/css/css-conditional/container-queries/size-container-writing-mode-change.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>CSS Container Queries Test: size container writing-mode change</title>
+<link rel="help" href="https://drafts.csswg.org/css-conditional-5/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ container-type: size;
+ width: 500px;
+ height: 300px;
+ }
+ #target {
+ @container (inline-size = 300px) {
+ color: green;
+ }
+ @container (inline-size = 500px) {
+ color: red;
+ }
+ }
+</style>
+<div id="container">
+ <div id="target">Should be green</div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(target).color, "rgb(255, 0, 0)");
+ }, "Initial horizontal writing-mode");
+
+ test(() => {
+ container.style.writingMode = "vertical-lr";
+ assert_equals(getComputedStyle(target).color, "rgb(0, 128, 0)");
+ }, "Vertical writing-mode changes logical query evaluation");
+</script>
diff --git a/tests/wpt/tests/css/css-multicol/crashtests/text-box-trim-end-and-widows.html b/tests/wpt/tests/css/css-multicol/crashtests/text-box-trim-end-and-widows.html
new file mode 100644
index 00000000000..8ff033342c1
--- /dev/null
+++ b/tests/wpt/tests/css/css-multicol/crashtests/text-box-trim-end-and-widows.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="http://crbug.com/41494433">
+<div style="columns:2; column-fill:auto; height:100px; text-box-trim:trim-end; line-height:50px; orphans:1; widows:2;">
+ <br>
+ <br>
+ <br>
+ <br>
+</div>
diff --git a/tests/wpt/tests/css/css-overflow/line-clamp/reference/webkit-line-clamp-050-ref.html b/tests/wpt/tests/css/css-overflow/line-clamp/reference/webkit-line-clamp-050-ref.html
new file mode 100644
index 00000000000..1fa0720aeaf
--- /dev/null
+++ b/tests/wpt/tests/css/css-overflow/line-clamp/reference/webkit-line-clamp-050-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<style>
+ .clamp {
+ display: block;
+ padding: 10px;
+ border: solid 3px;
+ width: 100px;
+ }
+ .clamp div {
+ border: medium solid green;
+ padding: 15px;
+ }
+</style>
+<div class="clamp">
+ Line1
+ <div>Line2…</div>
+</div>
diff --git a/tests/wpt/tests/css/css-overflow/line-clamp/webkit-line-clamp-050.html b/tests/wpt/tests/css/css-overflow/line-clamp/webkit-line-clamp-050.html
new file mode 100644
index 00000000000..973871b72d8
--- /dev/null
+++ b/tests/wpt/tests/css/css-overflow/line-clamp/webkit-line-clamp-050.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#propdef--webkit-line-clamp">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/pull/10816">
+<link rel="match" href="reference/webkit-line-clamp-050-ref.html">
+<style>
+ .clamp {
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
+ overflow: hidden;
+ padding: 10px;
+ border: solid 3px;
+ width: 100px;
+ }
+ .clamp div {
+ border: medium solid green;
+ padding: 15px;
+ }
+ span {
+ /* TODO: Remove once we don't paint clamped lines */
+ color: transparent;
+ }
+</style>
+<div class="clamp">
+ Line1
+ <div>Line2<br><span>Line3</span></div>
+ <span>Line4</span>
+ <div>Line5<br>Line6</div>
+ Line7
+</div>
diff --git a/tests/wpt/tests/css/css-pseudo/first-line-below-float.html b/tests/wpt/tests/css/css-pseudo/first-line-below-float.html
new file mode 100644
index 00000000000..2e32513e9c7
--- /dev/null
+++ b/tests/wpt/tests/css/css-pseudo/first-line-below-float.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-pseudo-4/#first-text-line">
+<meta name="assert" content="Floats are not part of lines, so if a float is too wide to fit any inline content beside it, the first formatted line goes below it">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
+<style>
+ .container {
+ width: 100px;
+ height: 100px;
+ font: 50px/50px Ahem;
+ color: red;
+ background: red;
+ }
+ .container::first-line {
+ color: green;
+ }
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="container">
+ <div style="float:left; width:100px; height:50px; background:green;"></div>
+ xx
+</div>
diff --git a/tests/wpt/tests/css/css-pseudo/parsing/the-check-pseudo-element.tentative.html b/tests/wpt/tests/css/css-pseudo/parsing/the-check-pseudo-element.tentative.html
new file mode 100644
index 00000000000..70f35091bc9
--- /dev/null
+++ b/tests/wpt/tests/css/css-pseudo/parsing/the-check-pseudo-element.tentative.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS ::check Pseudo-Element Test</title>
+<link rel="help" href="https://github.com/w3c/csswg-drafts/pull/10986">
+<meta name="assert" content="This test checks the validity of the ::check pseudo element selector." />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script>
+test_valid_selector("::check");
+test_valid_selector("*::check", "::check");
+test_valid_selector("foo.bar[baz]::check");
+test_invalid_selector("::check *");
+
+// Combinations
+test_invalid_selector("::check::check");
+
+test_invalid_selector("::before::check");
+test_invalid_selector("::after::check");
+test_invalid_selector("::marker::check");
+test_invalid_selector("::placeholder::check");
+
+test_invalid_selector("::check::before");
+test_invalid_selector("::check::after");
+test_valid_selector("::check::marker");
+test_invalid_selector("::check::placeholder");
+
+test_invalid_selector("::slotted(*)::check::slotted(*)");
+test_valid_selector("::slotted(*)::check");
+
+test_valid_selector("::part(foo)::check");
+</script>
diff --git a/tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-001.tentative.html b/tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-001.tentative.html
index 209a47298e3..858a8e5abb7 100644
--- a/tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-001.tentative.html
+++ b/tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-001.tentative.html
@@ -56,7 +56,7 @@
test.innerHTML = '';
styles = getComputedStyle(target);
assert_equals(styles.getPropertyValue('color'), green);
- }, name);
+ });
</script>
</body>
diff --git a/tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-002.tentative.html b/tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-002.tentative.html
index 36fafcb1dcc..76b726a0a4f 100644
--- a/tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-002.tentative.html
+++ b/tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-002.tentative.html
@@ -58,7 +58,7 @@
test.replaceChildren();
styles = getComputedStyle(target);
assert_equals(styles.getPropertyValue('color'), green);
- }, name);
+ });
</script>
</body>
diff --git a/tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-003.tentative.html b/tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-003.tentative.html
index 9914e452088..0b1d710d770 100644
--- a/tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-003.tentative.html
+++ b/tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-003.tentative.html
@@ -57,7 +57,7 @@
test.textContent = '';
styles = getComputedStyle(target);
assert_equals(styles.getPropertyValue('color'), green);
- }, name);
+ });
</script>
</body>
diff --git a/tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-004.tentative.html b/tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-004.tentative.html
index 669162050aa..f4fd54f3d48 100644
--- a/tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-004.tentative.html
+++ b/tests/wpt/tests/css/css-scoping/has-slotted-functional-changing-004.tentative.html
@@ -64,7 +64,7 @@
span.remove();
styles = getComputedStyle(target);
assert_equals(styles.getPropertyValue('color'), green);
- }, name);
+ });
</script>
</body>
diff --git a/tests/wpt/tests/css/css-scroll-anchoring/start-edge-in-block-layout-direction.html b/tests/wpt/tests/css/css-scroll-anchoring/start-edge-in-block-layout-direction.html
index 043844d0564..09b1655f86c 100644
--- a/tests/wpt/tests/css/css-scroll-anchoring/start-edge-in-block-layout-direction.html
+++ b/tests/wpt/tests/css/css-scroll-anchoring/start-edge-in-block-layout-direction.html
@@ -17,6 +17,8 @@ html.rtl { direction: rtl; }
html.horz { writing-mode: horizontal-tb; }
html.vlr { writing-mode: vertical-lr; }
html.vrl { writing-mode: vertical-rl; }
+html.slr { writing-mode: sideways-lr; }
+html.srl { writing-mode: sideways-rl; }
.horz.ltr .cx2, .vlr .cx2 { left: 100vw; }
.horz.rtl .cx2, .vrl .cx2 { right: 100vw; }
@@ -138,4 +140,28 @@ test(() => {
});
}, "Vertical-RL RTL.");
+test(() => {
+ CORNERS.forEach((corner) => {
+ runCase("slr ltr", 1, -1, true, -30, 0, corner);
+ });
+}, "Sideways-LR LTR.");
+
+test(() => {
+ CORNERS.forEach((corner) => {
+ runCase("slr rtl", 1, 1, true, -30, 0, corner);
+ });
+}, "Sideways-LR RTL.");
+
+test(() => {
+ CORNERS.forEach((corner) => {
+ runCase("srl ltr", -1, 1, true, 30, 0, corner);
+ });
+}, "Sideways-RL LTR.");
+
+test(() => {
+ CORNERS.forEach((corner) => {
+ runCase("srl rtl", -1, -1, true, 30, 0, corner);
+ });
+}, "Sideways-RL RTL.");
+
</script>
diff --git a/tests/wpt/tests/css/css-sizing/animation/height-interpolation.html b/tests/wpt/tests/css/css-sizing/animation/height-interpolation.html
index 75e0977fa11..7539dcb0161 100644
--- a/tests/wpt/tests/css/css-sizing/animation/height-interpolation.html
+++ b/tests/wpt/tests/css/css-sizing/animation/height-interpolation.html
@@ -121,4 +121,19 @@ test_no_interpolation({
to: 'fit-content',
});
+let new_style_text = `
+ .target {
+ height: auto;
+ }
+`;
+let new_style = document.createElement("style");
+new_style.append(new_style_text);
+document.head.append(new_style);
+test_no_interpolation({
+ property: 'height',
+ from: neutralKeyframe,
+ to: '100px',
+});
+new_style.remove();
+
</script>
diff --git a/tests/wpt/tests/css/css-sizing/keyword-sizes-on-inline-block.html b/tests/wpt/tests/css/css-sizing/keyword-sizes-on-inline-block.html
index a66e118c203..d91d8e6ed9c 100644
--- a/tests/wpt/tests/css/css-sizing/keyword-sizes-on-inline-block.html
+++ b/tests/wpt/tests/css/css-sizing/keyword-sizes-on-inline-block.html
@@ -1,5 +1,5 @@
<!DOCTYPE html>
-<title>Keyword sizes on floated element</title>
+<title>Keyword sizes on inline-block</title>
<link rel="author" title="Oriol Brufau" href="obrufau@igalia.com">
<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#sizing-values">
<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#sizing-values">
diff --git a/tests/wpt/tests/css/css-sizing/stretch/abspos-1.html b/tests/wpt/tests/css/css-sizing/stretch/abspos-1.html
new file mode 100644
index 00000000000..a64f0d05fdf
--- /dev/null
+++ b/tests/wpt/tests/css/css-sizing/stretch/abspos-1.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/4028">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<style>
+ #reference-overlapped-red {
+ position: absolute;
+ background-color: red;
+ width: 100px;
+ height: 100px;
+ z-index: -1;
+ }
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="reference-overlapped-red"></div>
+
+<div style="width: 100px; height: 100px; position: relative;">
+ <div style="position: absolute; width: stretch; height: 100px; background: green;">
+ </div>
+</div>
diff --git a/tests/wpt/tests/css/css-sizing/stretch/abspos-2.html b/tests/wpt/tests/css/css-sizing/stretch/abspos-2.html
new file mode 100644
index 00000000000..80d815113d1
--- /dev/null
+++ b/tests/wpt/tests/css/css-sizing/stretch/abspos-2.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/4028">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<style>
+ #reference-overlapped-red {
+ position: absolute;
+ background-color: red;
+ width: 100px;
+ height: 100px;
+ z-index: -1;
+ }
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="reference-overlapped-red"></div>
+
+<div style="width: 100px; height: 200px; position: relative;">
+ <div
+ style="width: 100%; height: stretch; position: absolute; bottom: 100px; background: green;">
+ </div>
+</div>
diff --git a/tests/wpt/tests/css/css-sizing/stretch/bfc-next-to-float-1.html b/tests/wpt/tests/css/css-sizing/stretch/bfc-next-to-float-1.html
new file mode 100644
index 00000000000..9c2a60e6c01
--- /dev/null
+++ b/tests/wpt/tests/css/css-sizing/stretch/bfc-next-to-float-1.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/4028">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<style>
+ #reference-overlapped-red {
+ position: absolute;
+ background-color: red;
+ width: 100px;
+ height: 100px;
+ z-index: -1;
+ }
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="reference-overlapped-red"></div>
+
+<div style="width:200px; margin-left: -100px;">
+ <div style="float: left; width: 100px; height: 100px;"></div>
+ <div
+ style="display: flow-root; width: stretch; height: 100px; background: green;">
+ </div>
+</div>
diff --git a/tests/wpt/tests/css/css-sizing/stretch/block-height-1.html b/tests/wpt/tests/css/css-sizing/stretch/block-height-1.html
new file mode 100644
index 00000000000..94960f15b96
--- /dev/null
+++ b/tests/wpt/tests/css/css-sizing/stretch/block-height-1.html
@@ -0,0 +1,128 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-width">
+<script src='/resources/testharness.js'></script>
+<script src='/resources/testharnessreport.js'></script>
+<script src="/resources/check-layout-th.js"></script>
+<meta name="assert" content="Checks the behaviour of stretch in various configurations.">
+<style>
+.content {
+ width: 20px;
+ height: 20px;
+ background: lime;
+}
+.tall-content {
+ width: 20px;
+ height: 120px;
+ background: lime;
+}
+</style>
+<body onload="checkLayout('[data-expected-height]')">
+
+<div style="height: 100px;">
+ <div data-expected-height=100 style="display: block; height: stretch;">
+ <div class=content></div>
+ </div>
+</div>
+
+<div style="height: 100px;">
+ <div data-expected-height=100 style="display: flex; height: stretch;">
+ <div class=content></div>
+ </div>
+</div>
+
+<div style="height: 100px;">
+ <div data-expected-height=100 style="display: grid; height: stretch;">
+ <div class=content></div>
+ </div>
+</div>
+
+<!-- As the height of the container is indefinite, stretch is treated as auto. -->
+<div style="height: 100%;">
+ <div data-expected-height=20 style="display: block; height: stretch;">
+ <div class=content></div>
+ </div>
+</div>
+
+<div style="height: 100%;">
+ <div data-expected-height=20 style="display: flex; height: stretch;">
+ <div class=content></div>
+ </div>
+</div>
+
+<div style="height: 100%;">
+ <div data-expected-height=20 style="display: grid; height: stretch;">
+ <div class=content></div>
+ </div>
+</div>
+
+<div style="height: 100px;">
+ <div data-expected-height=100 style="display: block; min-height: stretch;">
+ <div class=content></div>
+ </div>
+</div>
+
+<div style="height: 100px;">
+ <div data-expected-height=100 style="display: flex; min-height: stretch;">
+ <div class=content></div>
+ </div>
+</div>
+
+<div style="height: 100px;">
+ <div data-expected-height=100 style="display: grid; min-height: stretch;">
+ <div class=content></div>
+ </div>
+</div>
+
+<div style="height: 100%;">
+ <div data-expected-height=20 style="display: block; min-height: stretch;">
+ <div class=content></div>
+ </div>
+</div>
+
+<div style="height: 100%;">
+ <div data-expected-height=20 style="display: flex; min-height: stretch;">
+ <div class=content></div>
+ </div>
+</div>
+
+<div style="height: 100%;">
+ <div data-expected-height=20 style="display: grid; min-height: stretch;">
+ <div class=content></div>
+ </div>
+</div>
+
+<div style="height: 100px;">
+ <div data-expected-height=100 style="display: block; max-height: stretch;">
+ <div class=tall-content></div>
+ </div>
+</div>
+
+<div style="height: 100px;">
+ <div data-expected-height=100 style="display: flex; max-height: stretch;">
+ <div class=tall-content></div>
+ </div>
+</div>
+
+<div style="height: 100px;">
+ <div data-expected-height=100 style="display: grid; max-height: stretch;">
+ <div class=tall-content></div>
+ </div>
+</div>
+
+<div style="height: 100%;">
+ <div data-expected-height=120 style="display: block; max-height: stretch;">
+ <div class=tall-content></div>
+ </div>
+</div>
+
+<div style="height: 100%;">
+ <div data-expected-height=120 style="display: flex; max-height: stretch;">
+ <div class=tall-content></div>
+ </div>
+</div>
+
+<div style="height: 100%;">
+ <div data-expected-height=120 style="display: grid; max-height: stretch;">
+ <div class=tall-content></div>
+ </div>
+</div>
diff --git a/tests/wpt/tests/css/css-sizing/stretch/block-height-2.html b/tests/wpt/tests/css/css-sizing/stretch/block-height-2.html
new file mode 100644
index 00000000000..7028adf9054
--- /dev/null
+++ b/tests/wpt/tests/css/css-sizing/stretch/block-height-2.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing">
+<script src='/resources/testharness.js'></script>
+<script src='/resources/testharnessreport.js'></script>
+<script src="/resources/check-layout-th.js"></script>
+<meta name="assert" content="Checks the behaviour of stretch in various configurations.">
+
+<body onload="checkLayout('[data-expected-height]')">
+
+<div style="height: 200px; border: solid;">
+ <div style="height: stretch; margin: 10px;" data-expected-height="180"></div>
+</div>
+
+<!--
+
+Chrome fails the following test, which is a variation of example 9 in the spec. Safari passes.
+
+From https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing, height:stretch for blocks behaves as
+"""
+100% but applying the resulting size to its margin box instead of the box indicated by box-sizing. For this purpose, auto margins are treated as zero, and furthermore, for block-level boxes in particular, if its block-start/block-end margin would be adjoining to its parent’s block-start/block-end margin if its parent’s sizing properties all had their initial values, then ***its block-start/block-end margin is treated as zero.***
+"""
+
+So the spec demands that the child has 0px margins and as a corollary, has 300px inner and outer height.
+
+But Blink gives it an inner height of 200px and margins as specified (25px/75px).
+-->
+<div style="height: 300px; outline: 1px solid; margin: 10px 0px 10px 0px;">
+ <div
+ style="height: stretch; margin: 25px 0px 75px 0px; outline: 2px dashed blue;"
+ data-expected-height="300"></div>
+</div>
diff --git a/tests/wpt/tests/css/css-sizing/stretch/min-width-1.html b/tests/wpt/tests/css/css-sizing/stretch/min-width-1.html
new file mode 100644
index 00000000000..a1a39073e88
--- /dev/null
+++ b/tests/wpt/tests/css/css-sizing/stretch/min-width-1.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-width">
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<p>Test passes if there is a filled green square.</p>
+<div style="width: 100px;">
+ <div style="width: 50px; min-width: stretch; height: 100px; background: green;"></div>
+</div>
diff --git a/tests/wpt/tests/css/css-sizing/stretch/parsing.html b/tests/wpt/tests/css/css-sizing/stretch/parsing.html
new file mode 100644
index 00000000000..1f5bd39059e
--- /dev/null
+++ b/tests/wpt/tests/css/css-sizing/stretch/parsing.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Intrinsic & Extrinsic Sizing Test: parsing stretch value</title>
+<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#sizing-values">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value("width", "stretch");
+test_valid_value("height", "stretch");
+test_valid_value("max-width", "stretch");
+test_valid_value("min-width", "stretch");
+test_valid_value("max-height", "stretch");
+test_valid_value("min-height", "stretch");
+test_valid_value("inline-size", "stretch");
+test_valid_value("block-size", "stretch");
+test_valid_value("max-inline-size", "stretch");
+test_valid_value("min-inline-size", "stretch");
+test_valid_value("max-block-size", "stretch");
+test_valid_value("min-block-size", "stretch");
+test_valid_value("flex-basis", "stretch");
+</script>
+</body>
+</html>
diff --git a/tests/wpt/tests/css/css-sizing/stretch/positioned-non-replaced-1.html b/tests/wpt/tests/css/css-sizing/stretch/positioned-non-replaced-1.html
new file mode 100644
index 00000000000..b66916b8ab4
--- /dev/null
+++ b/tests/wpt/tests/css/css-sizing/stretch/positioned-non-replaced-1.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://github.com/webcompat/web-bugs/issues/103641#issuecomment-1122414992">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1324259">
+<p>Test passes if there is a filled green square.</p>
+<style>
+#target {
+ position: absolute;
+ background: green;
+ min-width: 50px;
+ min-height: 25px;
+ width: stretch;
+ height: stretch;
+}
+</style>
+<div style="display: flow-root; position: relative; width: 150px; height: 150px; margin-top: -50px; margin-left: -50px;">
+ <div style="margin-left: 50px; margin-top: 50px;">
+ <div id="target"></div>
+ </div>
+</div>
diff --git a/tests/wpt/tests/css/css-sizing/stretch/positioned-replaced-1.html b/tests/wpt/tests/css/css-sizing/stretch/positioned-replaced-1.html
new file mode 100644
index 00000000000..60b817933d3
--- /dev/null
+++ b/tests/wpt/tests/css/css-sizing/stretch/positioned-replaced-1.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://github.com/webcompat/web-bugs/issues/103641#issuecomment-1122414992">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1324259">
+<p>Test passes if there is a filled green square.</p>
+<style>
+canvas {
+ position: absolute;
+ background: green;
+ width: stretch;
+ height: stretch;
+}
+</style>
+<div style="display: flow-root; position: relative; width: 150px; height: 150px; margin-top: -50px; margin-left: -50px;">
+ <div style="margin-left: 50px; margin-top: 50px;">
+ <canvas width="50" height="25"></canvas>
+ </div>
+</div>
diff --git a/tests/wpt/tests/css/css-text/text-indent/below-float.html b/tests/wpt/tests/css/css-text/text-indent/below-float.html
new file mode 100644
index 00000000000..a386232fd0e
--- /dev/null
+++ b/tests/wpt/tests/css/css-text/text-indent/below-float.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-text-4/#text-indent-property">
+<meta name="assert" content="Floats are not part of lines, so if a float is too wide to fit any inline content beside it, the first formatted line goes below it">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="position:relative; width:100px; height:100px; font:50px/50px Ahem; text-indent:50px; color:green; background:red;">
+ <div style="position:absolute; top:50px; width:50px; height:50px; background:green;"></div>
+ <span>
+ <div style="float:left; width:100px; height:50px; background:green;"></div>
+ x
+ </span>
+</div>
diff --git a/tests/wpt/tests/css/css-ui/crashtests/text-overflow-ellipsis-multiline-crash.html b/tests/wpt/tests/css/css-ui/crashtests/text-overflow-ellipsis-multiline-crash.html
new file mode 100644
index 00000000000..a281df3a280
--- /dev/null
+++ b/tests/wpt/tests/css/css-ui/crashtests/text-overflow-ellipsis-multiline-crash.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<style>
+div {
+ width: 5ch;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+div::first-line {
+ text-decoration: underline;
+}
+</style>
+<div>
+ <br>
+ 1234567
+</div>
diff --git a/tests/wpt/tests/css/css-ui/reference/text-overflow-ellipsis-multiline-001-ref.html b/tests/wpt/tests/css/css-ui/reference/text-overflow-ellipsis-multiline-001-ref.html
new file mode 100644
index 00000000000..a26b8260eae
--- /dev/null
+++ b/tests/wpt/tests/css/css-ui/reference/text-overflow-ellipsis-multiline-001-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<style>
+div {
+ width: 6ch;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+div.first-line {
+ color: orange;
+}
+</style>
+<div class="first-line">1234567</div>
+<div>1234567</div>
diff --git a/tests/wpt/tests/css/css-ui/text-overflow-ellipsis-multiline-001.html b/tests/wpt/tests/css/css-ui/text-overflow-ellipsis-multiline-001.html
new file mode 100644
index 00000000000..5987817a5c9
--- /dev/null
+++ b/tests/wpt/tests/css/css-ui/text-overflow-ellipsis-multiline-001.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<title>Test multiline ellipsis with `::first-line`</title>
+<link rel="match" href="reference/text-overflow-ellipsis-multiline-001-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-ui-3/#ellipsing-details">
+<style>
+div {
+ width: 6ch;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+div::first-line {
+ color: orange;
+}
+</style>
+<div>
+ 1234567<br>
+ 1234567
+</div>
diff --git a/tests/wpt/tests/css/css-values/calc-serialization-002.html b/tests/wpt/tests/css/css-values/calc-serialization-002.html
index 28a7de5cdab..a3b99cf87bb 100644
--- a/tests/wpt/tests/css/css-values/calc-serialization-002.html
+++ b/tests/wpt/tests/css/css-values/calc-serialization-002.html
@@ -139,7 +139,7 @@
);
verifySerialization(
"calc((min(10px, 20%) + max(1rem, 2%)) * 2)",
- "calc((min(10px, 20%) + max(1rem, 2%)) * 2)",
+ "calc(2 * (min(10px, 20%) + max(1rem, 2%)))",
"testing calc((min(10px, 20%) + max(1rem, 2%)) * 2)"
);
diff --git a/tests/wpt/tests/css/css-values/calc-size/animation/calc-size-height-interpolation.html b/tests/wpt/tests/css/css-values/calc-size/animation/calc-size-height-interpolation.html
index 2126bd8faed..20b7b8ba317 100644
--- a/tests/wpt/tests/css/css-values/calc-size/animation/calc-size-height-interpolation.html
+++ b/tests/wpt/tests/css/css-values/calc-size/animation/calc-size-height-interpolation.html
@@ -131,7 +131,7 @@ html.no-parent-height .parent {
{ at: 0, expect: `${expected}px` },
{ at: 0.75, expect: `${expected * 0.25 + 50 * 0.75}px` },
{ at: 1, expect: `50px` },
- { at: 1.25, expect: `${50 * 1.25 - expected * 0.25}px` },
+ { at: 1.1, expect: `${50 * 1.1 - expected * 0.1}px` },
]);
test_interpolation({
@@ -139,7 +139,7 @@ html.no-parent-height .parent {
from: 'calc-size(any, 50px)',
to: `calc-size(${keyword}, size * 2)`,
}, [
- { at: -0.1, expect: `${50 * 1.1 - expected * 0.2}px` },
+ { at: -0.05, expect: `${50 * 1.05 - expected * 0.1}px` },
{ at: 0, expect: "50px" },
{ at: 0.75, expect: `${50 * 0.25 + expected * 1.5}px` },
{ at: 1, expect: `${expected * 2}px` },
diff --git a/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-height-composition.html b/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-height-composition.html
index 22f62b8edac..9a3caa747bb 100644
--- a/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-height-composition.html
+++ b/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-height-composition.html
@@ -43,15 +43,20 @@ test_composition({
test_composition({
property: 'height',
- underlying: 'fit-content', /* ignored because the keywords aren't compatible */
- addFrom: 'min-content', /* 50px */
- addTo: '200px',
+ underlying: 'fit-content',
+ addFrom: 'min-content', /* min-content is 50px, fit-content is ignored
+ because min-content and fit-content are not
+ compatible */
+ addTo: '200px', /* combines with fit-content (50px) to be 250px */
+ /* the composited from value is a min-content size and the composited
+ to value is a fit-content size, so they cannot be interpolated,
+ and the animation is discrete */
}, [
- {at: -0.3, expect: '5px'},
+ {at: -0.3, expect: '50px'},
{at: 0, expect: '50px'},
- {at: 0.5, expect: '125px'},
- {at: 1, expect: '200px'},
- {at: 1.5, expect: '275px'},
+ {at: 0.5, expect: '250px'},
+ {at: 1, expect: '250px'},
+ {at: 1.5, expect: '250px'},
]);
</script>
</body>
diff --git a/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-max-height-composition.html b/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-max-height-composition.html
index e356fb60746..958022d4cd0 100644
--- a/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-max-height-composition.html
+++ b/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-max-height-composition.html
@@ -40,24 +40,24 @@ test_composition({
addFrom: '100px',
addTo: '200px',
}, [
- {at: -0.3, expect: 'calc-size(fit-content, 70px + size * 1)'},
- {at: 0, expect: 'calc-size(fit-content, 100px + size * 1)'},
- {at: 0.5, expect: 'calc-size(fit-content, 150px + size * 1)'},
- {at: 1, expect: 'calc-size(fit-content, 200px + size * 1)'},
- {at: 1.5, expect: 'calc-size(fit-content, 250px + size * 1)'},
+ {at: -0.3, expect: 'calc-size(fit-content, (100px + size) * 1.3 + (200px + size) * -0.3)'},
+ {at: 0, expect: 'calc-size(fit-content, (100px + size) * 1 + (200px + size) * 0)'},
+ {at: 0.5, expect: 'calc-size(fit-content, (100px + size) * 0.5 + (200px + size) * 0.5)'},
+ {at: 1, expect: 'calc-size(fit-content, (100px + size) * 0 + (200px + size) * 1)'},
+ {at: 1.5, expect: 'calc-size(fit-content, (100px + size) * -0.5 + (200px + size) * 1.5)'},
]);
test_composition({
property: 'max-height',
- underlying: 'fit-content', /* ignored because the keywords aren't compatible */
- addFrom: 'min-content', /* 50px */
- addTo: '200px',
+ underlying: 'fit-content', /* 50px */
+ addFrom: 'min-content', /* 50px (fit-content is ignored) */
+ addTo: '200px', /* adds to 250px, can't interpolate with from */
}, [
- {at: -0.3, expect: 'calc-size(min-content, -60px + size * 1.3)'},
- {at: 0, expect: 'calc-size(min-content, 0px + size * 1)'},
- {at: 0.5, expect: 'calc-size(min-content, 100px + size * 0.5)'},
- {at: 1, expect: 'calc-size(min-content, 200px + size * 0)'},
- {at: 1.5, expect: 'calc-size(min-content, 300px + size * -0.5)'},
+ {at: -0.3, expect: 'min-content'},
+ {at: 0, expect: 'min-content'},
+ {at: 0.5, expect: 'calc-size(fit-content, 200px + size)'},
+ {at: 1, expect: 'calc-size(fit-content, 200px + size)'},
+ {at: 1.5, expect: 'calc-size(fit-content, 200px + size)'},
]);
</script>
</body>
diff --git a/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-max-width-composition.html b/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-max-width-composition.html
index 1e540eaee64..852e1eed793 100644
--- a/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-max-width-composition.html
+++ b/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-max-width-composition.html
@@ -40,11 +40,11 @@ test_composition({
addFrom: '100px',
addTo: 'fit-content',
}, [
- {at: -0.3, expect: 'calc-size(fit-content, 230px + size * -0.3)'},
- {at: 0, expect: 'calc-size(fit-content, 200px + size * 0)'},
- {at: 0.5, expect: 'calc-size(fit-content, 150px + size * 0.5)'},
- {at: 1, expect: 'calc-size(fit-content, 100px + size * 1)'},
- {at: 1.5, expect: 'calc-size(fit-content, 50px + size * 1.5)'},
+ {at: -0.3, expect: 'calc-size(fit-content, 260px + (100px + size) * -0.3)'},
+ {at: 0, expect: 'calc-size(fit-content, 200px + (100px + size) * 0)'},
+ {at: 0.5, expect: 'calc-size(fit-content, 100px + (100px + size) * 0.5)'},
+ {at: 1, expect: 'calc-size(fit-content, 0px + (100px + size) * 1)'},
+ {at: 1.5, expect: 'calc-size(fit-content, -100px + (100px + size) * 1.5)'},
]);
test_composition({
@@ -62,15 +62,15 @@ test_composition({
test_composition({
property: 'max-width',
- underlying: 'max-content', /* ignored, not compatible */
+ underlying: 'max-content',
addFrom: '100px',
addTo: 'min-content',
}, [
- {at: -0.3, expect: 'calc-size(min-content, 130px + size * -0.3)'},
- {at: 0, expect: 'calc-size(min-content, 100px + size * 0)'},
- {at: 0.5, expect: 'calc-size(min-content, 50px + size * 0.5)'},
- {at: 1, expect: 'calc-size(min-content, 0px + size * 1)'},
- {at: 1.5, expect: 'calc-size(min-content, -50px + size * 1.5)'},
+ {at: -0.3, expect: 'calc-size(max-content, 100px + size)'},
+ {at: 0, expect: 'calc-size(max-content, 100px + size)'},
+ {at: 0.5, expect: 'min-content'},
+ {at: 1, expect: 'min-content'},
+ {at: 1.5, expect: 'min-content'},
]);
</script>
</body>
diff --git a/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-min-height-composition.html b/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-min-height-composition.html
index 520ec75aaf8..0c3b4d2c7e3 100644
--- a/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-min-height-composition.html
+++ b/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-min-height-composition.html
@@ -40,24 +40,24 @@ test_composition({
addFrom: '100px',
addTo: '200px',
}, [
- {at: -0.3, expect: 'calc-size(fit-content, 70px + size * 1)'},
- {at: 0, expect: 'calc-size(fit-content, 100px + size * 1)'},
- {at: 0.5, expect: 'calc-size(fit-content, 150px + size * 1)'},
- {at: 1, expect: 'calc-size(fit-content, 200px + size * 1)'},
- {at: 1.5, expect: 'calc-size(fit-content, 250px + size * 1)'},
+ {at: -0.3, expect: 'calc-size(fit-content, (100px + size) * 1.3 + (200px + size) * -0.3)'},
+ {at: 0, expect: 'calc-size(fit-content, (100px + size) * 1 + (200px + size) * 0)'},
+ {at: 0.5, expect: 'calc-size(fit-content, (100px + size) * 0.5 + (200px + size) * 0.5)'},
+ {at: 1, expect: 'calc-size(fit-content, (100px + size) * 0 + (200px + size) * 1)'},
+ {at: 1.5, expect: 'calc-size(fit-content, (100px + size) * -0.5 + (200px + size) * 1.5)'},
]);
test_composition({
property: 'min-height',
- underlying: 'fit-content', /* ignored because the keywords aren't compatible */
+ underlying: 'fit-content',
addFrom: '200px',
addTo: 'min-content', /* 50px */
}, [
- {at: -0.3, expect: 'calc-size(min-content, 260px + size * -0.3)'},
- {at: 0, expect: 'calc-size(min-content, 200px + size * 0)'},
- {at: 0.5, expect: 'calc-size(min-content, 100px + size * 0.5)'},
- {at: 1, expect: 'calc-size(min-content, 0px + size * 1)'},
- {at: 1.5, expect: 'calc-size(min-content, -100px + size * 1.5)'},
+ {at: -0.3, expect: 'calc-size(fit-content, 200px + size)'},
+ {at: 0, expect: 'calc-size(fit-content, 200px + size)'},
+ {at: 0.5, expect: 'min-content'},
+ {at: 1, expect: 'min-content'},
+ {at: 1.5, expect: 'min-content'},
]);
</script>
</body>
diff --git a/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-min-width-composition.html b/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-min-width-composition.html
index 4f9e91394a5..2472f805526 100644
--- a/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-min-width-composition.html
+++ b/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-min-width-composition.html
@@ -40,11 +40,11 @@ test_composition({
addFrom: 'max-content',
addTo: '100px',
}, [
- {at: -0.3, expect: 'calc-size(max-content, 70px + size * 1.3)'},
- {at: 0, expect: 'calc-size(max-content, 100px + size * 1)'},
- {at: 0.5, expect: 'calc-size(max-content, 150px + size * 0.5)'},
- {at: 1, expect: 'calc-size(max-content, 200px + size * 0)'},
- {at: 1.5, expect: 'calc-size(max-content, 250px + size * -0.5)'},
+ {at: -0.3, expect: 'calc-size(max-content, (100px + size) * 1.3 + -60px)'},
+ {at: 0, expect: 'calc-size(max-content, (100px + size) * 1 + 0px)'},
+ {at: 0.5, expect: 'calc-size(max-content, (100px + size) * 0.5 + 100px)'},
+ {at: 1, expect: 'calc-size(max-content, (100px + size) * 0 + 200px)'},
+ {at: 1.5, expect: 'calc-size(max-content, (100px + size) * -0.5 + 300px)'},
]);
test_composition({
@@ -62,15 +62,16 @@ test_composition({
test_composition({
property: 'min-width',
- underlying: 'max-content', /* ignored, not compatible */
- addFrom: '100px',
- addTo: 'min-content',
+ underlying: 'max-content',
+ addFrom: '100px', /* composites to calc-size(max-content, 100px + size) */
+ addTo: 'min-content', /* underlying value ignored when compositing since not compatible */
+ /* min-content and max-content values cannot interpolate, so they animate discretely */
}, [
- {at: -0.3, expect: 'calc-size(min-content, 130px + size * -0.3)'},
- {at: 0, expect: 'calc-size(min-content, 100px + size * 0)'},
- {at: 0.5, expect: 'calc-size(min-content, 50px + size * 0.5)'},
- {at: 1, expect: 'calc-size(min-content, 0px + size * 1)'},
- {at: 1.5, expect: 'calc-size(min-content, -50px + size * 1.5)'},
+ {at: -0.3, expect: 'calc-size(max-content, 100px + size)'},
+ {at: 0, expect: 'calc-size(max-content, 100px + size)'},
+ {at: 0.5, expect: 'min-content'},
+ {at: 1, expect: 'min-content'},
+ {at: 1.5, expect: 'min-content'},
]);
</script>
</body>
diff --git a/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-width-composition.html b/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-width-composition.html
index a84e0bec3d5..529eac2f7ff 100644
--- a/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-width-composition.html
+++ b/tests/wpt/tests/css/css-values/calc-size/animation/interpolate-size-width-composition.html
@@ -56,15 +56,15 @@ test_composition({
test_composition({
property: 'width',
- underlying: 'max-content', /* ignored, not compatible */
- addFrom: '100px',
- addTo: 'auto', /* 200px */
+ underlying: 'max-content', /* 100px */
+ addFrom: '200px',
+ addTo: 'auto', /* 200px, max-content underlying is ignored */
}, [
- {at: -0.3, expect: '70px'},
- {at: 0, expect: '100px'},
- {at: 0.5, expect: '150px'},
+ {at: -0.3, expect: '300px'},
+ {at: 0, expect: '300px'},
+ {at: 0.5, expect: '200px'},
{at: 1, expect: '200px'},
- {at: 1.5, expect: '250px'},
+ {at: 1.5, expect: '200px'},
]);
</script>
</body>
diff --git a/tests/wpt/tests/css/css-values/minmax-length-percent-serialize.html b/tests/wpt/tests/css/css-values/minmax-length-percent-serialize.html
index 0a109d7c18e..5d11b850467 100644
--- a/tests/wpt/tests/css/css-values/minmax-length-percent-serialize.html
+++ b/tests/wpt/tests/css/css-values/minmax-length-percent-serialize.html
@@ -126,8 +126,8 @@ test_serialization(
test_serialization(
'max((min(10%, 30px) + 10px) * 2 + 10px, 5em + 5%)',
- 'max(10px + ((10px + min(10%, 30px)) * 2), 5% + 5em)',
- 'max(10px + ((10px + min(10%, 30px)) * 2), 5% + 80px)',
+ 'max(10px + (2 * (10px + min(10%, 30px))), 5% + 5em)',
+ 'max(10px + (2 * (10px + min(10%, 30px))), 5% + 80px)',
'85px',
prop='width');
</script>
diff --git a/tests/wpt/tests/css/css-values/round-function.html b/tests/wpt/tests/css/css-values/round-function.html
index 338ecaed904..fd35567a575 100644
--- a/tests/wpt/tests/css/css-values/round-function.html
+++ b/tests/wpt/tests/css/css-values/round-function.html
@@ -246,4 +246,9 @@ test_minus_infinity("round(down, -1, infinity)");
test_minus_zero("round(down, -1 * 0, infinity)");
test_plus_zero("round(down, 0, infinity)");
test_plus_zero("round(down, 1, infinity)");
-</script> \ No newline at end of file
+
+// In this test if the multiplication is factored into the sum first, the
+// result of the round will be incorrect, because of floating point inprecision.
+// round(down, 2.3333333 - 0.33333334, 1) = round(down, 1.99999996, 1) = 1
+test_math_used('round(down, (7 - 1) / 3, 1)', '2', {type:'number'});
+</script>
diff --git a/tests/wpt/tests/css/css-view-transitions/inline-child-with-overflow-shadow-ref.html b/tests/wpt/tests/css/css-view-transitions/inline-child-with-overflow-shadow-ref.html
new file mode 100644
index 00000000000..69ed62da57d
--- /dev/null
+++ b/tests/wpt/tests/css/css-view-transitions/inline-child-with-overflow-shadow-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: inline child with overflowing shadow</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<style>
+body {
+ background: rebeccapurple;
+ margin: 0;
+}
+
+.target {
+ width: 100px;
+ height: 200px;
+ position: absolute;
+ top: 100px;
+ left: 100px;
+ view-transition-name: target;
+}
+
+.child {
+ background: green;
+ font-size: 100px;
+ box-shadow: -20px -20px yellow;
+}
+</style>
+
+<div class=target>
+ <span class=child>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
+</div>
+
diff --git a/tests/wpt/tests/css/css-view-transitions/inline-child-with-overflow-shadow.html b/tests/wpt/tests/css/css-view-transitions/inline-child-with-overflow-shadow.html
new file mode 100644
index 00000000000..2c2d50af60c
--- /dev/null
+++ b/tests/wpt/tests/css/css-view-transitions/inline-child-with-overflow-shadow.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: inline child with overflowing shadow</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="match" href="inline-child-with-overflow-shadow-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root { view-transition-name: none; }
+::view-transition { background: rebeccapurple; }
+body {
+ margin: 0;
+}
+
+.target {
+ width: 100px;
+ height: 200px;
+ position: absolute;
+ top: 100px;
+ left: 100px;
+ view-transition-name: target;
+}
+
+.child {
+ background: green;
+ font-size: 100px;
+ box-shadow: -20px -20px yellow;
+}
+
+html::view-transition-group(target) {
+ animation-play-state: paused;
+ }
+html::view-transition-old(target),
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+}
+
+html::view-transition-old(target) {
+ opacity: 0;
+}
+
+/* None of these should apply, so make everything red if it does */
+html::view-transition-group(root) { animation: unset; opacity: 1; background: red; }
+html::view-transition-image-pair(root) { visibility: hidden }
+</style>
+
+<div class=target>
+ <span class=child>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/tests/wpt/tests/css/css-view-transitions/inline-with-offset-from-containing-block.html b/tests/wpt/tests/css/css-view-transitions/inline-with-offset-from-containing-block.html
index 026ecb240a3..6bbb8b49392 100644
--- a/tests/wpt/tests/css/css-view-transitions/inline-with-offset-from-containing-block.html
+++ b/tests/wpt/tests/css/css-view-transitions/inline-with-offset-from-containing-block.html
@@ -4,7 +4,7 @@
<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
<link rel="author" href="mailto:khushalsagar@chromium.org">
<link rel="match" href="inline-with-offset-from-containing-block-ref.html">
-<meta name="fuzzy" content="maxDifference=0-255; totalPixels=0-1400">
+<meta name="fuzzy" content="maxDifference=0-255; totalPixels=0-1500">
<script src="/common/reftest-wait.js"></script>
<script src="/common/rendering-utils.js"></script>
diff --git a/tests/wpt/tests/css/css-view-transitions/layered-capture/capture-mode-flat.tentative.html b/tests/wpt/tests/css/css-view-transitions/layered-capture/capture-mode-flat.tentative.html
new file mode 100644
index 00000000000..beed17c8973
--- /dev/null
+++ b/tests/wpt/tests/css/css-view-transitions/layered-capture/capture-mode-flat.tentative.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>Capture mode: flat</title>
+<meta name=fuzzy content="maxDifference=0-255; totalPixels=0-515">
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-2/">
+<link rel="match" href="nested-opacity-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<script src="../nested/resources/compute-test.js"></script>
+<style>
+ body {
+ margin: 0;
+ }
+ div {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+
+ .parent {
+ opacity: 0.4;
+ view-transition-name: parent;
+ view-transition-capture-mode: flat;
+ will-change: opacity;
+ }
+
+ .child {
+ top: 50px;
+ left: 50px;
+ }
+
+ ::view-transition-group(parent) {
+ animation-name: none;
+ opacity: 1;
+ }
+ ::view-transition-old(*),
+ ::view-transition-new(*) {
+ animation-play-state: paused;
+ }
+</style>
+<body>
+ <div class="parent">
+ <div class="child"></div>
+ </div>
+</body> \ No newline at end of file
diff --git a/tests/wpt/tests/css/css-view-transitions/layered-capture/capture-mode-layered.tentative.html b/tests/wpt/tests/css/css-view-transitions/layered-capture/capture-mode-layered.tentative.html
new file mode 100644
index 00000000000..d1f190343b0
--- /dev/null
+++ b/tests/wpt/tests/css/css-view-transitions/layered-capture/capture-mode-layered.tentative.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>Captured mode: layered</title>
+<meta name=fuzzy content="maxDifference=0-255; totalPixels=0-515">
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-2/">
+<link rel="match" href="nested-opacity-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<script src="../nested/resources/compute-test.js"></script>
+<style>
+ body {
+ margin: 0;
+ }
+ div {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+
+ .parent {
+ opacity: 0.7;
+ view-transition-name: parent;
+ will-change: opacity;
+ view-transition-capture-mode: layered;
+ }
+
+ .child {
+ top: 50px;
+ left: 50px;
+ }
+
+ ::view-transition-group(parent) {
+ opacity: 0.4;
+ animation-name: none;
+ }
+ ::view-transition-old(*),
+ ::view-transition-new(*) {
+ animation-play-state: paused;
+ }
+</style>
+<body>
+ <div class="parent">
+ <div class="child"></div>
+ </div>
+</body> \ No newline at end of file
diff --git a/tests/wpt/tests/css/css-view-transitions/nested/opacity-backdrop-blend-animated.tentative.html b/tests/wpt/tests/css/css-view-transitions/layered-capture/nested-opacity-backdrop-blend-animated.tentative.html
index 835f068c492..73100015cdd 100644
--- a/tests/wpt/tests/css/css-view-transitions/nested/opacity-backdrop-blend-animated.tentative.html
+++ b/tests/wpt/tests/css/css-view-transitions/layered-capture/nested-opacity-backdrop-blend-animated.tentative.html
@@ -5,7 +5,7 @@
<link rel="help" href="https://drafts.csswg.org/css-view-transitions-2/">
<link rel="match" href="nested-opacity-ref.html">
<script src="/common/reftest-wait.js"></script>
-<script src="resources/compute-test.js"></script>
+<script src="../nested/resources/compute-test.js"></script>
<style>
body {
margin: 0;
diff --git a/tests/wpt/tests/css/css-view-transitions/nested/opacity-backdrop-blend.tentative.html b/tests/wpt/tests/css/css-view-transitions/layered-capture/nested-opacity-backdrop-blend.tentative.html
index ea8acfc86b0..0042d9676f2 100644
--- a/tests/wpt/tests/css/css-view-transitions/nested/opacity-backdrop-blend.tentative.html
+++ b/tests/wpt/tests/css/css-view-transitions/layered-capture/nested-opacity-backdrop-blend.tentative.html
@@ -5,7 +5,7 @@
<link rel="help" href="https://drafts.csswg.org/css-view-transitions-2/">
<link rel="match" href="nested-opacity-ref.html">
<script src="/common/reftest-wait.js"></script>
-<script src="resources/compute-test.js"></script>
+<script src="../nested/resources/compute-test.js"></script>
<style>
body {
margin: 0;
diff --git a/tests/wpt/tests/css/css-view-transitions/nested/opacity-computed-style.tentative.html b/tests/wpt/tests/css/css-view-transitions/layered-capture/opacity-computed-style.tentative.html
index f370b7b03d2..f370b7b03d2 100644
--- a/tests/wpt/tests/css/css-view-transitions/nested/opacity-computed-style.tentative.html
+++ b/tests/wpt/tests/css/css-view-transitions/layered-capture/opacity-computed-style.tentative.html
diff --git a/tests/wpt/tests/css/css-view-transitions/nested/opacity-resets-after-done.tentative.html b/tests/wpt/tests/css/css-view-transitions/layered-capture/opacity-resets-after-done.tentative.html
index 7616638dc5e..7616638dc5e 100644
--- a/tests/wpt/tests/css/css-view-transitions/nested/opacity-resets-after-done.tentative.html
+++ b/tests/wpt/tests/css/css-view-transitions/layered-capture/opacity-resets-after-done.tentative.html
diff --git a/tests/wpt/tests/css/css-view-transitions/nested/opacity-resets-after-skip.tentative.html b/tests/wpt/tests/css/css-view-transitions/layered-capture/opacity-resets-after-skip.tentative.html
index e7a11ebe331..e7a11ebe331 100644
--- a/tests/wpt/tests/css/css-view-transitions/nested/opacity-resets-after-skip.tentative.html
+++ b/tests/wpt/tests/css/css-view-transitions/layered-capture/opacity-resets-after-skip.tentative.html
diff --git a/tests/wpt/tests/css/css-view-transitions/layered-capture/parsing/view-transition-capture-mode-invalid.tentative.html b/tests/wpt/tests/css/css-view-transitions/layered-capture/parsing/view-transition-capture-mode-invalid.tentative.html
new file mode 100644
index 00000000000..6bcd77cdae0
--- /dev/null
+++ b/tests/wpt/tests/css/css-view-transitions/layered-capture/parsing/view-transition-capture-mode-invalid.tentative.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS View Transitions Test: view-transition-capture-mode with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-2/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value("view-transition-capture-mode", "none");
+test_invalid_value("view-transition-capture-mode", "auto");
+test_invalid_value("view-transition-capture-mode", "stuff");
+</script>
+</body>
+</html>
diff --git a/tests/wpt/tests/css/css-view-transitions/layered-capture/parsing/view-transition-capture-mode-valid.tentative.html b/tests/wpt/tests/css/css-view-transitions/layered-capture/parsing/view-transition-capture-mode-valid.tentative.html
new file mode 100644
index 00000000000..2b739fcfe28
--- /dev/null
+++ b/tests/wpt/tests/css/css-view-transitions/layered-capture/parsing/view-transition-capture-mode-valid.tentative.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS View Transitions Test: view-transition-capture-mode with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-2/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value("view-transition-capture-mode", "flat");
+test_valid_value("view-transition-capture-mode", "layered");
+
+</script>
+</body>
+</html>
diff --git a/tests/wpt/tests/css/css-view-transitions/nested-elements-in-overflow-ref.html b/tests/wpt/tests/css/css-view-transitions/nested-elements-in-overflow-ref.html
new file mode 100644
index 00000000000..a05172fa40e
--- /dev/null
+++ b/tests/wpt/tests/css/css-view-transitions/nested-elements-in-overflow-ref.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: nested named element in overflow</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<style>
+body {
+ background: rebeccapurple;
+ margin: 0;
+}
+.outer {
+ width: 50px;
+ height: 100px;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+ border: 2px solid black;
+}
+.inner {
+ background: lightblue;
+ width: 50px;
+ height: 50px;
+ view-transition-name: outer;
+ position: absolute;
+ top: 25px;
+}
+.grey {
+ background: lightgrey;
+ position: relative;
+ width: 50px;
+ height: 50px;
+}
+</style>
+<div class="outer">
+ <div class="inner"></div>
+</div>
+<div class="grey"></div>
diff --git a/tests/wpt/tests/css/css-view-transitions/nested-elements-in-overflow.html b/tests/wpt/tests/css/css-view-transitions/nested-elements-in-overflow.html
new file mode 100644
index 00000000000..cce8fe8d8ff
--- /dev/null
+++ b/tests/wpt/tests/css/css-view-transitions/nested-elements-in-overflow.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<meta name="timeout" content="long">
+<title>View transitions: nested named element in overflow</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="nested-elements-in-overflow-ref.html">
+<meta name="fuzzy" content="maxDifference=0-60; totalPixels=0-500">
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root {
+ view-transition-name: none;
+}
+
+.outer {
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ view-transition-name: outer;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+}
+.inner {
+ background: lightgrey;
+ position: relative;
+ top: -50px;
+ left: -50px;
+ width: 50px;
+ height: 50px;
+ view-transition-name: inner;
+}
+
+::view-transition { background: rebeccapurple; }
+::view-transition-group(*) {
+ animation-duration: 300s;
+}
+::view-transition-group(outer) {
+ width: 50px;
+ height: 100px;
+ border: 2px solid black;
+ animation: none;
+}
+::view-transition-new(*),
+::view-transition-old(*) {
+ position: absolute;
+ inset-block-start: unset;
+ inline-size: 100%;
+ block-size: 100%;
+ object-fit: contain;
+}
+::view-transition-old(*) {
+ opacity: 0;
+ animation: none;
+}
+::view-transition-new(*) {
+ opacity: 1;
+ animation: none;
+}
+</style>
+<div class="outer">
+ <div class="inner"></div>
+</div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition().ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/tests/wpt/tests/css/css-view-transitions/new-and-old-sizes-match.html b/tests/wpt/tests/css/css-view-transitions/new-and-old-sizes-match.html
index f23f63d28ff..7245e4b42f2 100644
--- a/tests/wpt/tests/css/css-view-transitions/new-and-old-sizes-match.html
+++ b/tests/wpt/tests/css/css-view-transitions/new-and-old-sizes-match.html
@@ -4,7 +4,7 @@
<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
<link rel="author" href="mailto:vmpstr@chromium.org">
<link rel="match" href="new-and-old-sizes-match-ref.html">
-<meta name="fuzzy" content="maxDifference=0-15; totalPixels=0-500">
+<meta name="fuzzy" content="maxDifference=0-25; totalPixels=0-1500">
<script src="/common/reftest-wait.js"></script>
<style>
.box {
diff --git a/tests/wpt/tests/css/css-view-transitions/outer-padding-inner-background-ref.html b/tests/wpt/tests/css/css-view-transitions/outer-padding-inner-background-ref.html
new file mode 100644
index 00000000000..7c7ee533f5c
--- /dev/null
+++ b/tests/wpt/tests/css/css-view-transitions/outer-padding-inner-background-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<style>
+:root { background: rebeccapurple; }
+.target {
+ width: 200px;
+ height: 200px;
+ contain: paint;
+ view-transition-name: target;
+ padding: 20px;
+}
+
+.child {
+ width: 100px;
+ height: 200px;
+ position: relative;
+ background: green;
+}
+</style>
+
+<div class=target>
+ <div class=child>
+ </div>
+</div>
+
diff --git a/tests/wpt/tests/css/css-view-transitions/outer-padding-inner-background.html b/tests/wpt/tests/css/css-view-transitions/outer-padding-inner-background.html
new file mode 100644
index 00000000000..6bbcf514ab4
--- /dev/null
+++ b/tests/wpt/tests/css/css-view-transitions/outer-padding-inner-background.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: named element has padding, inner element has background</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="match" href="outer-padding-inner-background-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root { view-transition-name: none; }
+::view-transition { background: rebeccapurple; }
+.target {
+ width: 200px;
+ height: 200px;
+ view-transition-name: target;
+ padding: 20px;
+}
+
+.child {
+ width: 100px;
+ height: 100px;
+ position: relative;
+ background: green;
+}
+
+html::view-transition-group(target) {
+ animation-play-state: paused;
+ }
+html::view-transition-old(target),
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+}
+
+html::view-transition-new(target) {
+ position: relative;
+ top: 100px;
+}
+
+/* None of these should apply, so make everything red if it does */
+html::view-transition-group(root) { animation: unset; opacity: 1; background: red; }
+html::view-transition-image-pair(root) { visibility: hidden }
+</style>
+
+<div class=target>
+ <div class=child>
+ </div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/tests/wpt/tests/css/filter-effects/backdrop-filter-plus-filter.html b/tests/wpt/tests/css/filter-effects/backdrop-filter-plus-filter.html
index 546786d8e60..5c83faae868 100644
--- a/tests/wpt/tests/css/filter-effects/backdrop-filter-plus-filter.html
+++ b/tests/wpt/tests/css/filter-effects/backdrop-filter-plus-filter.html
@@ -4,6 +4,7 @@
<link rel="author" href="mailto:masonf@chromium.org">
<link rel="help" href="https://drafts.fxtf.org/filter-effects-2/#BackdropFilterProperty">
<link rel="match" href="backdrop-filter-plus-filter-ref.html">
+<meta name=fuzzy content="maxDifference=0-1; totalPixels=0-210">
<p>Expected: A green box with an overlapping purple box.<br>
The overlapping portion of the boxes should be bright magenta.<br>
diff --git a/tests/wpt/tests/custom-elements/CustomElementRegistry.html b/tests/wpt/tests/custom-elements/CustomElementRegistry.html
index 5b75fc651fc..87da806bcab 100644
--- a/tests/wpt/tests/custom-elements/CustomElementRegistry.html
+++ b/tests/wpt/tests/custom-elements/CustomElementRegistry.html
@@ -11,6 +11,8 @@
<div id="log"></div>
<script>
+const moveBefore_supported = ("moveBefore" in Node.prototype);
+
test(function () {
assert_true('define' in CustomElementRegistry.prototype, '"define" exists on CustomElementRegistry.prototype');
assert_true('define' in customElements, '"define" exists on window.customElements');
@@ -273,7 +275,9 @@ test(function () {
}
});
customElements.define('element-with-proxy-prototype', constructor);
- assert_array_equals(calls, ['connectedCallback', 'disconnectedCallback', 'adoptedCallback', 'attributeChangedCallback']);
+ assert_array_equals(calls,
+ moveBefore_supported ? ['connectedCallback', 'disconnectedCallback', 'connectedMoveCallback', 'adoptedCallback', 'attributeChangedCallback'] :
+ ['connectedCallback', 'disconnectedCallback', 'adoptedCallback', 'attributeChangedCallback']);
}, 'customElements.define must get callbacks of the constructor prototype');
test(function () {
@@ -305,7 +309,10 @@ test(function () {
}
});
assert_throws_js(TypeError, function () { customElements.define('element-with-throwing-callback', constructor); });
- assert_array_equals(calls, ['connectedCallback', 'disconnectedCallback', 'adoptedCallback'],
+ assert_array_equals(calls,
+ moveBefore_supported ?
+ ['connectedCallback', 'disconnectedCallback', 'connectedMoveCallback', 'adoptedCallback'] :
+ ['connectedCallback', 'disconnectedCallback', 'adoptedCallback'],
'customElements.define must not get callbacks after one of the conversion throws');
}, 'customElements.define must rethrow an exception thrown while converting a callback value to Function callback type');
@@ -332,11 +339,14 @@ test(function () {
}
});
customElements.define('element-with-attribute-changed-callback', proxy);
- assert_array_equals(prototypeCalls, [1, 'connectedCallback', 2, 'disconnectedCallback', 3, 'adoptedCallback', 4, 'attributeChangedCallback']);
+ assert_array_equals(prototypeCalls,
+ moveBefore_supported ?
+ [1, 'connectedCallback', 2, 'disconnectedCallback', 3, 'connectedMoveCallback', 4, 'adoptedCallback', 5, 'attributeChangedCallback'] :
+ [1, 'connectedCallback', 2, 'disconnectedCallback', 3, 'adoptedCallback', 4, 'attributeChangedCallback']);
assert_array_equals(constructorCalls, [0, 'prototype',
- 5, 'observedAttributes',
- 6, 'disabledFeatures',
- 7, 'formAssociated']);
+ 6, 'observedAttributes',
+ 7, 'disabledFeatures',
+ 8, 'formAssociated']);
}, 'customElements.define must get "observedAttributes" property on the constructor prototype when "attributeChangedCallback" is present');
test(function () {
@@ -492,6 +502,10 @@ test(function () {
'"formAssociated" on the constructor');
assert_array_equals(
prototypeCalls,
+ moveBefore_supported ? ['connectedCallback', 'disconnectedCallback', 'connectedMoveCallback', 'adoptedCallback',
+ 'attributeChangedCallback', 'formAssociatedCallback',
+ 'formResetCallback', 'formDisabledCallback',
+ 'formStateRestoreCallback'] :
['connectedCallback', 'disconnectedCallback', 'adoptedCallback',
'attributeChangedCallback', 'formAssociatedCallback',
'formResetCallback', 'formDisabledCallback',
@@ -521,7 +535,10 @@ test(function () {
});
assert_throws_exactly(err,
() => customElements.define('element-with-throwing-callback-2', proxy));
- assert_array_equals(calls, ['connectedCallback', 'disconnectedCallback',
+ assert_array_equals(calls, moveBefore_supported ? ['connectedCallback', 'disconnectedCallback', 'connectedMoveCallback',
+ 'adoptedCallback', 'attributeChangedCallback',
+ 'formAssociatedCallback', 'formResetCallback',
+ 'formDisabledCallback'] : ['connectedCallback', 'disconnectedCallback',
'adoptedCallback', 'attributeChangedCallback',
'formAssociatedCallback', 'formResetCallback',
'formDisabledCallback'],
@@ -538,7 +555,9 @@ test(function () {
});
assert_throws_js(TypeError,
() => customElements.define('element-with-throwing-callback-3', proxy));
- assert_array_equals(calls2, ['connectedCallback', 'disconnectedCallback',
+ assert_array_equals(calls2, moveBefore_supported ? ['connectedCallback', 'disconnectedCallback', 'connectedMoveCallback',
+ 'adoptedCallback', 'attributeChangedCallback',
+ 'formAssociatedCallback', 'formResetCallback'] : ['connectedCallback', 'disconnectedCallback',
'adoptedCallback', 'attributeChangedCallback',
'formAssociatedCallback', 'formResetCallback'],
'customElements.define must not get callbacks after one of the get throws');
diff --git a/tests/wpt/tests/digital-credentials/allow-attribute.https.html b/tests/wpt/tests/digital-credentials/allow-attribute.https.html
index 41223626808..d988e94cd23 100644
--- a/tests/wpt/tests/digital-credentials/allow-attribute.https.html
+++ b/tests/wpt/tests/digital-credentials/allow-attribute.https.html
@@ -8,6 +8,8 @@
<script src="/common/get-host-info.sub.js"></script>
<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>
const hostInfo = get_host_info();
const iframeDetails = [
diff --git a/tests/wpt/tests/digital-credentials/support/iframe.html b/tests/wpt/tests/digital-credentials/support/iframe.html
index 6f3c072f29f..3ec761e08a6 100644
--- a/tests/wpt/tests/digital-credentials/support/iframe.html
+++ b/tests/wpt/tests/digital-credentials/support/iframe.html
@@ -69,5 +69,6 @@
}
}
+ test_driver.set_test_context(parent);
window.addEventListener("message", messageListener);
</script>
diff --git a/tests/wpt/tests/dom/nodes/moveBefore/tentative/custom-element-move-reactions.html b/tests/wpt/tests/dom/nodes/moveBefore/tentative/custom-element-move-reactions.html
new file mode 100644
index 00000000000..ce0302cd734
--- /dev/null
+++ b/tests/wpt/tests/dom/nodes/moveBefore/tentative/custom-element-move-reactions.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<title>Node.moveBefore custom element reactions</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+;
+</script>
+
+<body>
+ <section id="section"></section>
+ <script>
+ promise_test(async t => {
+ const ce = document.getElementById("ce");
+ let reactions = [];
+ const element_name = `ce-${performance.now()}`;
+ customElements.define(element_name,
+ class MockCustomElement extends HTMLElement {
+ connectedCallback() { reactions.push("connected"); }
+ disconnectedCallback() { reactions.push("disconnected"); }
+ });
+ const element = document.createElement(element_name);
+ t.add_cleanup(() => element.remove());
+ document.body.append(element);
+ await Promise.resolve();
+ reactions = [];
+ document.getElementById("section").moveBefore(element, null);
+ await Promise.resolve();
+ assert_array_equals(reactions, ["disconnected", "connected"]);
+ }, "the disconnected/connected callbacks should be called when no other callback is defined");
+
+ promise_test(async t => {
+ const ce = document.getElementById("ce");
+ let reactions = [];
+ const element_name = `ce-${performance.now()}`;
+ customElements.define(element_name,
+ class MockCustomElement extends HTMLElement {
+ connectedCallback() { reactions.push(this.isConnected); }
+ disconnectedCallback() { reactions.push(this.isConnected); }
+ });
+ const element = document.createElement(element_name);
+ t.add_cleanup(() => element.remove());
+ document.body.append(element);
+ await Promise.resolve();
+ reactions = [];
+ document.getElementById("section").moveBefore(element, null);
+ await Promise.resolve();
+ assert_array_equals(reactions, [true, true]);
+ }, "the element should stay connected during the callbacks");
+
+ promise_test(async t => {
+ const ce = document.getElementById("ce");
+ let reactions = [];
+ const element_name = `ce-${performance.now()}`;
+ customElements.define(element_name,
+ class MockCustomElement extends HTMLElement {
+ connectedMoveCallback() { reactions.push("connectedMove"); }
+ connectedCallback() { reactions.push("connected"); }
+ disconnectedCallback() { reactions.push("disconnected"); }
+ });
+ const element = document.createElement(element_name);
+ t.add_cleanup(() => element.remove());
+ document.body.append(element);
+ await Promise.resolve();
+ reactions = [];
+ document.getElementById("section").moveBefore(element, null);
+ await Promise.resolve();
+ assert_array_equals(reactions, ["connectedMove"]);
+ }, "When connectedMoveCallback is defined, it is called instead of disconnectedCallback/connectedCallback");
+
+ promise_test(async t => {
+ const ce = document.getElementById("ce");
+ let reactions = [];
+ const outer_element_name = `ce-${performance.now()}-outer`;
+ const inner_element_name = `ce-${performance.now()}-inner`;
+ customElements.define(outer_element_name,
+ class MockCustomElement extends HTMLElement {
+ connectedCallback() { reactions.push("outer connected"); }
+ disconnectedCallback() { reactions.push("outer disconnected"); }
+ });
+ customElements.define(inner_element_name,
+ class MockCustomElement extends HTMLElement {
+ connectedCallback() { reactions.push("inner connected"); }
+ disconnectedCallback() { reactions.push("inner disconnected"); }
+ });
+ const outer = document.createElement(outer_element_name);
+ const inner = document.createElement(inner_element_name);
+ t.add_cleanup(() => outer.remove());
+ outer.append(inner);
+ document.body.append(outer);
+ await Promise.resolve();
+ reactions = [];
+ document.getElementById("section").moveBefore(outer, null);
+ await Promise.resolve();
+ assert_array_equals(reactions, ["outer disconnected", "outer connected", "inner disconnected", "inner connected"]);
+ }, "Reactions to atomic move are called in order of element, not in order of operation");
+
+</script>
+</body>
diff --git a/tests/wpt/tests/editing/data/inserthtml.js b/tests/wpt/tests/editing/data/inserthtml.js
index bdfc1d34020..412fa63ef31 100644
--- a/tests/wpt/tests/editing/data/inserthtml.js
+++ b/tests/wpt/tests/editing/data/inserthtml.js
@@ -487,7 +487,7 @@ var browserTests = [
{"inserthtml":[false,false,"",false,false,""]}],
["<p>{}<br></p>",
[["inserthtml","<!--abc-->"]],
- "<p><!--abc-->{}</p>",
+ "<p><!--abc-->{}<br></p>",
[true],
{"inserthtml":[false,false,"",false,false,""]}],
["<p><!--foo-->{}<span><br></span><!--bar--></p>",
@@ -521,13 +521,13 @@ var browserTests = [
{"inserthtml":[false,false,"",false,false,""]}],
["<p><br>{}</p>",
[["inserthtml","<!--abc-->"]],
- "<p><!--abc--></p>",
+ "<p><!--abc--><br></p>",
[true],
{"inserthtml":[false,false,"",false,false,""]}],
["<p><!--foo--><span><br></span>{}<!--bar--></p>",
[["inserthtml","abc"]],
["<p><!--foo--><span>abc</span><!--bar--></p>",
- "<p><!--foo-->abc<span></span><!--bar--></p>"],
+ "<p><!--foo-->abc<!--bar--></p>"],
[true],
{"inserthtml":[false,false,"",false,false,""]}],
["<p><!--foo--><span><br></span>{}<!--bar--></p>",
@@ -535,7 +535,7 @@ var browserTests = [
"<p><!--foo--><span><!--abc-->{}<br></span><!--bar--></p>",
[true],
{"inserthtml":[false,false,"",false,false,""]}],
-// TODO: Fix the insertion not occurring at carot position.
+// TODO: Fix the insertion not occurring at caret position.
// Updating the expected value of below two tests as to how other
// browsers behave these tests will still fail and since the insertion
// position is incorrect br tag gets removed, after fixing this it shouldn't.
@@ -552,40 +552,34 @@ var browserTests = [
["<pre>12[]34</pre>",
[["inserthtml","<pre>abc</pre>"]],
- ["<pre>12abc34</pre>",
- "<pre>12abc34<br></pre>"],
+ "<pre>12abc34</pre>",
[true],
{"inserthtml":[false,false,"",false,false,""]}],
["<pre>1[23]4</pre>",
[["inserthtml","<pre>abc</pre>"]],
- ["<pre>1abc4</pre>",
- "<pre>1abc4<br></pre>"],
+ "<pre>1abc4</pre>",
[true],
{"inserthtml":[false,false,"",false,false,""]}],
["<pre>[1234]</pre>",
[["inserthtml","<pre>abc</pre>"]],
- ["<pre>abc</pre>",
- "<pre>abc<br></pre>"],
+ "<pre>abc</pre>",
[true],
{"inserthtml":[false,false,"",false,false,""]}],
["<pre contenteditable=\"false\"><span contenteditable>[1234]</span></pre>",
[["inserthtml","<pre>abc</pre>"]],
- ["<pre contenteditable=\"false\"><span contenteditable=\"\">abc</span></pre>",
- "<pre contenteditable=\"false\"><span contenteditable=\"\">abc<br></span></pre>"],
+ "<pre contenteditable=\"false\"><span contenteditable=\"\">abc</span></pre>",
[true],
{"inserthtml":[false,false,"",false,false,""]}],
// Empty inline elements shouldn't be deleted if they are inserted intentionally
["<div>a[]b</div>",
[["inserthtml","<span></span>"]],
- ["<div>a<span></span>b</div>",
- "<div>a<span></span>b<br></div>"],
+ "<div>a<span></span>b</div>",
[true],
{"inserthtml":[false,false,"",false,false,""]}],
["<div>a[]c</div>",
[["inserthtml","<span class=\"s1\"></span>b<span class=\"s2\"></span>"]],
- ["<div>a<span class=\"s1\"></span>b<span class=\"s2\"></span>c</div>",
- "<div>a<span class=\"s1\"></span>b<span class=\"s2\"></span>c<br></div>"],
+ "<div>a<span class=\"s1\"></span>b<span class=\"s2\"></span>c</div>",
[true],
{"inserthtml":[false,false,"",false,false,""]}],
["{}",
diff --git a/tests/wpt/tests/editing/data/insertimage.js b/tests/wpt/tests/editing/data/insertimage.js
index b62331e1520..f92a5709191 100644
--- a/tests/wpt/tests/editing/data/insertimage.js
+++ b/tests/wpt/tests/editing/data/insertimage.js
@@ -357,8 +357,7 @@ var browserTests = [
{"insertimage":[false,false,"",false,false,""]}],
["<div>{}<br></div>",
[["insertimage","/img/lion.svg"]],
- ["<div><img src=\"/img/lion.svg\"></div>",
- "<div><img src=\"/img/lion.svg\"><br></div>"],
+ "<div><img src=\"/img/lion.svg\"></div>",
[true],
{}],
["<div><b>{}<br></b></div>",
diff --git a/tests/wpt/tests/editing/data/inserttext.js b/tests/wpt/tests/editing/data/inserttext.js
index 8fa8127f2df..568b467f153 100644
--- a/tests/wpt/tests/editing/data/inserttext.js
+++ b/tests/wpt/tests/editing/data/inserttext.js
@@ -1248,36 +1248,32 @@ var browserTests = [
{"inserttext":[false,false,"",false,false,""]}],
["<br>{}",
[["inserttext","a"]],
- ["a", "a<br>"],
+ "a",
[true],
{"inserttext":[false,false,"",false,false,""]}],
["abc<br>{}",
[["inserttext","d"]],
- ["abcd", "abcd<br>"],
+ "abcd",
[true],
{"inserttext":[false,false,"",false,false,""]}],
["abc<br>{}<br>",
[["inserttext","d"]],
- ["abc<br>d",
- "abc<br>d<br>"],
+ "abc<br>d",
[true],
{"inserttext":[false,false,"",false,false,""]}],
["<span contenteditable=false>abc</span><br>{}",
[["inserttext","d"]],
- ["<span contenteditable=\"false\">abc</span>d",
- "<span contenteditable=\"false\">abc</span>d<br>"],
+ "<span contenteditable=\"false\">abc</span>d",
[true],
{"inserttext":[false,false,"",false,false,""]}],
["<div contenteditable=false><span contenteditable><br>{}</span></div>",
[["inserttext","a"]],
- ["<div contenteditable=\"false\"><span contenteditable=\"\">a</span></div>",
- "<div contenteditable=\"false\"><span contenteditable=\"\">a<br></span></div>"],
+ "<div contenteditable=\"false\"><span contenteditable=\"\">a</span></div>",
[true],
{"inserttext":[false,false,"",false,false,""]}],
["<div contenteditable=false><span contenteditable>abc<br>{}</span></div>",
[["inserttext","d"]],
- ["<div contenteditable=\"false\"><span contenteditable=\"\">abcd</span></div>",
- "<div contenteditable=\"false\"><span contenteditable=\"\">abcd<br></span></div>"],
+ "<div contenteditable=\"false\"><span contenteditable=\"\">abcd</span></div>",
[true],
{"inserttext":[false,false,"",false,false,""]}],
["<div style=white-space:pre>foo[]bar</div>",
@@ -1349,15 +1345,20 @@ var browserTests = [
// element.
["<p>a<br>{}<span></span></p>",
[["inserttext","b"]],
- "<p>ab<br><span></span></p>",
+ "<p>ab<span></span></p>",
[true],
{"inserttext":[false,false,"",false,false,""]}],
-// In this case, the <span> element after <br> element is visible and is put in
-// the second line, but for backward compatibility, typing text should be
-// inserted before the <br> element.
+// In these cases, the <span> element after <br> element is visible and is put in
+// the second line and caret is in the second line. Therefore, new text should
+// be inserted into the second line.
["<p style=\"white-space:pre-wrap\">a<br>{}<span style=\"padding:1px\"></span></p>",
[["inserttext","b"]],
- "<p style=\"white-space:pre-wrap\">ab<br><span style=\"padding:1px\"></span></p>",
+ "<p style=\"white-space:pre-wrap\">a<br>b<span style=\"padding:1px\"></span></p>",
+ [true],
+ {"inserttext":[false,false,"",false,false,""]}],
+["<div style=\"white-space:pre-wrap\">a<br>{}<span style=\"padding:1px\"></span><p>c</p></div>",
+ [["inserttext","b"]],
+ "<div style=\"white-space:pre-wrap\">a<br>b<span style=\"padding:1px\"></span><p>c</p></div>",
[true],
{"inserttext":[false,false,"",false,false,""]}],
// Similar case if <br> follows last visible thing and is followed by invisible
@@ -1368,13 +1369,6 @@ var browserTests = [
"<div>a<br><span></span><p>bc</p></div>",
[true],
{"inserttext":[false,false,"",false,false,""]}],
-// And even if the <br> element is followed by visible but empty inline element,
-// should be same as previous test.
-["<div style=\"white-space:pre-wrap\">a<br>{}<span style=\"padding:1px\"></span><p>c</p></div>",
- [["inserttext","b"]],
- "<div style=\"white-space:pre-wrap\">a<br><span style=\"padding:1px\"></span><p>bc</p></div>",
- [true],
- {"inserttext":[false,false,"",false,false,""]}],
// https://bugzilla.mozilla.org/show_bug.cgi?id=1785801
["<div>abc{</div><div>}efg</div>",
[["inserttext", "d"]],
@@ -1474,75 +1468,63 @@ var browserTests = [
// selection start container.
["<div>{abc</div><div>def</div>}",
[["inserttext","g"],["inserttext","h"]],
- ["<div>gh</div>",
- "<div>gh<br></div>"],
+ "<div>gh</div>",
[true,true],
{}],
["<div>abc</div><div>{def</div>}",
[["inserttext","g"],["inserttext","h"]],
- ["<div>abc</div><div>gh</div>",
- "<div>abc</div><div>gh<br></div>"],
+ "<div>abc</div><div>gh</div>",
[true,true],
{}],
["<div style=display:flex><span>{abc</span><span>def</span>}</div>",
[["inserttext","g"],["inserttext","h"]],
- ["<div style=\"display:flex\"><span>gh</span></div>",
- "<div style=\"display:flex\"><span>gh<br></span></div>"],
+ "<div style=\"display:flex\"><span>gh</span></div>",
[true,true],
{}],
["<div style=display:flex><span>abc</span><span>{def</span>}</div>",
[["inserttext","g"],["inserttext","h"]],
- ["<div style=\"display:flex\"><span>abc</span><span>gh</span></div>",
- "<div style=\"display:flex\"><span>abc</span><span>gh<br></span></div>"],
+ "<div style=\"display:flex\"><span>abc</span><span>gh</span></div>",
[true,true],
{}],
["<div style=display:grid><span>{abc</span><span>def</span>}</div>",
[["inserttext","g"],["inserttext","h"]],
- ["<div style=\"display:grid\"><span>gh</span></div>",
- "<div style=\"display:grid\"><span>gh<br></span></div>"],
+ "<div style=\"display:grid\"><span>gh</span></div>",
[true,true],
{}],
["<div style=display:grid><span>abc</span><span>{def</span>}</div>",
[["inserttext","g"],["inserttext","h"]],
- ["<div style=\"display:grid\"><span>abc</span><span>gh</span></div>",
- "<div style=\"display:grid\"><span>abc</span><span>gh<br></span></div>"],
+ "<div style=\"display:grid\"><span>abc</span><span>gh</span></div>",
[true,true],
{}],
// The inline style at selection start should be preserved for typed text.
["<div><b>{abc</b></div><div>def</div>}",
[["inserttext","g"],["inserttext","h"]],
- ["<div><b>gh</b></div>",
- "<div><b>gh<br></b></div>"],
+ "<div><b>gh</b></div>",
[true,true],
{}],
["<div>abc</div><div><b>{def</b></div>}",
[["inserttext","g"],["inserttext","h"]],
- ["<div>abc</div><div><b>gh</b></div>",
- "<div>abc</div><div><b>gh<br></b></div>"],
+ "<div>abc</div><div><b>gh</b></div>",
[true,true],
{}],
["<div style=display:flex><span><b>{abc</b></span><span>def</span>}</div>",
[["inserttext","g"],["inserttext","h"]],
- ["<div style=\"display:flex\"><span><b>gh</b></span></div>",
- "<div style=\"display:flex\"><span><b>gh<br></b></span></div>"],
+ "<div style=\"display:flex\"><span><b>gh</b></span></div>",
[true,true],
{}],
["<div style=display:flex><span>abc</span><span><b>{def</b></span>}</div>",
[["inserttext","g"],["inserttext","h"]],
- ["<div style=\"display:flex\"><span>abc</span><span><b>gh</b></span></div>",
- "<div style=\"display:flex\"><span>abc</span><span><b>gh<br></b></span></div>"],
+ "<div style=\"display:flex\"><span>abc</span><span><b>gh</b></span></div>",
[true,true],
{}],
["<div style=display:grid><span><b>{abc</b></span><span>def</span>}</div>",
[["inserttext","g"],["inserttext","h"]],
- ["<div style=\"display:grid\"><span><b>gh</b></span></div>",
- "<div style=\"display:grid\"><span><b>gh<br></b></span></div>"],
+ "<div style=\"display:grid\"><span><b>gh</b></span></div>",
[true,true],
{}],
["<div style=display:grid><span>abc</span><span><b>{def</b></span>}</div>",
[["inserttext","g"],["inserttext","h"]],
- ["<div style=\"display:grid\"><span>abc</span><span><b>gh</b></span></div>",
- "<div style=\"display:grid\"><span>abc</span><span><b>gh<br></b></span></div>"],
+ "<div style=\"display:grid\"><span>abc</span><span><b>gh</b></span></div>",
[true,true],
{}],
]
diff --git a/tests/wpt/tests/editing/other/delete-before-invisible-line-break.html b/tests/wpt/tests/editing/other/delete-before-invisible-line-break.html
new file mode 100644
index 00000000000..ec88079d31e
--- /dev/null
+++ b/tests/wpt/tests/editing/other/delete-before-invisible-line-break.html
@@ -0,0 +1,154 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<meta name="variant" content="?white-space=normal">
+<meta name="variant" content="?white-space=pre">
+<meta name="variant" content="?white-space=pre-line">
+<meta name="variant" content="?white-space=pre-wrap">
+<title>Deleting content immediately before invisible line break should clean up if it's unnecessary anymore</title>
+<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>
+<script src="../include/editor-test-utils.js"></script>
+<script>
+"use strict";
+
+const searchParams = new URLSearchParams(document.location.search);
+const whiteSpace = searchParams.get("white-space");
+const useBR = whiteSpace == "normal";
+const collapseWhiteSpaces = whiteSpace == "normal" || whiteSpace == "pre-line";
+
+addEventListener("load", () => {
+ const editingHost = document.querySelector("div[contenteditable]");
+ editingHost.style.whiteSpace = whiteSpace;
+ editingHost.getBoundingClientRect();
+ editingHost.focus();
+ const utils = new EditorTestUtils(editingHost);
+
+ for (const data of [
+ {
+ initialInnerHTML: "<p>a []<br></p>",
+ expected: "<p>a</p>",
+ },
+ {
+ initialInnerHTML: "<p>a[ ]<br></p>",
+ expected: "<p>a</p>",
+ },
+ {
+ initialInnerHTML: "<p>a b[]<br></p>",
+ expected: collapseWhiteSpaces
+ ? (useBR ? ["<p>a <br></p>", "<p>a&nbsp;</p>"] : ["<p>a <br></p>", "<p>a \n</p>", "<p>a&nbsp;</p>"])
+ : "<p>a </p>",
+ },
+ {
+ initialInnerHTML: "<p>a [b]<br></p>",
+ expected: collapseWhiteSpaces
+ ? (useBR ? ["<p>a <br></p>", "<p>a&nbsp;</p>"] : ["<p>a <br></p>", "<p>a \n</p>", "<p>a&nbsp;</p>"])
+ : "<p>a </p>",
+ },
+ {
+ initialInnerHTML: "<p>a []\n</p>",
+ expected: "<p>a</p>",
+ skipIf: () => useBR,
+ },
+ {
+ initialInnerHTML: "<p>a[ ]\n</p>",
+ expected: "<p>a</p>",
+ skipIf: () => useBR,
+ },
+ {
+ initialInnerHTML: "<p>a b[]\n</p>",
+ expected: collapseWhiteSpaces
+ ? ["<p>a \n</p>", "<p>a&nbsp;</p>"]
+ : "<p>a </p>",
+ skipIf: () => useBR,
+ },
+ {
+ initialInnerHTML: "<p>a [b]\n</p>",
+ expected: collapseWhiteSpaces
+ ? ["<p>a \n</p>", "<p>a&nbsp;</p>"]
+ : "<p>a </p>",
+ skipIf: () => useBR,
+ },
+ {
+ initialInnerHTML: "<div>a []<br><div>b</div></div>",
+ expected: "<div>a<div>b</div></div>",
+ },
+ {
+ initialInnerHTML: "<div>a[ ]<br><div>b</div></div>",
+ expected: "<div>a<div>b</div></div>",
+ },
+ {
+ initialInnerHTML: "<div>a b[]<br><div>b</div></div>",
+ expected: collapseWhiteSpaces
+ ? (useBR
+ ? ["<div>a <br><div>b</div></div>", "<div>a&nbsp;<div>b</div></div>"]
+ : ["<div>a <br><div>b</div></div>", "<div>a \n<div>b</div></div>", "<div>a&nbsp;<div>b</div></div>"])
+ : "<div>a <div>b</div></div>",
+ },
+ {
+ initialInnerHTML: "<div>a [b]<br><div>b</div></div>",
+ expected: collapseWhiteSpaces
+ ? (useBR
+ ? ["<div>a <br><div>b</div></div>", "<div>a&nbsp;<div>b</div></div>"]
+ : ["<div>a <br><div>b</div></div>", "<div>a \n<div>b</div></div>", "<div>a&nbsp;<div>b</div></div>"])
+ : "<div>a <div>b</div></div>",
+ },
+ {
+ initialInnerHTML: "<div>a []\n<div>b</div></div>",
+ expected: "<div>a<div>b</div></div>",
+ skipIf: () => useBR,
+ },
+ {
+ initialInnerHTML: "<div>a[ ]\n<div>b</div></div>",
+ expected: "<div>a<div>b</div></div>",
+ skipIf: () => useBR,
+ },
+ {
+ initialInnerHTML: "<div>a b[]\n<div>b</div></div>",
+ expected: collapseWhiteSpaces
+ ? ["<div>a \n<div>b</div></div>", "<div>a&nbsp;<div>b</div></div>"]
+ : "<div>a <div>b</div></div>",
+ skipIf: () => useBR,
+ },
+ {
+ initialInnerHTML: "<div>a [b]\n<div>b</div></div>",
+ expected: collapseWhiteSpaces
+ ? ["<div>a \n<div>b</div></div>", "<div>a&nbsp;<div>b</div></div>"]
+ : "<div>a <div>b</div></div>",
+ skipIf: () => useBR,
+ },
+ ]) {
+ if (data.skipIf !== undefined && data.skipIf()) {
+ continue;
+ }
+ promise_test(async () => {
+ utils.setupEditingHost(data.initialInnerHTML);
+ document.execCommand("delete");
+ if (Array.isArray(data.expected)) {
+ assert_in_array(editingHost.innerHTML, data.expected);
+ } else {
+ assert_equals(editingHost.innerHTML, data.expected);
+ }
+ }, `document.execCommand("delete") when ${data.initialInnerHTML.replaceAll("\n", "\\n")}`);
+ promise_test(async () => {
+ utils.setupEditingHost(data.initialInnerHTML);
+ await utils.sendBackspaceKey();
+ if (Array.isArray(data.expected)) {
+ assert_in_array(editingHost.innerHTML, data.expected);
+ } else {
+ assert_equals(editingHost.innerHTML, data.expected);
+ }
+ }, `Backspace when ${data.initialInnerHTML.replaceAll("\n", "\\n")}`);
+ }
+}, {once: true});
+</script>
+</head>
+<body>
+ <div contenteditable></div>
+</body>
+</html>
diff --git a/tests/wpt/tests/editing/other/double-click-range-selection-in-floating-list-item.html b/tests/wpt/tests/editing/other/double-click-range-selection-in-floating-list-item.html
new file mode 100644
index 00000000000..898f42b9b04
--- /dev/null
+++ b/tests/wpt/tests/editing/other/double-click-range-selection-in-floating-list-item.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>
+ This test is for testing the range selection of floating list item on
+ double click.
+</title>
+<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>
+<style>
+ .fl,
+ li {
+ float: left;
+ margin-right: 40px;
+ }
+</style>
+<div>
+ <ul>
+ <li id="first">First</li>
+ <li>Second</li>
+ </ul>
+</div>
+<div>
+ <strong id="sfirst" class="fl">first</strong
+ ><strong class="fl">second</strong>
+</div>
+<script>
+ function runTests() {
+ promise_test(async () => {
+ const first = document.getElementById("first");
+ first.focus();
+ let actions = new test_driver.Actions()
+ .pointerMove(0, 0, { origin: first })
+ .pointerDown()
+ .pointerUp()
+ .pointerDown()
+ .pointerUp();
+ await actions.send();
+ const selection = window.getSelection();
+ let selectedText = selection.toString();
+ assert_equals(
+ selectedText,
+ "First",
+ "Selected Text Should be equal to first list item"
+ );
+ }, "Double click on one floating list item should not select more than one list item");
+
+ promise_test(async () => {
+ const sfirst = document.getElementById("sfirst");
+ sfirst.focus();
+ let actions = new test_driver.Actions()
+ .pointerMove(0, 0, { origin: sfirst })
+ .pointerDown()
+ .pointerUp()
+ .pointerDown()
+ .pointerUp();
+ await actions.send();
+ const selection = window.getSelection();
+ let selectedText = selection.toString();
+ assert_equals(
+ selectedText,
+ "first",
+ "Selected Text Should be equal to first list item"
+ );
+ }, "Double click on one floating strong text should not select more than one item");
+ }
+
+ window.addEventListener("load", runTests, { once: true });
+</script>
diff --git a/tests/wpt/tests/editing/other/double-click-range-selection-in-list-item.html b/tests/wpt/tests/editing/other/double-click-range-selection-in-list-item.html
new file mode 100644
index 00000000000..18dee19966a
--- /dev/null
+++ b/tests/wpt/tests/editing/other/double-click-range-selection-in-list-item.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>
+ This test is for testing the range selection of list item on double
+ click.
+</title>
+<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>
+<style>
+ .inline-block {
+ display: inline-block;
+ width: 50px;
+ height: 20px;
+ background-color: lightblue;
+ }
+</style>
+<div>
+ <ul>
+ <li id="first">First</li>
+ <li>Second</li>
+ </ul>
+</div>
+<div>
+ This is some
+ <span id="atomicinline" class="inline-block">atomicinline</span> text.
+</div>
+<script>
+ function runTests() {
+ promise_test(async () => {
+ const first = document.getElementById("first");
+ first.focus();
+ let actions = new test_driver.Actions()
+ .pointerMove(0, 0, { origin: "viewport" })
+ .pointerDown()
+ .pointerUp()
+ .pointerDown()
+ .pointerUp();
+ await actions.send();
+ const selection = window.getSelection();
+ let selectedText = selection.toString();
+ assert_equals(
+ selectedText,
+ "First",
+ "Selected Text Should be equal to first list item"
+ );
+ }, "Double click on one list item should not select more than one list item");
+
+ promise_test(async () => {
+ const atomic_inline = document.getElementById("atomicinline");
+ atomic_inline.focus();
+ let actions = new test_driver.Actions()
+ .pointerMove(0, 0, { origin: atomic_inline })
+ .pointerDown()
+ .pointerUp()
+ .pointerDown()
+ .pointerUp();
+ await actions.send();
+ const selection = window.getSelection();
+ let selectedText = selection.toString();
+ assert_equals(
+ selectedText,
+ "atomicinline",
+ "Selected Text Should be equal to atomicinline"
+ );
+ }, "Double click on one text item should select only one text item");
+ }
+
+ window.addEventListener("load", runTests, { once: true });
+</script>
diff --git a/tests/wpt/tests/editing/other/forwarddelete-before-invisible-line-break.html b/tests/wpt/tests/editing/other/forwarddelete-before-invisible-line-break.html
new file mode 100644
index 00000000000..aebfdc2899e
--- /dev/null
+++ b/tests/wpt/tests/editing/other/forwarddelete-before-invisible-line-break.html
@@ -0,0 +1,154 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<meta name="variant" content="?white-space=normal">
+<meta name="variant" content="?white-space=pre">
+<meta name="variant" content="?white-space=pre-line">
+<meta name="variant" content="?white-space=pre-wrap">
+<title>Deleting content immediately before invisible line break should clean up if it's unnecessary anymore</title>
+<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>
+<script src="../include/editor-test-utils.js"></script>
+<script>
+"use strict";
+
+const searchParams = new URLSearchParams(document.location.search);
+const whiteSpace = searchParams.get("white-space");
+const useBR = whiteSpace == "normal";
+const collapseWhiteSpaces = whiteSpace == "normal" || whiteSpace == "pre-line";
+
+addEventListener("load", () => {
+ const editingHost = document.querySelector("div[contenteditable]");
+ editingHost.style.whiteSpace = whiteSpace;
+ editingHost.getBoundingClientRect();
+ editingHost.focus();
+ const utils = new EditorTestUtils(editingHost);
+
+ for (const data of [
+ {
+ initialInnerHTML: "<p>a[] <br></p>",
+ expected: "<p>a</p>",
+ },
+ {
+ initialInnerHTML: "<p>a[ ]<br></p>",
+ expected: "<p>a</p>",
+ },
+ {
+ initialInnerHTML: "<p>a []b<br></p>",
+ expected: collapseWhiteSpaces
+ ? (useBR ? ["<p>a <br></p>", "<p>a&nbsp;</p>"] : ["<p>a <br></p>", "<p>a \n</p>", "<p>a&nbsp;</p>"])
+ : "<p>a </p>",
+ },
+ {
+ initialInnerHTML: "<p>a [b]<br></p>",
+ expected: collapseWhiteSpaces
+ ? (useBR ? ["<p>a <br></p>", "<p>a&nbsp;</p>"] : ["<p>a <br></p>", "<p>a \n</p>", "<p>a&nbsp;</p>"])
+ : "<p>a </p>",
+ },
+ {
+ initialInnerHTML: "<p>a[] \n</p>",
+ expected: "<p>a</p>",
+ skipIf: () => useBR,
+ },
+ {
+ initialInnerHTML: "<p>a[ ]\n</p>",
+ expected: "<p>a</p>",
+ skipIf: () => useBR,
+ },
+ {
+ initialInnerHTML: "<p>a []b\n</p>",
+ expected: collapseWhiteSpaces
+ ? ["<p>a \n</p>", "<p>a&nbsp;</p>"]
+ : "<p>a </p>",
+ skipIf: () => useBR,
+ },
+ {
+ initialInnerHTML: "<p>a [b]\n</p>",
+ expected: collapseWhiteSpaces
+ ? ["<p>a \n</p>", "<p>a&nbsp;</p>"]
+ : "<p>a </p>",
+ skipIf: () => useBR,
+ },
+ {
+ initialInnerHTML: "<div>a[] <br><div>b</div></div>",
+ expected: "<div>a<div>b</div></div>",
+ },
+ {
+ initialInnerHTML: "<div>a[ ]<br><div>b</div></div>",
+ expected: "<div>a<div>b</div></div>",
+ },
+ {
+ initialInnerHTML: "<div>a []b<br><div>b</div></div>",
+ expected: collapseWhiteSpaces
+ ? (useBR
+ ? ["<div>a <br><div>b</div></div>", "<div>a&nbsp;<div>b</div></div>"]
+ : ["<div>a <br><div>b</div></div>", "<div>a \n<div>b</div></div>", "<div>a&nbsp;<div>b</div></div>"])
+ : "<div>a <div>b</div></div>",
+ },
+ {
+ initialInnerHTML: "<div>a [b]<br><div>b</div></div>",
+ expected: collapseWhiteSpaces
+ ? (useBR
+ ? ["<div>a <br><div>b</div></div>", "<div>a&nbsp;<div>b</div></div>"]
+ : ["<div>a <br><div>b</div></div>", "<div>a \n<div>b</div></div>", "<div>a&nbsp;<div>b</div></div>"])
+ : "<div>a <div>b</div></div>",
+ },
+ {
+ initialInnerHTML: "<div>a[] \n<div>b</div></div>",
+ expected: "<div>a<div>b</div></div>",
+ skipIf: () => useBR,
+ },
+ {
+ initialInnerHTML: "<div>a[ ]\n<div>b</div></div>",
+ expected: "<div>a<div>b</div></div>",
+ skipIf: () => useBR,
+ },
+ {
+ initialInnerHTML: "<div>a []b\n<div>b</div></div>",
+ expected: collapseWhiteSpaces
+ ? ["<div>a \n<div>b</div></div>", "<div>a&nbsp;<div>b</div></div>"]
+ : "<div>a <div>b</div></div>",
+ skipIf: () => useBR,
+ },
+ {
+ initialInnerHTML: "<div>a [b]\n<div>b</div></div>",
+ expected: collapseWhiteSpaces
+ ? ["<div>a \n<div>b</div></div>", "<div>a&nbsp;<div>b</div></div>"]
+ : "<div>a <div>b</div></div>",
+ skipIf: () => useBR,
+ },
+ ]) {
+ if (data.skipIf !== undefined && data.skipIf()) {
+ continue;
+ }
+ promise_test(async () => {
+ utils.setupEditingHost(data.initialInnerHTML);
+ document.execCommand("forwardDelete");
+ if (Array.isArray(data.expected)) {
+ assert_in_array(editingHost.innerHTML, data.expected);
+ } else {
+ assert_equals(editingHost.innerHTML, data.expected);
+ }
+ }, `document.execCommand("forwardDelete") when ${data.initialInnerHTML.replaceAll("\n", "\\n")}`);
+ promise_test(async () => {
+ utils.setupEditingHost(data.initialInnerHTML);
+ await utils.sendDeleteKey();
+ if (Array.isArray(data.expected)) {
+ assert_in_array(editingHost.innerHTML, data.expected);
+ } else {
+ assert_equals(editingHost.innerHTML, data.expected);
+ }
+ }, `(Forward) Delete when ${data.initialInnerHTML.replaceAll("\n", "\\n")}`);
+ }
+}, {once: true});
+</script>
+</head>
+<body>
+ <div contenteditable></div>
+</body>
+</html>
diff --git a/tests/wpt/tests/editing/plaintext-only/insertText.html b/tests/wpt/tests/editing/plaintext-only/insertText.html
index 9045e04d368..664b9befb8d 100644
--- a/tests/wpt/tests/editing/plaintext-only/insertText.html
+++ b/tests/wpt/tests/editing/plaintext-only/insertText.html
@@ -36,6 +36,24 @@ addEventListener("load", () => {
for (const data of [
{
+ initialInnerHTML: "{}<br>",
+ insertText: " ",
+ expected: collapseWhiteSpaces
+ ? (useBR ? [" <br>", "&nbsp;"] : [" <br>", " \n", "&nbsp;"])
+ : " ",
+ },
+ {
+ initialInnerHTML: "{}<br>",
+ insertText: "a",
+ expected: "a",
+ },
+ {
+ initialInnerHTML: "[]\n",
+ skipIf: () => useBR,
+ insertText: "a",
+ expected: "a",
+ },
+ {
initialInnerHTML: "A[]B",
insertText: "a",
expected: "AaB",
@@ -98,9 +116,7 @@ addEventListener("load", () => {
prepareDescription: "execCommand(\"insertParagraph\")",
prepare: () => document.execCommand("insertParagraph"),
insertText: "a",
- expected: useBR
- ? ["<p><b>A</b></p><p><b>aB</b></p>", "<p><b>A</b></p><p><b>aB<br></b></p>"]
- : ["<p><b>A</b></p><p><b>aB</b></p>", "<p><b>A</b></p><p><b>aB<br></b></p>", "<p><b>A</b></p><p><b>aB\n</b></p>"],
+ expected: "<p><b>A</b></p><p><b>aB</b></p>",
},
{
initialInnerHTML: "<p><b>AB[]</b></p>",
@@ -109,9 +125,7 @@ addEventListener("load", () => {
insertText: "a",
// To keep the style of next typing even after lost focus, the placeholder line break in
// the empty paragraph after "insertParagraph" should be wrapped in the <b>.
- expected: useBR
- ? ["<p><b>AB</b></p><p><b>a</b></p>", "<p><b>AB</b></p><p><b>a<br></b></p>"]
- : ["<p><b>AB</b></p><p><b>a</b></p>", "<p><b>AB</b></p><p><b>a<br></b></p>", "<p><b>AB</b></p><p><b>a\n</b></p>"],
+ expected: "<p><b>AB</b></p><p><b>a</b></p>",
},
{
initialInnerHTML: "<p><b>[AB]</b></p>",
@@ -119,9 +133,8 @@ addEventListener("load", () => {
prepare: () => document.execCommand("insertParagraph"),
insertText: "a",
expected: useBR
- ? ["<p><b><br></b></p><p><b>a</b></p>", "<p><b><br></b></p><p><b>a<br></b></p>"]
- : ["<p><b><br></b></p><p><b>a</b></p>", "<p><b>\n</b></p><p><b>a</b></p>",
- "<p><b><br></b></p><p><b>a<br></b></p>", "<p><b>\n</b></p><p><b>a\n</b></p>"],
+ ? "<p><b><br></b></p><p><b>a</b></p>"
+ : ["<p><b><br></b></p><p><b>a</b></p>", "<p><b>\n</b></p><p><b>a</b></p>"],
},
{
initialInnerHTML: "<p><b>[]AB</b></p>",
@@ -149,9 +162,8 @@ addEventListener("load", () => {
// To keep the style of next typing even after once the paragraph becomes empty,
// the placeholder line break (if there is) should be in <b>.
expected: useBR
- ? ["<p><b>AB<br>a</b></p>", "<p><b>AB<br>a<br></b></p>"]
- : ["<p><b>AB<br>a</b></p>", "<p><b>AB<br>a<br></b></p>", "<p><b>AB\na</b></p>",
- "<p><b>AB\na\n</b></p>", "<p><b>AB\na<br></b></p>", "<p><b>AB<br>a\n</b></p>"],
+ ? "<p><b>AB<br>a</b></p>"
+ : ["<p><b>AB<br>a</b></p>", "<p><b>AB\na</b></p>"],
},
{
initialInnerHTML: "<p><b>[AB]</b></p>",
@@ -161,9 +173,8 @@ addEventListener("load", () => {
// To keep the style of next typing even after once the paragraph becomes empty,
// the placeholder line break (if there is) should be in <b>.
expected: useBR
- ? ["<p><b><br>a</b></p>", "<p><b><br>a<br></b></p>"]
- : ["<p><b><br>a</b></p>", "<p><b><br>a<br></b></p>", "<p><b>\na</b></p>", "<p><b>\na\n</b></p>",
- "<p><b><br>a\n</b></p>", "<p><b>\na<br></b></p>"],
+ ? "<p><b><br>a</b></p>"
+ : ["<p><b><br>a</b></p>", "<p><b>\na</b></p>"],
},
{
initialInnerHTML: "<p><b>[AB]</b></p>",
@@ -172,9 +183,7 @@ addEventListener("load", () => {
insertText: "a",
// To keep the style of next typing even after blur, the placeholder line break
// (if there is) should be in <b>.
- expected: useBR
- ? ["<p><b>a</b></p>", "<p><b>a<br></b></p>"]
- : ["<p><b>a</b></p>", "<p><b>a<br></b></p>", "<p><b>a\n</b></p>"],
+ expected: "<p><b>a</b></p>",
},
{
initialInnerHTML: "<p><b>A[]</b></p><p>B</p>",
@@ -186,9 +195,7 @@ addEventListener("load", () => {
},
insertText: "a",
// Moving caret shouldn't cause loosing the style.
- expected: useBR
- ? ["<p><b>a</b></p><p>B</p>", "<p><b>a<br></b></p><p>B</p>"]
- : ["<p><b>a</b></p><p>B</p>", "<p><b>a<br></b></p><p>B</p>", "<p><b>a\n</b></p><p>B</p>"],
+ expected: "<p><b>a</b></p><p>B</p>",
},
{
initialInnerHTML: "<p><b>[]A</b></p><p>B</p>",
@@ -200,9 +207,7 @@ addEventListener("load", () => {
},
insertText: "a",
// Moving caret shouldn't cause loosing the style.
- expected: useBR
- ? ["<p><b>a</b></p><p>B</p>", "<p><b>a<br></b></p><p>B</p>"]
- : ["<p><b>a</b></p><p>B</p>", "<p><b>a<br></b></p><p>B</p>", "<p><b>a\n</b></p><p>B</p>"],
+ expected: "<p><b>a</b></p><p>B</p>",
},
{
initialInnerHTML: "<p><b>[A]</b></p><p>B</p>",
@@ -214,9 +219,7 @@ addEventListener("load", () => {
},
insertText: "a",
// Moving caret shouldn't cause loosing the style.
- expected: useBR
- ? ["<p><b>a</b></p><p>B</p>", "<p><b>a<br></b></p><p>B</p>"]
- : ["<p><b>a</b></p><p>B</p>", "<p><b>a<br></b></p><p>B</p>", "<p><b>a\n</b></p><p>B</p>"],
+ expected: "<p><b>a</b></p><p>B</p>",
},
{
initialInnerHTML: "<p><b>A[]</b></b>",
@@ -228,11 +231,12 @@ addEventListener("load", () => {
},
insertText: "a",
// Moving caret shouldn't cause loosing the style.
- expected: useBR
- ? ["<p><b>A</b></p><p><b>a</b></p>", "<p><b>A</b></p><p><b>a<br></b></p>"]
- : ["<p><b>A</b></p><p><b>a</b></p>", "<p><b>A</b></p><p><b>a<br></b></p>", "<p><b>A</b></p><p><b>a\n</b></p>"],
+ expected: "<p><b>A</b></p><p><b>a</b></p>",
},
]) {
+ if (data.skipIf !== undefined && data.skipIf()) {
+ continue;
+ }
test(() => {
utils.setupEditingHost(data.initialInnerHTML);
if (data.prepare) {
@@ -244,8 +248,10 @@ addEventListener("load", () => {
} else {
assert_equals(editingHost.innerHTML, data.expected);
}
- }, `execCommand("insertText", false, "${data.insertText}") when ${data.initialInnerHTML}${
- data.prepareDescription ? ` and ${data.prepareDescription}` : ""
+ }, `execCommand("insertText", false, "${data.insertText.replaceAll("\n", "\\n")}") when ${
+ data.initialInnerHTML.replaceAll("\n", "\\n")
+ }${
+ data.prepareDescription ? ` and ${data.prepareDescription.replaceAll("\n", "\\n")}` : ""
}`);
promise_test(async t => {
utils.setupEditingHost(data.initialInnerHTML);
@@ -260,8 +266,10 @@ addEventListener("load", () => {
} else {
assert_equals(editingHost.innerHTML, data.expected);
}
- }, `Typing "${data.insertText}" when ${data.initialInnerHTML}${
- data.prepareDescription ? ` and ${data.prepareDescription}` : ""
+ }, `Typing "${data.insertText.replaceAll("\n", "\\n")}" when ${
+ data.initialInnerHTML.replaceAll("\n", "\\n")
+ }${
+ data.prepareDescription ? ` and ${data.prepareDescription.replaceAll("\n", "\\n")}` : ""
}`);
}
}, {once: true});
diff --git a/tests/wpt/tests/eyedropper/idlharness.https.window.js b/tests/wpt/tests/eyedropper/idlharness.https.window.js
new file mode 100644
index 00000000000..891d334e9f6
--- /dev/null
+++ b/tests/wpt/tests/eyedropper/idlharness.https.window.js
@@ -0,0 +1,7 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+idl_test(
+ ['eyedropper-api'],
+ [],
+);
diff --git a/tests/wpt/tests/fenced-frame/http-localhost-url.https.html b/tests/wpt/tests/fenced-frame/http-localhost-url.https.html
new file mode 100644
index 00000000000..a8b16d75c85
--- /dev/null
+++ b/tests/wpt/tests/fenced-frame/http-localhost-url.https.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>Test navigate fenced frame to http://localhost URL</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/utils.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+
+<body>
+<script>
+promise_test(async (t) => {
+ const key = token();
+ const url = generateURL("http://localhost:" + get_host_info().HTTP_PORT +
+ "/fenced-frame/resources/embeddee.html", [key]);
+ attachFencedFrame(url);
+
+ const result = await nextValueFromServer(key);
+ assert_equals(result, "PASS",
+ "The fenced frame should load a http://localhost URL.");
+}, 'http://localhost URLs can load');
+
+</script>
+</body>
+</html>
diff --git a/tests/wpt/tests/fledge/tentative/get-interest-group-auction-data.https.window.js b/tests/wpt/tests/fledge/tentative/get-interest-group-auction-data.https.window.js
index 3788045c8c2..453d0f8e642 100644
--- a/tests/wpt/tests/fledge/tentative/get-interest-group-auction-data.https.window.js
+++ b/tests/wpt/tests/fledge/tentative/get-interest-group-auction-data.https.window.js
@@ -374,15 +374,16 @@ subsetTest(promise_test, async test => {
assert_equals(ig.browserSignals.joinCount, 2, 'joinCount');
assert_equals(ig.browserSignals.bidCount, 1, 'bidCount');
- // Recency is the # of seconds since the join. We can't exactly say what it
- // is, but it shouldn't be too huge.
- assert_true(typeof ig.browserSignals.recency === 'number');
+ // RecencyMs is the # of milliseconds since the join. We can't exactly say
+ // what it is, but it shouldn't be too huge.
+ assert_true(typeof ig.browserSignals.recencyMs === 'number');
assert_between_inclusive(
- ig.browserSignals.recency, 0, 60, 'Recency is between 0 and 60 seconds');
+ ig.browserSignals.recencyMs, 0, 60000,
+ 'RecencyMs is between 0 and 60 seconds');
// It's also supposed to be an integer.
assert_equals(
- ig.browserSignals.recency, Math.round(ig.browserSignals.recency),
- 'Recency is an integer');
+ ig.browserSignals.recencyMs, Math.round(ig.browserSignals.recencyMs),
+ 'RecencyMs is an integer');
// One win. The format here depends highly on whether full ads are used or
// not.
@@ -433,15 +434,16 @@ subsetTest(promise_test, async test => {
assert_equals(ig.browserSignals.joinCount, 2, 'joinCount');
assert_equals(ig.browserSignals.bidCount, 1, 'bidCount');
- // Recency is the # of seconds since the join. We can't exactly say what it
- // is, but it shouldn't be too huge.
- assert_true(typeof ig.browserSignals.recency === 'number');
+ // RecencyMs is the # of milliseconds since the join. We can't exactly say
+ // what it is, but it shouldn't be too huge.
+ assert_true(typeof ig.browserSignals.recencyMs === 'number');
assert_between_inclusive(
- ig.browserSignals.recency, 0, 60, 'Recency is between 0 and 60 seconds');
+ ig.browserSignals.recencyMs, 0, 60000,
+ 'RecencyMs is between 0 and 60 seconds');
// It's also supposed to be an integer.
assert_equals(
- ig.browserSignals.recency, Math.round(ig.browserSignals.recency),
- 'Recency is an integer');
+ ig.browserSignals.recencyMs, Math.round(ig.browserSignals.recencyMs),
+ 'RecencyMs is an integer');
// One win. The format here depends highly on whether full ads are used or
// not.
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage-expected.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage-expected.html
new file mode 100644
index 00000000000..eea78248a83
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.filter.no_shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.no_shadow.drawImage</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage.html
new file mode 100644
index 00000000000..8e6b95ae221
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage.html
@@ -0,0 +1,845 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.filter.no_shadow.drawImage-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.no_shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.no_shadow.drawImage</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas25");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage.png b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage.png
new file mode 100644
index 00000000000..2318c1ec94e
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.drawImage.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect-expected.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect-expected.html
new file mode 100644
index 00000000000..08ed3566fd1
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.filter.no_shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.no_shadow.fillRect</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect.html
new file mode 100644
index 00000000000..5dca89e3c12
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect.html
@@ -0,0 +1,767 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.filter.no_shadow.fillRect-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.no_shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.no_shadow.fillRect</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas25");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect.png b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect.png
new file mode 100644
index 00000000000..2318c1ec94e
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.fillRect.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern-expected.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern-expected.html
new file mode 100644
index 00000000000..22c84f42e89
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.filter.no_shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.no_shadow.pattern</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern.html
new file mode 100644
index 00000000000..6b3c4c6a589
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern.html
@@ -0,0 +1,871 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.filter.no_shadow.pattern-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.no_shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.no_shadow.pattern</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas25");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern.png b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern.png
new file mode 100644
index 00000000000..2318c1ec94e
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.no_shadow.pattern.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage-expected.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage-expected.html
new file mode 100644
index 00000000000..2072348f904
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.filter.shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.shadow.drawImage</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage.html
new file mode 100644
index 00000000000..f6872b22127
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage.html
@@ -0,0 +1,897 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.filter.shadow.drawImage-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.shadow.drawImage</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas25");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage.png b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage.png
new file mode 100644
index 00000000000..fde78773116
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.drawImage.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect-expected.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect-expected.html
new file mode 100644
index 00000000000..1e119bcbde5
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.filter.shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.shadow.fillRect</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect.html
new file mode 100644
index 00000000000..1c68c0e4540
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect.html
@@ -0,0 +1,819 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.filter.shadow.fillRect-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.shadow.fillRect</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas25");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect.png b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect.png
new file mode 100644
index 00000000000..fde78773116
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.fillRect.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern-expected.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern-expected.html
new file mode 100644
index 00000000000..f45fe82c302
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.filter.shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.shadow.pattern</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern.html
new file mode 100644
index 00000000000..1e3f14fb9a3
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern.html
@@ -0,0 +1,923 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.filter.shadow.pattern-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.shadow.pattern</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas25");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern.png b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern.png
new file mode 100644
index 00000000000..fde78773116
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.filter.shadow.pattern.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage-expected.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage-expected.html
new file mode 100644
index 00000000000..923d8360a9d
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.no_filter.no_shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.no_shadow.drawImage</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html
new file mode 100644
index 00000000000..31e0fba7918
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html
@@ -0,0 +1,845 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.no_filter.no_shadow.drawImage-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.no_shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.no_shadow.drawImage</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas25");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.png b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.png
new file mode 100644
index 00000000000..ce392a1dccc
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect-expected.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect-expected.html
new file mode 100644
index 00000000000..c809e56cac3
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.no_filter.no_shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.no_shadow.fillRect</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html
new file mode 100644
index 00000000000..e14c336868e
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html
@@ -0,0 +1,767 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.no_filter.no_shadow.fillRect-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.no_shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.no_shadow.fillRect</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas25");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.png b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.png
new file mode 100644
index 00000000000..ce392a1dccc
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern-expected.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern-expected.html
new file mode 100644
index 00000000000..f052442a637
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.no_filter.no_shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.no_shadow.pattern</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html
new file mode 100644
index 00000000000..6f8159466db
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html
@@ -0,0 +1,871 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.no_filter.no_shadow.pattern-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.no_shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.no_shadow.pattern</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas25");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern.png b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern.png
new file mode 100644
index 00000000000..ce392a1dccc
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.no_shadow.pattern.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage-expected.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage-expected.html
new file mode 100644
index 00000000000..ad07c35d310
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.no_filter.shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.shadow.drawImage</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage.html
new file mode 100644
index 00000000000..84527f5a283
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage.html
@@ -0,0 +1,897 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.no_filter.shadow.drawImage-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.shadow.drawImage</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas25");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage.png b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage.png
new file mode 100644
index 00000000000..aca03a61b22
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.drawImage.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect-expected.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect-expected.html
new file mode 100644
index 00000000000..e16a5fcf458
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.no_filter.shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.shadow.fillRect</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect.html
new file mode 100644
index 00000000000..46bc366c8ac
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect.html
@@ -0,0 +1,819 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.no_filter.shadow.fillRect-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.shadow.fillRect</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas25");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect.png b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect.png
new file mode 100644
index 00000000000..aca03a61b22
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.fillRect.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern-expected.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern-expected.html
new file mode 100644
index 00000000000..01e1d4d7b26
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.no_filter.shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.shadow.pattern</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern.html b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern.html
new file mode 100644
index 00000000000..e636330c59f
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern.html
@@ -0,0 +1,923 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.no_filter.shadow.pattern-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.shadow.pattern</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-in</div>
+ <canvas id="canvas1" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" 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 = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" 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.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = document.getElementById("canvas25");
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern.png b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern.png
new file mode 100644
index 00000000000..aca03a61b22
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/compositing/2d.composite.grid.no_filter.shadow.pattern.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/element/text/2d.text.draw.fill.basic.png b/tests/wpt/tests/html/canvas/element/text/2d.text.draw.fill.basic.png
index 8021427a07d..70d7b046cb2 100644
--- a/tests/wpt/tests/html/canvas/element/text/2d.text.draw.fill.basic.png
+++ b/tests/wpt/tests/html/canvas/element/text/2d.text.draw.fill.basic.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/element/text/2d.text.draw.fill.maxWidth.large.png b/tests/wpt/tests/html/canvas/element/text/2d.text.draw.fill.maxWidth.large.png
index 8021427a07d..70d7b046cb2 100644
--- a/tests/wpt/tests/html/canvas/element/text/2d.text.draw.fill.maxWidth.large.png
+++ b/tests/wpt/tests/html/canvas/element/text/2d.text.draw.fill.maxWidth.large.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/element/text/2d.text.draw.fill.rtl.png b/tests/wpt/tests/html/canvas/element/text/2d.text.draw.fill.rtl.png
index 8021427a07d..70d7b046cb2 100644
--- a/tests/wpt/tests/html/canvas/element/text/2d.text.draw.fill.rtl.png
+++ b/tests/wpt/tests/html/canvas/element/text/2d.text.draw.fill.rtl.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/element/text/2d.text.draw.stroke.basic.png b/tests/wpt/tests/html/canvas/element/text/2d.text.draw.stroke.basic.png
index d4f6dc1ee88..fb3b5b830d3 100644
--- a/tests/wpt/tests/html/canvas/element/text/2d.text.draw.stroke.basic.png
+++ b/tests/wpt/tests/html/canvas/element/text/2d.text.draw.stroke.basic.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-position.tentative.html b/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-position.tentative.html
new file mode 100644
index 00000000000..cc6f366e072
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-position.tentative.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<title>Canvas test: 2d.text.measure.text-clusters-position.tentative</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">
+<style>
+@font-face {
+ font-family: CanvasTest;
+ src: url("/fonts/CanvasTest.ttf");
+}
+</style>
+<body class="show_output">
+
+<h1>2d.text.measure.text-clusters-position.tentative</h1>
+<p class="desc">Test that TextMetrics::getTextClusters() returns clusters that are positioned according to the target align and baseline passed as options.</p>
+
+
+<span style="font-family: CanvasTest; position: absolute; visibility: hidden">A</span>
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="500" height="500"><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');
+
+ await document.fonts.ready;
+ ctx.font = '40px CanvasTest';
+ const text = 'E';
+
+ // Origin for all the measurements is placed at the top left corner.
+ ctx.textAlign = 'left';
+ ctx.textBaseline = 'top';
+ let tm = ctx.measureText(text);
+
+ // X position.
+ _assertSame(Math.abs(tm.getTextClusters({align: 'left'})[0].x), 0, "Math.abs(tm.getTextClusters({align: 'left'})[\""+(0)+"\"].x)", "0");
+ _assertSame(tm.getTextClusters({align: 'center'})[0].x, 20, "tm.getTextClusters({align: 'center'})[\""+(0)+"\"].x", "20");
+ _assertSame(tm.getTextClusters({align: 'right'})[0].x, 40, "tm.getTextClusters({align: 'right'})[\""+(0)+"\"].x", "40");
+
+ // Y position.
+ _assertSame(Math.abs(tm.getTextClusters({baseline: 'top'})[0].y), 0, "Math.abs(tm.getTextClusters({baseline: 'top'})[\""+(0)+"\"].y)", "0");
+ _assertSame(tm.getTextClusters({baseline: 'middle'})[0].y, 20, "tm.getTextClusters({baseline: 'middle'})[\""+(0)+"\"].y", "20");
+ _assertSame(tm.getTextClusters({baseline: 'bottom'})[0].y, 40, "tm.getTextClusters({baseline: 'bottom'})[\""+(0)+"\"].y", "40");
+ _assertSame(tm.getTextClusters({baseline: 'alphabetic'})[0].y, 30, "tm.getTextClusters({baseline: 'alphabetic'})[\""+(0)+"\"].y", "30");
+
+}, "Test that TextMetrics::getTextClusters() returns clusters that are positioned according to the target align and baseline passed as options.");
+</script>
+
diff --git a/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-range.tentative.html b/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-range.tentative.html
new file mode 100644
index 00000000000..effa53c4c95
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-range.tentative.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<title>Canvas test: 2d.text.measure.text-clusters-range.tentative</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">
+<style>
+@font-face {
+ font-family: CanvasTest;
+ src: url("/fonts/CanvasTest.ttf");
+}
+</style>
+<body class="show_output">
+
+<h1>2d.text.measure.text-clusters-range.tentative</h1>
+<p class="desc">Test that getTextClusters() and fillTextCluster() correctly render different ranges of the input text.</p>
+
+
+<span style="font-family: CanvasTest; position: absolute; visibility: hidden">A</span>
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="400" height="300"><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');
+
+ // Renders all the clusters in the list from position (x, y).
+ function renderClusters(clusters, x, y) {
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+ }
+
+ await document.fonts.ready;
+
+ ctx.font = '50px CanvasTest';
+ ctx.textAlign = 'left';
+ ctx.textBaseline = 'top';
+ const text = 'EEEEE';
+ let tm = ctx.measureText(text);
+
+ // Background color.
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ ctx.fillStyle = '#0f0';
+
+ // Without the first character.
+ renderClusters(tm.getTextClusters(1, 5), 0, 0);
+ _assertPixelApprox(canvas, 5,5, 255,0,0,255, 2);
+ _assertPixelApprox(canvas, 55,5, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 105,5, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 155,5, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 205,5, 0,255,0,255, 2);
+ // Without the last character.
+ renderClusters(tm.getTextClusters(0, 4), 0, 100);
+ _assertPixelApprox(canvas, 5,105, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 55,105, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 105,105, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 155,105, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 205,105, 255,0,0,255, 2);
+ // Only the middle character.
+ renderClusters(tm.getTextClusters(2, 3), 0, 150);
+ _assertPixelApprox(canvas, 5,155, 255,0,0,255, 2);
+ _assertPixelApprox(canvas, 55,155, 255,0,0,255, 2);
+ _assertPixelApprox(canvas, 105,155, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 155,155, 255,0,0,255, 2);
+ _assertPixelApprox(canvas, 205,155, 255,0,0,255, 2);
+
+}, "Test that getTextClusters() and fillTextCluster() correctly render different ranges of the input text.");
+</script>
+
diff --git a/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative-expected.html b/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative-expected.html
new file mode 100644
index 00000000000..967ae7e4636
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative-expected.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<title>Canvas test: 2d.text.measure.text-clusters-rendering-align.tentative</title>
+<h1 style="font-size: 20px;">2d.text.measure.text-clusters-rendering-align.tentative</h1>
+<p class="desc">Test that fillTextCluster() correctly positions the text, taking into account the textAlign from the context at the time the text was measured.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(3, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>ctx_align_left</div>
+ <canvas id="canvas0" width="250" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = 'left';
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ ctx.fillText(text, x, y);
+ </script>
+</span>
+
+<span>
+ <div>ctx_align_center</div>
+ <canvas id="canvas1" width="250" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = 'center';
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ ctx.fillText(text, x, y);
+ </script>
+</span>
+
+<span>
+ <div>ctx_align_right</div>
+ <canvas id="canvas2" width="250" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = 'right';
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ ctx.fillText(text, x, y);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative.html b/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative.html
new file mode 100644
index 00000000000..159efb4fee4
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-align.tentative.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.text.measure.text-clusters-rendering-align.tentative-expected.html">
+<title>Canvas test: 2d.text.measure.text-clusters-rendering-align.tentative</title>
+<h1 style="font-size: 20px;">2d.text.measure.text-clusters-rendering-align.tentative</h1>
+<p class="desc">Test that fillTextCluster() correctly positions the text, taking into account the textAlign from the context at the time the text was measured.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(3, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>ctx_align_left</div>
+ <canvas id="canvas0" width="250" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = 'left';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+ </script>
+</span>
+
+<span>
+ <div>ctx_align_center</div>
+ <canvas id="canvas1" width="250" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = 'center';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+ </script>
+</span>
+
+<span>
+ <div>ctx_align_right</div>
+ <canvas id="canvas2" width="250" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = 'right';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative-expected.html b/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative-expected.html
new file mode 100644
index 00000000000..2dffe90aadc
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative-expected.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<title>Canvas test: 2d.text.measure.text-clusters-rendering-baseline.tentative</title>
+<h1 style="font-size: 20px;">2d.text.measure.text-clusters-rendering-baseline.tentative</h1>
+<p class="desc">Test that fillTextCluster() correctly positions the text, taking into account the textBaseline from the context at the time the text was measured.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(4, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>ctx_baseline_top</div>
+ <canvas id="canvas0" width="180" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'top';
+ ctx.fillText(text, x, y);
+ </script>
+</span>
+
+<span>
+ <div>ctx_baseline_middle</div>
+ <canvas id="canvas1" width="180" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'middle';
+ ctx.fillText(text, x, y);
+ </script>
+</span>
+
+<span>
+ <div>ctx_baseline_bottom</div>
+ <canvas id="canvas2" width="180" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'bottom';
+ ctx.fillText(text, x, y);
+ </script>
+</span>
+
+<span>
+ <div>ctx_baseline_alphabetic</div>
+ <canvas id="canvas3" width="180" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'alphabetic';
+ ctx.fillText(text, x, y);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html b/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html
new file mode 100644
index 00000000000..c20e076a351
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.text.measure.text-clusters-rendering-baseline.tentative-expected.html">
+<title>Canvas test: 2d.text.measure.text-clusters-rendering-baseline.tentative</title>
+<h1 style="font-size: 20px;">2d.text.measure.text-clusters-rendering-baseline.tentative</h1>
+<p class="desc">Test that fillTextCluster() correctly positions the text, taking into account the textBaseline from the context at the time the text was measured.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(4, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>ctx_baseline_top</div>
+ <canvas id="canvas0" width="180" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'top';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+ </script>
+</span>
+
+<span>
+ <div>ctx_baseline_middle</div>
+ <canvas id="canvas1" width="180" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'middle';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+ </script>
+</span>
+
+<span>
+ <div>ctx_baseline_bottom</div>
+ <canvas id="canvas2" width="180" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'bottom';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+ </script>
+</span>
+
+<span>
+ <div>ctx_baseline_alphabetic</div>
+ <canvas id="canvas3" width="180" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'alphabetic';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-font-change.tentative-expected.html b/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-font-change.tentative-expected.html
new file mode 100644
index 00000000000..9a9443962df
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-font-change.tentative-expected.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<title>Canvas test: 2d.text.measure.text-clusters-rendering-font-change.tentative</title>
+<h1>2d.text.measure.text-clusters-rendering-font-change.tentative</h1>
+<p class="desc">Test that fillTextCluster() renders in the font used originally when the text was measured, even if the font set on the context has changed since.</p>
+<canvas id="canvas" width="500" height="200">
+ <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+ const canvas = document.getElementById("canvas");
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '50px sans-serif';
+ const text = 'Hello ♦️ World!';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ const x = 100;
+ const y = 100;
+ ctx.fillText(text, x, y);
+</script>
diff --git a/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-font-change.tentative.html b/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-font-change.tentative.html
new file mode 100644
index 00000000000..a927cfcd330
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/element/text/2d.text.measure.text-clusters-rendering-font-change.tentative.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.text.measure.text-clusters-rendering-font-change.tentative-expected.html">
+<title>Canvas test: 2d.text.measure.text-clusters-rendering-font-change.tentative</title>
+<h1>2d.text.measure.text-clusters-rendering-font-change.tentative</h1>
+<p class="desc">Test that fillTextCluster() renders in the font used originally when the text was measured, even if the font set on the context has changed since.</p>
+<canvas id="canvas" width="500" height="200">
+ <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+ const canvas = document.getElementById("canvas");
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '50px sans-serif';
+ const text = 'Hello ♦️ World!';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ ctx.font = '80px serif';
+
+ const x = 100;
+ const y = 100;
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+</script>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage-expected.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage-expected.html
new file mode 100644
index 00000000000..eea78248a83
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.filter.no_shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.no_shadow.drawImage</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.html
new file mode 100644
index 00000000000..72b23aeeafb
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.html
@@ -0,0 +1,949 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.filter.no_shadow.drawImage-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.no_shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.no_shadow.drawImage</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas3");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas4");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas5");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas6");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas7");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas8");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas9");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas10");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas11");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas12");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas13");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas14");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas15");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas16");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas17");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas18");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas19");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas20");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas21");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas22");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas23");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas24");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas25");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.png b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.png
new file mode 100644
index 00000000000..2318c1ec94e
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.w.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.w.html
new file mode 100644
index 00000000000..89f4dba75b5
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.w.html
@@ -0,0 +1,1316 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<html class="reftest-wait">
+<link rel="match" href="2d.composite.grid.filter.no_shadow.drawImage-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.no_shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.no_shadow.drawImage</h1>
+<p class="desc"></p>
+<script>pending_tests = 26;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas2" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-over</div>
+ <canvas id="canvas4" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-in</div>
+ <canvas id="canvas5" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas6" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>color</div>
+ <canvas id="canvas24" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker25" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker25').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas25');
+ 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/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.worker.js b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.worker.js
new file mode 100644
index 00000000000..45329fcd9c8
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.drawImage.worker.js
@@ -0,0 +1,685 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.composite.grid.filter.no_shadow.drawImage
+// Description:
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+done();
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect-expected.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect-expected.html
new file mode 100644
index 00000000000..08ed3566fd1
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.filter.no_shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.no_shadow.fillRect</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.html
new file mode 100644
index 00000000000..3f8fdc8164d
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.html
@@ -0,0 +1,871 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.filter.no_shadow.fillRect-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.no_shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.no_shadow.fillRect</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas3");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas4");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas5");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas6");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas7");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas8");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas9");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas10");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas11");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas12");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas13");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas14");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas15");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas16");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas17");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas18");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas19");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas20");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas21");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas22");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas23");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas24");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas25");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.png b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.png
new file mode 100644
index 00000000000..2318c1ec94e
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.w.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.w.html
new file mode 100644
index 00000000000..37839bf8a8b
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.w.html
@@ -0,0 +1,1238 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<html class="reftest-wait">
+<link rel="match" href="2d.composite.grid.filter.no_shadow.fillRect-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.no_shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.no_shadow.fillRect</h1>
+<p class="desc"></p>
+<script>pending_tests = 26;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas2" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-over</div>
+ <canvas id="canvas4" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-in</div>
+ <canvas id="canvas5" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas6" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>color</div>
+ <canvas id="canvas24" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker25" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker25').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas25');
+ 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/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.worker.js b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.worker.js
new file mode 100644
index 00000000000..dff55436a40
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.fillRect.worker.js
@@ -0,0 +1,607 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.composite.grid.filter.no_shadow.fillRect
+// Description:
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+done();
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern-expected.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern-expected.html
new file mode 100644
index 00000000000..22c84f42e89
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.filter.no_shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.no_shadow.pattern</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.html
new file mode 100644
index 00000000000..0bb970ab3f8
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.html
@@ -0,0 +1,975 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.filter.no_shadow.pattern-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.no_shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.no_shadow.pattern</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas3");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas4");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas5");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas6");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas7");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas8");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas9");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas10");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas11");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas12");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas13");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas14");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas15");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas16");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas17");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas18");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas19");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas20");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas21");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas22");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas23");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas24");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas25");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.png b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.png
new file mode 100644
index 00000000000..2318c1ec94e
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.w.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.w.html
new file mode 100644
index 00000000000..81d0a8e6a69
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.w.html
@@ -0,0 +1,1342 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<html class="reftest-wait">
+<link rel="match" href="2d.composite.grid.filter.no_shadow.pattern-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.no_shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.no_shadow.pattern</h1>
+<p class="desc"></p>
+<script>pending_tests = 26;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas2" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-over</div>
+ <canvas id="canvas4" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-in</div>
+ <canvas id="canvas5" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas6" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>color</div>
+ <canvas id="canvas24" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker25" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker25').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas25');
+ 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/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.worker.js b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.worker.js
new file mode 100644
index 00000000000..d3e79cd2d15
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.no_shadow.pattern.worker.js
@@ -0,0 +1,711 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.composite.grid.filter.no_shadow.pattern
+// Description:
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+done();
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage-expected.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage-expected.html
new file mode 100644
index 00000000000..2072348f904
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.filter.shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.shadow.drawImage</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.html
new file mode 100644
index 00000000000..5c9e992c7ce
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.html
@@ -0,0 +1,1001 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.filter.shadow.drawImage-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.shadow.drawImage</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas3");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas4");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas5");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas6");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas7");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas8");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas9");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas10");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas11");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas12");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas13");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas14");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas15");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas16");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas17");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas18");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas19");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas20");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas21");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas22");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas23");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas24");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas25");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.png b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.png
new file mode 100644
index 00000000000..fde78773116
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.w.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.w.html
new file mode 100644
index 00000000000..08e66abd464
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.w.html
@@ -0,0 +1,1368 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<html class="reftest-wait">
+<link rel="match" href="2d.composite.grid.filter.shadow.drawImage-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.shadow.drawImage</h1>
+<p class="desc"></p>
+<script>pending_tests = 26;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas2" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-over</div>
+ <canvas id="canvas4" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-in</div>
+ <canvas id="canvas5" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas6" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>color</div>
+ <canvas id="canvas24" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker25" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker25').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas25');
+ 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/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.worker.js b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.worker.js
new file mode 100644
index 00000000000..9a9c2f93632
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.drawImage.worker.js
@@ -0,0 +1,737 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.composite.grid.filter.shadow.drawImage
+// Description:
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+done();
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect-expected.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect-expected.html
new file mode 100644
index 00000000000..1e119bcbde5
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.filter.shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.shadow.fillRect</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.html
new file mode 100644
index 00000000000..0f6b88fd5e9
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.html
@@ -0,0 +1,923 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.filter.shadow.fillRect-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.shadow.fillRect</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas3");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas4");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas5");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas6");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas7");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas8");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas9");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas10");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas11");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas12");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas13");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas14");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas15");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas16");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas17");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas18");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas19");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas20");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas21");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas22");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas23");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas24");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas25");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.png b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.png
new file mode 100644
index 00000000000..fde78773116
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.w.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.w.html
new file mode 100644
index 00000000000..f754f538b56
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.w.html
@@ -0,0 +1,1290 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<html class="reftest-wait">
+<link rel="match" href="2d.composite.grid.filter.shadow.fillRect-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.shadow.fillRect</h1>
+<p class="desc"></p>
+<script>pending_tests = 26;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas2" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-over</div>
+ <canvas id="canvas4" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-in</div>
+ <canvas id="canvas5" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas6" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>color</div>
+ <canvas id="canvas24" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker25" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker25').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas25');
+ 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/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.worker.js b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.worker.js
new file mode 100644
index 00000000000..f495009b301
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.fillRect.worker.js
@@ -0,0 +1,659 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.composite.grid.filter.shadow.fillRect
+// Description:
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+done();
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern-expected.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern-expected.html
new file mode 100644
index 00000000000..f45fe82c302
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.filter.shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.shadow.pattern</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.html
new file mode 100644
index 00000000000..e89aff9196d
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.html
@@ -0,0 +1,1027 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.filter.shadow.pattern-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.shadow.pattern</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas3");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas4");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas5");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas6");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas7");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas8");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas9");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas10");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas11");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas12");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas13");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas14");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas15");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas16");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas17");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas18");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas19");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas20");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas21");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas22");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas23");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas24");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas25");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.png b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.png
new file mode 100644
index 00000000000..fde78773116
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.w.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.w.html
new file mode 100644
index 00000000000..79f7aab01cd
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.w.html
@@ -0,0 +1,1394 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<html class="reftest-wait">
+<link rel="match" href="2d.composite.grid.filter.shadow.pattern-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.filter.shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.filter.shadow.pattern</h1>
+<p class="desc"></p>
+<script>pending_tests = 26;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas2" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-over</div>
+ <canvas id="canvas4" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-in</div>
+ <canvas id="canvas5" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas6" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>color</div>
+ <canvas id="canvas24" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker25" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker25').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas25');
+ 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/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.worker.js b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.worker.js
new file mode 100644
index 00000000000..d960d0d5401
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.filter.shadow.pattern.worker.js
@@ -0,0 +1,763 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.composite.grid.filter.shadow.pattern
+// Description:
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+done();
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage-expected.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage-expected.html
new file mode 100644
index 00000000000..923d8360a9d
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.no_filter.no_shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.no_shadow.drawImage</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html
new file mode 100644
index 00000000000..54a53b46576
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.html
@@ -0,0 +1,949 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.no_filter.no_shadow.drawImage-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.no_shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.no_shadow.drawImage</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas3");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas4");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas5");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas6");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas7");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas8");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas9");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas10");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas11");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas12");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas13");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas14");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas15");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas16");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas17");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas18");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas19");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas20");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas21");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas22");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas23");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas24");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas25");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.png b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.png
new file mode 100644
index 00000000000..ce392a1dccc
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.w.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.w.html
new file mode 100644
index 00000000000..4750ed210ff
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.w.html
@@ -0,0 +1,1316 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<html class="reftest-wait">
+<link rel="match" href="2d.composite.grid.no_filter.no_shadow.drawImage-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.no_shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.no_shadow.drawImage</h1>
+<p class="desc"></p>
+<script>pending_tests = 26;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas2" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-over</div>
+ <canvas id="canvas4" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-in</div>
+ <canvas id="canvas5" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas6" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>color</div>
+ <canvas id="canvas24" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker25" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker25').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas25');
+ 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/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.worker.js b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.worker.js
new file mode 100644
index 00000000000..de1686a76e8
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.drawImage.worker.js
@@ -0,0 +1,685 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.composite.grid.no_filter.no_shadow.drawImage
+// Description:
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+done();
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect-expected.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect-expected.html
new file mode 100644
index 00000000000..c809e56cac3
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.no_filter.no_shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.no_shadow.fillRect</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html
new file mode 100644
index 00000000000..e69af8a79a9
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.html
@@ -0,0 +1,871 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.no_filter.no_shadow.fillRect-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.no_shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.no_shadow.fillRect</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas3");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas4");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas5");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas6");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas7");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas8");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas9");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas10");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas11");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas12");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas13");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas14");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas15");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas16");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas17");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas18");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas19");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas20");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas21");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas22");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas23");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas24");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas25");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.png b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.png
new file mode 100644
index 00000000000..ce392a1dccc
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.w.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.w.html
new file mode 100644
index 00000000000..0cfc23ab86a
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.w.html
@@ -0,0 +1,1238 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<html class="reftest-wait">
+<link rel="match" href="2d.composite.grid.no_filter.no_shadow.fillRect-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.no_shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.no_shadow.fillRect</h1>
+<p class="desc"></p>
+<script>pending_tests = 26;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas2" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-over</div>
+ <canvas id="canvas4" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-in</div>
+ <canvas id="canvas5" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas6" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>color</div>
+ <canvas id="canvas24" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker25" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker25').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas25');
+ 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/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.worker.js b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.worker.js
new file mode 100644
index 00000000000..cb60645b704
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.fillRect.worker.js
@@ -0,0 +1,607 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.composite.grid.no_filter.no_shadow.fillRect
+// Description:
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+done();
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern-expected.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern-expected.html
new file mode 100644
index 00000000000..f052442a637
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.no_filter.no_shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.no_shadow.pattern</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.no_filter.no_shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html
new file mode 100644
index 00000000000..b6008b7c79f
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.html
@@ -0,0 +1,975 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.no_filter.no_shadow.pattern-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.no_shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.no_shadow.pattern</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas3");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas4");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas5");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas6");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas7");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas8");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas9");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas10");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas11");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas12");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas13");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas14");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas15");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas16");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas17");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas18");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas19");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas20");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas21");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas22");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas23");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas24");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas25");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.png b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.png
new file mode 100644
index 00000000000..ce392a1dccc
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.w.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.w.html
new file mode 100644
index 00000000000..ef952ce12cd
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.w.html
@@ -0,0 +1,1342 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<html class="reftest-wait">
+<link rel="match" href="2d.composite.grid.no_filter.no_shadow.pattern-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.no_shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.no_shadow.pattern</h1>
+<p class="desc"></p>
+<script>pending_tests = 26;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas2" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-over</div>
+ <canvas id="canvas4" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-in</div>
+ <canvas id="canvas5" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas6" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>color</div>
+ <canvas id="canvas24" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker25" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker25').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas25');
+ 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/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.worker.js b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.worker.js
new file mode 100644
index 00000000000..e1479261ce2
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.no_shadow.pattern.worker.js
@@ -0,0 +1,711 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.composite.grid.no_filter.no_shadow.pattern
+// Description:
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ // No shadow.
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+done();
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage-expected.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage-expected.html
new file mode 100644
index 00000000000..ad07c35d310
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.no_filter.shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.shadow.drawImage</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.no_filter.shadow.drawImage.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.html
new file mode 100644
index 00000000000..d25f183aeb8
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.html
@@ -0,0 +1,1001 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.no_filter.shadow.drawImage-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.shadow.drawImage</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas3");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas4");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas5");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas6");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas7");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas8");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas9");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas10");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas11");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas12");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas13");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas14");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas15");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas16");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas17");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas18");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas19");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas20");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas21");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas22");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas23");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas24");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas25");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.png b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.png
new file mode 100644
index 00000000000..aca03a61b22
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.w.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.w.html
new file mode 100644
index 00000000000..c66b467d627
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.w.html
@@ -0,0 +1,1368 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<html class="reftest-wait">
+<link rel="match" href="2d.composite.grid.no_filter.shadow.drawImage-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.shadow.drawImage</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.shadow.drawImage</h1>
+<p class="desc"></p>
+<script>pending_tests = 26;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas2" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-over</div>
+ <canvas id="canvas4" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-in</div>
+ <canvas id="canvas5" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas6" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>color</div>
+ <canvas id="canvas24" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ 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>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker25" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker25').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas25');
+ 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/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.worker.js b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.worker.js
new file mode 100644
index 00000000000..c7827238f69
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.drawImage.worker.js
@@ -0,0 +1,737 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.composite.grid.no_filter.shadow.drawImage
+// Description:
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+}, "");
+
+done();
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect-expected.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect-expected.html
new file mode 100644
index 00000000000..e16a5fcf458
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.no_filter.shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.shadow.fillRect</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.no_filter.shadow.fillRect.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.html
new file mode 100644
index 00000000000..3fdbfa72caf
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.html
@@ -0,0 +1,923 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.no_filter.shadow.fillRect-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.shadow.fillRect</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas3");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas4");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas5");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas6");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas7");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas8");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas9");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas10");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas11");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas12");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas13");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas14");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas15");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas16");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas17");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas18");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas19");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas20");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas21");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas22");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas23");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas24");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas25");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.png b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.png
new file mode 100644
index 00000000000..aca03a61b22
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.w.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.w.html
new file mode 100644
index 00000000000..519631612f0
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.w.html
@@ -0,0 +1,1290 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<html class="reftest-wait">
+<link rel="match" href="2d.composite.grid.no_filter.shadow.fillRect-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.shadow.fillRect</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.shadow.fillRect</h1>
+<p class="desc"></p>
+<script>pending_tests = 26;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas2" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-over</div>
+ <canvas id="canvas4" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-in</div>
+ <canvas id="canvas5" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas6" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>color</div>
+ <canvas id="canvas24" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker25" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker25').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas25');
+ 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/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.worker.js b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.worker.js
new file mode 100644
index 00000000000..217fe38a8de
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.fillRect.worker.js
@@ -0,0 +1,659 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.composite.grid.no_filter.shadow.fillRect
+// Description:
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+done();
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern-expected.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern-expected.html
new file mode 100644
index 00000000000..01e1d4d7b26
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern-expected.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.composite.grid.no_filter.shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.shadow.pattern</h1>
+<p></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-in</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-out</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>source-atop</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-over</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-in</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px 0px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-out</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighter</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>copy</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>xor</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>multiply</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -60px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>screen</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>overlay</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>darken</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>lighten</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color-burn</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -120px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hard-light</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>soft-light</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>difference</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -160px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>exclusion</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -240px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>hue</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -320px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>saturation</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -400px -180px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>color</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: 0px -240px;
+ object-fit: none;">
+</span>
+
+<span>
+ <div>luminosity</div>
+ <img src="2d.composite.grid.no_filter.shadow.pattern.png"
+ style="outline: 1px solid;
+ width: 80px;
+ height: 60px;
+ object-position: -80px -240px;
+ object-fit: none;">
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.html
new file mode 100644
index 00000000000..d9df6be84f1
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.html
@@ -0,0 +1,1027 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.composite.grid.no_filter.shadow.pattern-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.shadow.pattern</h1>
+<p class="desc"></p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-out</div>
+ <canvas id="canvas2" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas3");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-over</div>
+ <canvas id="canvas4" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas4");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-in</div>
+ <canvas id="canvas5" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas5");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-out</div>
+ <canvas id="canvas6" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas6");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas7");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighter</div>
+ <canvas id="canvas8" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas8");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>copy</div>
+ <canvas id="canvas9" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas9");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>xor</div>
+ <canvas id="canvas10" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas10");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>multiply</div>
+ <canvas id="canvas11" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas11");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>screen</div>
+ <canvas id="canvas12" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas12");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>overlay</div>
+ <canvas id="canvas13" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas13");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>darken</div>
+ <canvas id="canvas14" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas14");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>lighten</div>
+ <canvas id="canvas15" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas15");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-dodge</div>
+ <canvas id="canvas16" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas16");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas17");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas18");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas19");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>difference</div>
+ <canvas id="canvas20" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas20");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas21");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>hue</div>
+ <canvas id="canvas22" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas22");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>saturation</div>
+ <canvas id="canvas23" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas23");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>color</div>
+ <canvas id="canvas24" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas24");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const outputCanvas = document.getElementById("canvas25");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.png b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.png
new file mode 100644
index 00000000000..aca03a61b22
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.w.html b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.w.html
new file mode 100644
index 00000000000..5c698e8c760
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.w.html
@@ -0,0 +1,1394 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<html class="reftest-wait">
+<link rel="match" href="2d.composite.grid.no_filter.shadow.pattern-expected.html">
+<meta name=fuzzy content="maxDifference=0-2; totalPixels=0-10210">
+<title>Canvas test: 2d.composite.grid.no_filter.shadow.pattern</title>
+<h1 style="font-size: 20px;">2d.composite.grid.no_filter.shadow.pattern</h1>
+<p class="desc"></p>
+<script>pending_tests = 26;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(6, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>source-over</div>
+ <canvas id="canvas0" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas2" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>source-atop</div>
+ <canvas id="canvas3" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-over</div>
+ <canvas id="canvas4" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-in</div>
+ <canvas id="canvas5" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-out</div>
+ <canvas id="canvas6" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>destination-atop</div>
+ <canvas id="canvas7" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>lighter</div>
+ <canvas id="canvas8" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>copy</div>
+ <canvas id="canvas9" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>xor</div>
+ <canvas id="canvas10" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>multiply</div>
+ <canvas id="canvas11" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>screen</div>
+ <canvas id="canvas12" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>overlay</div>
+ <canvas id="canvas13" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>darken</div>
+ <canvas id="canvas14" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>lighten</div>
+ <canvas id="canvas15" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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-dodge</div>
+ <canvas id="canvas16" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>color-burn</div>
+ <canvas id="canvas17" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>hard-light</div>
+ <canvas id="canvas18" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>soft-light</div>
+ <canvas id="canvas19" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>difference</div>
+ <canvas id="canvas20" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>exclusion</div>
+ <canvas id="canvas21" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>hue</div>
+ <canvas id="canvas22" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>saturation</div>
+ <canvas id="canvas23" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>color</div>
+ <canvas id="canvas24" width="80" height="60" 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(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ 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>
+
+<span>
+ <div>luminosity</div>
+ <canvas id="canvas25" width="80" height="60" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script id="myWorker25" type="text/worker">
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+
+ const bitmap = canvas.transferToImageBitmap();
+ self.postMessage(bitmap, bitmap);
+ };
+ </script>
+ <script type="module">
+ const blob = new Blob([document.getElementById('myWorker25').textContent]);
+ const worker = new Worker(URL.createObjectURL(blob));
+ worker.addEventListener('message', msg => {
+ const outputCanvas = document.getElementById('canvas25');
+ 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/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.worker.js b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.worker.js
new file mode 100644
index 00000000000..f26657b5214
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/compositing/2d.composite.grid.no_filter.shadow.pattern.worker.js
@@ -0,0 +1,763 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.composite.grid.no_filter.shadow.pattern
+// Description:
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'source-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-over'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-in'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-out'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'destination-atop'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighter'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'copy'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'xor'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'multiply'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'screen'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'overlay'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'darken'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'lighten'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-dodge'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color-burn'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hard-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'soft-light'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'difference'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'exclusion'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'hue'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'saturation'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'color'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+test(t => {
+ const canvas = new OffscreenCanvas(80, 60);
+ const ctx = canvas.getContext('2d');
+
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ // No filter.
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+
+ ctx.globalCompositeOperation = 'luminosity'
+
+ const img_canvas = new OffscreenCanvas(80, 60);
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, 80, 60);
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
+}, "");
+
+done();
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.fill.basic.png b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.fill.basic.png
index 8021427a07d..70d7b046cb2 100644
--- a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.fill.basic.png
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.fill.basic.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.large.png b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.large.png
index 8021427a07d..70d7b046cb2 100644
--- a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.large.png
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.large.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.fill.rtl.png b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.fill.rtl.png
index 8021427a07d..70d7b046cb2 100644
--- a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.fill.rtl.png
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.fill.rtl.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.stroke.basic.png b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.stroke.basic.png
index d4f6dc1ee88..fb3b5b830d3 100644
--- a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.stroke.basic.png
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.draw.stroke.basic.png
Binary files differ
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.html b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.html
new file mode 100644
index 00000000000..780a4f52623
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<title>OffscreenCanvas test: 2d.text.measure.text-clusters-position.tentative</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+
+<h1>2d.text.measure.text-clusters-position.tentative</h1>
+<p class="desc">Test that TextMetrics::getTextClusters() returns clusters that are positioned according to the target align and baseline passed as options.</p>
+
+
+<script>
+promise_test(async t => {
+
+ var canvas = new OffscreenCanvas(500, 500);
+ var ctx = canvas.getContext('2d');
+
+ var f = new FontFace("CanvasTest", "url('/fonts/CanvasTest.ttf')");
+ f.load();
+ document.fonts.add(f);
+ await document.fonts.ready;
+ ctx.font = '40px CanvasTest';
+ const text = 'E';
+
+ // Origin for all the measurements is placed at the top left corner.
+ ctx.textAlign = 'left';
+ ctx.textBaseline = 'top';
+ let tm = ctx.measureText(text);
+
+ // X position.
+ _assertSame(Math.abs(tm.getTextClusters({align: 'left'})[0].x), 0, "Math.abs(tm.getTextClusters({align: 'left'})[\""+(0)+"\"].x)", "0");
+ _assertSame(tm.getTextClusters({align: 'center'})[0].x, 20, "tm.getTextClusters({align: 'center'})[\""+(0)+"\"].x", "20");
+ _assertSame(tm.getTextClusters({align: 'right'})[0].x, 40, "tm.getTextClusters({align: 'right'})[\""+(0)+"\"].x", "40");
+
+ // Y position.
+ _assertSame(Math.abs(tm.getTextClusters({baseline: 'top'})[0].y), 0, "Math.abs(tm.getTextClusters({baseline: 'top'})[\""+(0)+"\"].y)", "0");
+ _assertSame(tm.getTextClusters({baseline: 'middle'})[0].y, 20, "tm.getTextClusters({baseline: 'middle'})[\""+(0)+"\"].y", "20");
+ _assertSame(tm.getTextClusters({baseline: 'bottom'})[0].y, 40, "tm.getTextClusters({baseline: 'bottom'})[\""+(0)+"\"].y", "40");
+ _assertSame(tm.getTextClusters({baseline: 'alphabetic'})[0].y, 30, "tm.getTextClusters({baseline: 'alphabetic'})[\""+(0)+"\"].y", "30");
+
+}, "Test that TextMetrics::getTextClusters() returns clusters that are positioned according to the target align and baseline passed as options.");
+</script>
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.worker.js b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.worker.js
new file mode 100644
index 00000000000..90ee50fa50f
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-position.tentative.worker.js
@@ -0,0 +1,36 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.text.measure.text-clusters-position.tentative
+// Description:Test that TextMetrics::getTextClusters() returns clusters that are positioned according to the target align and baseline passed as options.
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+promise_test(async t => {
+ var canvas = new OffscreenCanvas(500, 500);
+ var ctx = canvas.getContext('2d');
+
+ var f = new FontFace("CanvasTest", "url('/fonts/CanvasTest.ttf')");
+ f.load();
+ self.fonts.add(f);
+ await self.fonts.ready;
+ ctx.font = '40px CanvasTest';
+ const text = 'E';
+
+ // Origin for all the measurements is placed at the top left corner.
+ ctx.textAlign = 'left';
+ ctx.textBaseline = 'top';
+ let tm = ctx.measureText(text);
+
+ // X position.
+ _assertSame(Math.abs(tm.getTextClusters({align: 'left'})[0].x), 0, "Math.abs(tm.getTextClusters({align: 'left'})[\""+(0)+"\"].x)", "0");
+ _assertSame(tm.getTextClusters({align: 'center'})[0].x, 20, "tm.getTextClusters({align: 'center'})[\""+(0)+"\"].x", "20");
+ _assertSame(tm.getTextClusters({align: 'right'})[0].x, 40, "tm.getTextClusters({align: 'right'})[\""+(0)+"\"].x", "40");
+
+ // Y position.
+ _assertSame(Math.abs(tm.getTextClusters({baseline: 'top'})[0].y), 0, "Math.abs(tm.getTextClusters({baseline: 'top'})[\""+(0)+"\"].y)", "0");
+ _assertSame(tm.getTextClusters({baseline: 'middle'})[0].y, 20, "tm.getTextClusters({baseline: 'middle'})[\""+(0)+"\"].y", "20");
+ _assertSame(tm.getTextClusters({baseline: 'bottom'})[0].y, 40, "tm.getTextClusters({baseline: 'bottom'})[\""+(0)+"\"].y", "40");
+ _assertSame(tm.getTextClusters({baseline: 'alphabetic'})[0].y, 30, "tm.getTextClusters({baseline: 'alphabetic'})[\""+(0)+"\"].y", "30");
+}, "Test that TextMetrics::getTextClusters() returns clusters that are positioned according to the target align and baseline passed as options.");
+done();
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.html b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.html
new file mode 100644
index 00000000000..9bd2a026618
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<title>OffscreenCanvas test: 2d.text.measure.text-clusters-range.tentative</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+
+<h1>2d.text.measure.text-clusters-range.tentative</h1>
+<p class="desc">Test that getTextClusters() and fillTextCluster() correctly render different ranges of the input text.</p>
+
+
+<script>
+promise_test(async t => {
+
+ var canvas = new OffscreenCanvas(400, 300);
+ var ctx = canvas.getContext('2d');
+
+ // Renders all the clusters in the list from position (x, y).
+ function renderClusters(clusters, x, y) {
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+ }
+
+ var f = new FontFace("CanvasTest", "url('/fonts/CanvasTest.ttf')");
+ f.load();
+ document.fonts.add(f);
+ await document.fonts.ready;
+
+ ctx.font = '50px CanvasTest';
+ ctx.textAlign = 'left';
+ ctx.textBaseline = 'top';
+ const text = 'EEEEE';
+ let tm = ctx.measureText(text);
+
+ // Background color.
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ ctx.fillStyle = '#0f0';
+
+ // Without the first character.
+ renderClusters(tm.getTextClusters(1, 5), 0, 0);
+ _assertPixelApprox(canvas, 5,5, 255,0,0,255, 2);
+ _assertPixelApprox(canvas, 55,5, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 105,5, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 155,5, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 205,5, 0,255,0,255, 2);
+ // Without the last character.
+ renderClusters(tm.getTextClusters(0, 4), 0, 100);
+ _assertPixelApprox(canvas, 5,105, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 55,105, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 105,105, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 155,105, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 205,105, 255,0,0,255, 2);
+ // Only the middle character.
+ renderClusters(tm.getTextClusters(2, 3), 0, 150);
+ _assertPixelApprox(canvas, 5,155, 255,0,0,255, 2);
+ _assertPixelApprox(canvas, 55,155, 255,0,0,255, 2);
+ _assertPixelApprox(canvas, 105,155, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 155,155, 255,0,0,255, 2);
+ _assertPixelApprox(canvas, 205,155, 255,0,0,255, 2);
+
+}, "Test that getTextClusters() and fillTextCluster() correctly render different ranges of the input text.");
+</script>
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.worker.js b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.worker.js
new file mode 100644
index 00000000000..db76d19edf3
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-range.tentative.worker.js
@@ -0,0 +1,59 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.text.measure.text-clusters-range.tentative
+// Description:Test that getTextClusters() and fillTextCluster() correctly render different ranges of the input text.
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+promise_test(async t => {
+ var canvas = new OffscreenCanvas(400, 300);
+ var ctx = canvas.getContext('2d');
+
+ // Renders all the clusters in the list from position (x, y).
+ function renderClusters(clusters, x, y) {
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+ }
+
+ var f = new FontFace("CanvasTest", "url('/fonts/CanvasTest.ttf')");
+ f.load();
+ self.fonts.add(f);
+ await self.fonts.ready;
+
+ ctx.font = '50px CanvasTest';
+ ctx.textAlign = 'left';
+ ctx.textBaseline = 'top';
+ const text = 'EEEEE';
+ let tm = ctx.measureText(text);
+
+ // Background color.
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ ctx.fillStyle = '#0f0';
+
+ // Without the first character.
+ renderClusters(tm.getTextClusters(1, 5), 0, 0);
+ _assertPixelApprox(canvas, 5,5, 255,0,0,255, 2);
+ _assertPixelApprox(canvas, 55,5, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 105,5, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 155,5, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 205,5, 0,255,0,255, 2);
+ // Without the last character.
+ renderClusters(tm.getTextClusters(0, 4), 0, 100);
+ _assertPixelApprox(canvas, 5,105, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 55,105, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 105,105, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 155,105, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 205,105, 255,0,0,255, 2);
+ // Only the middle character.
+ renderClusters(tm.getTextClusters(2, 3), 0, 150);
+ _assertPixelApprox(canvas, 5,155, 255,0,0,255, 2);
+ _assertPixelApprox(canvas, 55,155, 255,0,0,255, 2);
+ _assertPixelApprox(canvas, 105,155, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 155,155, 255,0,0,255, 2);
+ _assertPixelApprox(canvas, 205,155, 255,0,0,255, 2);
+}, "Test that getTextClusters() and fillTextCluster() correctly render different ranges of the input text.");
+done();
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative-expected.html b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative-expected.html
new file mode 100644
index 00000000000..967ae7e4636
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative-expected.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<title>Canvas test: 2d.text.measure.text-clusters-rendering-align.tentative</title>
+<h1 style="font-size: 20px;">2d.text.measure.text-clusters-rendering-align.tentative</h1>
+<p class="desc">Test that fillTextCluster() correctly positions the text, taking into account the textAlign from the context at the time the text was measured.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(3, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>ctx_align_left</div>
+ <canvas id="canvas0" width="250" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = 'left';
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ ctx.fillText(text, x, y);
+ </script>
+</span>
+
+<span>
+ <div>ctx_align_center</div>
+ <canvas id="canvas1" width="250" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = 'center';
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ ctx.fillText(text, x, y);
+ </script>
+</span>
+
+<span>
+ <div>ctx_align_right</div>
+ <canvas id="canvas2" width="250" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = 'right';
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ ctx.fillText(text, x, y);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.html b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.html
new file mode 100644
index 00000000000..4fc41c79cc4
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.text.measure.text-clusters-rendering-align.tentative-expected.html">
+<title>Canvas test: 2d.text.measure.text-clusters-rendering-align.tentative</title>
+<h1 style="font-size: 20px;">2d.text.measure.text-clusters-rendering-align.tentative</h1>
+<p class="desc">Test that fillTextCluster() correctly positions the text, taking into account the textAlign from the context at the time the text was measured.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(3, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>ctx_align_left</div>
+ <canvas id="canvas0" width="250" height="43" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(250, 43);
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = 'left';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>ctx_align_center</div>
+ <canvas id="canvas1" width="250" height="43" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(250, 43);
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = 'center';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>ctx_align_right</div>
+ <canvas id="canvas2" width="250" height="43" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(250, 43);
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = 'right';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.w.html b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.w.html
new file mode 100644
index 00000000000..35ddd54bfd7
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-align.tentative.w.html
@@ -0,0 +1,147 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<html class="reftest-wait">
+<link rel="match" href="2d.text.measure.text-clusters-rendering-align.tentative-expected.html">
+<title>Canvas test: 2d.text.measure.text-clusters-rendering-align.tentative</title>
+<h1 style="font-size: 20px;">2d.text.measure.text-clusters-rendering-align.tentative</h1>
+<p class="desc">Test that fillTextCluster() correctly positions the text, taking into account the textAlign from the context at the time the text was measured.</p>
+<script>pending_tests = 3;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(3, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>ctx_align_left</div>
+ <canvas id="canvas0" width="250" height="43" 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(250, 43);
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = 'left';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+
+ 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>ctx_align_center</div>
+ <canvas id="canvas1" width="250" height="43" 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(250, 43);
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = 'center';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+
+ 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>ctx_align_right</div>
+ <canvas id="canvas2" width="250" height="43" 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(250, 43);
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = 'right';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+
+ 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>
+
+</div>
+</html>
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative-expected.html b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative-expected.html
new file mode 100644
index 00000000000..2dffe90aadc
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative-expected.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<title>Canvas test: 2d.text.measure.text-clusters-rendering-baseline.tentative</title>
+<h1 style="font-size: 20px;">2d.text.measure.text-clusters-rendering-baseline.tentative</h1>
+<p class="desc">Test that fillTextCluster() correctly positions the text, taking into account the textBaseline from the context at the time the text was measured.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(4, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>ctx_baseline_top</div>
+ <canvas id="canvas0" width="180" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'top';
+ ctx.fillText(text, x, y);
+ </script>
+</span>
+
+<span>
+ <div>ctx_baseline_middle</div>
+ <canvas id="canvas1" width="180" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'middle';
+ ctx.fillText(text, x, y);
+ </script>
+</span>
+
+<span>
+ <div>ctx_baseline_bottom</div>
+ <canvas id="canvas2" width="180" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'bottom';
+ ctx.fillText(text, x, y);
+ </script>
+</span>
+
+<span>
+ <div>ctx_baseline_alphabetic</div>
+ <canvas id="canvas3" width="180" height="43" 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.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'alphabetic';
+ ctx.fillText(text, x, y);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html
new file mode 100644
index 00000000000..84def142a9b
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.html
@@ -0,0 +1,132 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.text.measure.text-clusters-rendering-baseline.tentative-expected.html">
+<title>Canvas test: 2d.text.measure.text-clusters-rendering-baseline.tentative</title>
+<h1 style="font-size: 20px;">2d.text.measure.text-clusters-rendering-baseline.tentative</h1>
+<p class="desc">Test that fillTextCluster() correctly positions the text, taking into account the textBaseline from the context at the time the text was measured.</p>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(4, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>ctx_baseline_top</div>
+ <canvas id="canvas0" width="180" height="43" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(180, 43);
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'top';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+
+ const outputCanvas = document.getElementById("canvas0");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>ctx_baseline_middle</div>
+ <canvas id="canvas1" width="180" height="43" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(180, 43);
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'middle';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+
+ const outputCanvas = document.getElementById("canvas1");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>ctx_baseline_bottom</div>
+ <canvas id="canvas2" width="180" height="43" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(180, 43);
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'bottom';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+
+ const outputCanvas = document.getElementById("canvas2");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+<span>
+ <div>ctx_baseline_alphabetic</div>
+ <canvas id="canvas3" width="180" height="43" style="outline: 1px solid">
+ <p class="fallback">FAIL (fallback content)</p>
+ </canvas>
+ <script type="module">
+ const canvas = new OffscreenCanvas(180, 43);
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'alphabetic';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+
+ const outputCanvas = document.getElementById("canvas3");
+ const outputCtx = outputCanvas.getContext('2d');
+ outputCtx.drawImage(canvas, 0, 0);
+ </script>
+</span>
+
+</div>
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.w.html b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.w.html
new file mode 100644
index 00000000000..9227776d8c8
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-baseline.tentative.w.html
@@ -0,0 +1,191 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<html class="reftest-wait">
+<link rel="match" href="2d.text.measure.text-clusters-rendering-baseline.tentative-expected.html">
+<title>Canvas test: 2d.text.measure.text-clusters-rendering-baseline.tentative</title>
+<h1 style="font-size: 20px;">2d.text.measure.text-clusters-rendering-baseline.tentative</h1>
+<p class="desc">Test that fillTextCluster() correctly positions the text, taking into account the textBaseline from the context at the time the text was measured.</p>
+<script>pending_tests = 4;</script>
+
+<div style="display: grid; grid-gap: 4px;
+ grid-template-columns: repeat(4, max-content);
+ font-size: 13px; text-align: center;">
+<span>
+ <div>ctx_baseline_top</div>
+ <canvas id="canvas0" width="180" height="43" 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(180, 43);
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'top';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+
+ 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>ctx_baseline_middle</div>
+ <canvas id="canvas1" width="180" height="43" 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(180, 43);
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'middle';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+
+ 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>ctx_baseline_bottom</div>
+ <canvas id="canvas2" width="180" height="43" 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(180, 43);
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'bottom';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+
+ 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>ctx_baseline_alphabetic</div>
+ <canvas id="canvas3" width="180" height="43" 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(180, 43);
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = 'alphabetic';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+
+ 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>
+
+</div>
+</html>
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative-expected.html b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative-expected.html
new file mode 100644
index 00000000000..9a9443962df
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative-expected.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<title>Canvas test: 2d.text.measure.text-clusters-rendering-font-change.tentative</title>
+<h1>2d.text.measure.text-clusters-rendering-font-change.tentative</h1>
+<p class="desc">Test that fillTextCluster() renders in the font used originally when the text was measured, even if the font set on the context has changed since.</p>
+<canvas id="canvas" width="500" height="200">
+ <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+ const canvas = document.getElementById("canvas");
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '50px sans-serif';
+ const text = 'Hello ♦️ World!';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ const x = 100;
+ const y = 100;
+ ctx.fillText(text, x, y);
+</script>
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative.html b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative.html
new file mode 100644
index 00000000000..c8e3383a462
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<link rel="match" href="2d.text.measure.text-clusters-rendering-font-change.tentative-expected.html">
+<title>Canvas test: 2d.text.measure.text-clusters-rendering-font-change.tentative</title>
+<h1>2d.text.measure.text-clusters-rendering-font-change.tentative</h1>
+<p class="desc">Test that fillTextCluster() renders in the font used originally when the text was measured, even if the font set on the context has changed since.</p>
+<canvas id="canvas" width="500" height="200">
+ <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+ const canvas = new OffscreenCanvas(500, 200);
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '50px sans-serif';
+ const text = 'Hello ♦️ World!';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ ctx.font = '80px serif';
+
+ const x = 100;
+ const y = 100;
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+
+ const outputCanvas = document.getElementById("canvas");
+ outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
+</script>
diff --git a/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative.w.html b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative.w.html
new file mode 100644
index 00000000000..6bca8ebbc35
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/offscreen/text/2d.text.measure.text-clusters-rendering-font-change.tentative.w.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<meta charset="UTF-8">
+<html class="reftest-wait">
+<link rel="match" href="2d.text.measure.text-clusters-rendering-font-change.tentative-expected.html">
+<title>Canvas test: 2d.text.measure.text-clusters-rendering-font-change.tentative</title>
+<h1>2d.text.measure.text-clusters-rendering-font-change.tentative</h1>
+<p class="desc">Test that fillTextCluster() renders in the font used originally when the text was measured, even if the font set on the context has changed since.</p>
+<canvas id="canvas" width="500" height="200">
+ <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script id='myWorker' type='text/worker'>
+ self.onmessage = function(e) {
+ const canvas = new OffscreenCanvas(500, 200);
+ const ctx = canvas.getContext('2d');
+
+ ctx.font = '50px sans-serif';
+ const text = 'Hello ♦️ World!';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ ctx.font = '80px serif';
+
+ const x = 100;
+ const y = 100;
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+
+ 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/tests/wpt/tests/html/canvas/tools/gentestutilsunion.py b/tests/wpt/tests/html/canvas/tools/gentestutilsunion.py
index 2ec2e20886b..629b596b513 100644
--- a/tests/wpt/tests/html/canvas/tools/gentestutilsunion.py
+++ b/tests/wpt/tests/html/canvas/tools/gentestutilsunion.py
@@ -39,6 +39,7 @@ import dataclasses
import enum
import importlib
import itertools
+import math
import os
import pathlib
import sys
@@ -257,6 +258,7 @@ class _CanvasType(str, enum.Enum):
class _TemplateType(str, enum.Enum):
REFERENCE = 'reference'
HTML_REFERENCE = 'html_reference'
+ CAIRO_REFERENCE = 'cairo_reference'
TESTHARNESS = 'testharness'
@@ -338,12 +340,18 @@ def _write_cairo_images(pycairo_code: str, output_files: _OutputPaths,
if _CanvasType.HTML_CANVAS in canvas_types:
full_code = (f'{pycairo_code}\n'
f'surface.write_to_png("{output_files.element}")\n')
- eval(compile(full_code, '<string>', 'exec'), {'cairo': cairo})
+ eval(compile(full_code, '<string>', 'exec'), {
+ 'cairo': cairo,
+ 'math': math,
+ })
if {_CanvasType.OFFSCREEN_CANVAS, _CanvasType.WORKER} & canvas_types:
full_code = (f'{pycairo_code}\n'
f'surface.write_to_png("{output_files.offscreen}")\n')
- eval(compile(full_code, '<string>', 'exec'), {'cairo': cairo})
+ eval(compile(full_code, '<string>', 'exec'), {
+ 'cairo': cairo,
+ 'math': math,
+ })
class _Variant():
@@ -452,15 +460,21 @@ class _Variant():
return frozenset(_CanvasType(t) for t in canvas_types)
def _get_template_type(self) -> _TemplateType:
- if 'reference' in self.params and 'html_reference' in self.params:
+ reference_types = (('reference' in self.params) +
+ ('html_reference' in self.params) +
+ ('cairo_reference' in self.params))
+ if reference_types > 1:
raise InvalidTestDefinitionError(
- f'Test {self.params["name"]} is invalid, "reference" and '
- '"html_reference" can\'t both be specified at the same time.')
+ f'Test {self.params["name"]} is invalid, only one of '
+ '"reference", "html_reference" or "cairo_reference" can be '
+ 'specified at the same time.')
if 'reference' in self.params:
return _TemplateType.REFERENCE
if 'html_reference' in self.params:
return _TemplateType.HTML_REFERENCE
+ if 'cairo_reference' in self.params:
+ return _TemplateType.CAIRO_REFERENCE
return _TemplateType.TESTHARNESS
def finalize_params(self, jinja_env: jinja2.Environment,
@@ -476,13 +490,10 @@ class _Variant():
if isinstance(self._params['size'], list):
self._params['size'] = tuple(self._params['size'])
- if 'reference' in self._params:
- self._params['reference'] = _preprocess_code(
- jinja_env, self._params['reference'], self._params)
-
- if 'html_reference' in self._params:
- self._params['html_reference'] = _preprocess_code(
- jinja_env, self._params['html_reference'], self._params)
+ for ref_type in {'reference', 'html_reference', 'cairo_reference'}:
+ if ref_type in self._params:
+ self._params[ref_type] = _preprocess_code(
+ jinja_env, self._params[ref_type], self._params)
code_params = dict(self.params)
if _CanvasType.HTML_CANVAS in self.params['canvas_types']:
@@ -503,7 +514,7 @@ class _Variant():
_validate_test(self._params)
def generate_expected_image(self, output_dirs: _OutputPaths) -> None:
- """Creates a reference image using Cairo and save filename in params."""
+ """Creates an expected image using Cairo and save filename in params."""
expected = self.params['expected']
if expected == 'green':
@@ -660,7 +671,8 @@ class _VariantGrid:
'fonts': self._param_set('fonts'),
}
if self.template_type in (_TemplateType.REFERENCE,
- _TemplateType.HTML_REFERENCE):
+ _TemplateType.HTML_REFERENCE,
+ _TemplateType.CAIRO_REFERENCE):
grid_params['desc'] = self._unique_param('desc')
return grid_params
@@ -692,9 +704,12 @@ class _VariantGrid:
f'{output_files.offscreen}.w.html')
params['is_test_reference'] = True
- 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')
+ templates = {
+ _TemplateType.REFERENCE: f'reftest_element{grid}.html',
+ _TemplateType.HTML_REFERENCE: f'reftest{grid}.html',
+ _TemplateType.CAIRO_REFERENCE: f'reftest_img{grid}.html'
+ }
+ ref_template_name = templates[self.template_type]
if _CanvasType.HTML_CANVAS in self.canvas_types:
_render(jinja_env, ref_template_name, params,
@@ -727,9 +742,72 @@ class _VariantGrid:
_render(jinja_env, f'testharness_worker{grid}.js', self.params,
f'{output_files.offscreen}.worker.js')
+ def _generate_cairo_reference_grid(self,
+ output_dirs: _OutputPaths) -> None:
+ """Generate this grid's expected image from Cairo code, if needed.
+
+ In order to cut on the number of files generated, the expected image
+ of all the variants in this grid are packed into a single PNG. The
+ expected HTML then contains a grid of <img> tags, each showing a portion
+ of the PNG file."""
+ if not any(v.params.get('cairo_reference') for v in self.variants):
+ return
+
+ width, height = self._unique_param('size')
+ cairo_code = ''
+
+ # First generate a function producing a Cairo surface with the expected
+ # image for each variant in the grid. The function is needed to provide
+ # a scope isolating the variant code from each other.
+ for idx, variant in enumerate(self._variants):
+ cairo_ref = variant.params.get('cairo_reference')
+ if not cairo_ref:
+ raise InvalidTestDefinitionError(
+ 'When used, "cairo_reference" must be specified for all '
+ 'test variants.')
+ cairo_code += textwrap.dedent(f'''\
+ def draw_ref{idx}():
+ surface = cairo.ImageSurface(
+ cairo.FORMAT_ARGB32, {width}, {height})
+ cr = cairo.Context(surface)
+ {{}}
+ return surface
+ ''').format(textwrap.indent(cairo_ref, ' '))
+
+ # Write all variant images into the final surface.
+ surface_width = width * self._grid_width
+ surface_height = (height *
+ math.ceil(len(self._variants) / self._grid_width))
+ cairo_code += textwrap.dedent(f'''\
+ surface = cairo.ImageSurface(
+ cairo.FORMAT_ARGB32, {surface_width}, {surface_height})
+ cr = cairo.Context(surface)
+ ''')
+ for idx, variant in enumerate(self._variants):
+ x_pos = int(idx % self._grid_width) * width
+ y_pos = int(idx / self._grid_width) * height
+ cairo_code += textwrap.dedent(f'''\
+ cr.set_source_surface(draw_ref{idx}(), {x_pos}, {y_pos})
+ cr.paint()
+ ''')
+
+ img_filename = f'{self.file_name}.png'
+ _write_cairo_images(cairo_code, output_dirs.sub_path(img_filename),
+ self.canvas_types)
+ self._params['img_reference'] = img_filename
+
def _generate_cairo_images(self, output_dirs: _OutputPaths) -> None:
"""Generates the pycairo images found in the YAML test definition."""
- if any(v.params.get('expected') for v in self._variants):
+ has_expected = any(v.params.get('expected') for v in self._variants)
+ has_cairo_reference = any(
+ v.params.get('cairo_reference') for v in self._variants)
+
+ if has_expected and has_cairo_reference:
+ raise InvalidTestDefinitionError(
+ 'Parameters "expected" and "cairo_reference" can\'t be both '
+ 'used at the same time.')
+
+ if has_expected:
if len(self.variants) != 1:
raise InvalidTestDefinitionError(
'Parameter "expected" is not supported for variant grids.')
@@ -738,6 +816,8 @@ class _VariantGrid:
'Parameter "expected" is not supported in reference '
'tests.')
self.variants[0].generate_expected_image(output_dirs)
+ elif has_cairo_reference:
+ self._generate_cairo_reference_grid(output_dirs)
def generate_test(self, jinja_env: jinja2.Environment,
output_dirs: _OutputPaths) -> None:
@@ -747,7 +827,8 @@ class _VariantGrid:
output_files = output_dirs.sub_path(self.file_name)
if self.template_type in (_TemplateType.REFERENCE,
- _TemplateType.HTML_REFERENCE):
+ _TemplateType.HTML_REFERENCE,
+ _TemplateType.CAIRO_REFERENCE):
self._write_reference_test(jinja_env, output_files)
else:
self._write_testharness_test(jinja_env, output_files)
@@ -803,6 +884,9 @@ def _get_variant_grids(test: Mapping[str, Any],
jinja_env: jinja2.Environment) -> List[_VariantGrid]:
base_variant = _Variant.create_with_defaults(test)
grid_width = base_variant.params.get('grid_width', 1)
+ if not isinstance(grid_width, int):
+ raise InvalidTestDefinitionError('"grid_width" must be an integer.')
+
grids = [_VariantGrid([base_variant], grid_width=grid_width)]
for dimension in _get_variant_dimensions(test):
variants = dimension.variants
diff --git a/tests/wpt/tests/html/canvas/tools/templates/reftest_img.html b/tests/wpt/tests/html/canvas/tools/templates/reftest_img.html
new file mode 100644
index 00000000000..c058406d49a
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/tools/templates/reftest_img.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: {{ name }}</title>
+<h1>{{ name }}</h1>
+<p>{{ desc }}</p>
+{% if notes %}<p>{{ notes }}</p>{% endif %}
+
+<img src="{{ img_reference }}">
diff --git a/tests/wpt/tests/html/canvas/tools/templates/reftest_img_grid.html b/tests/wpt/tests/html/canvas/tools/templates/reftest_img_grid.html
new file mode 100644
index 00000000000..20026c3e82c
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/tools/templates/reftest_img_grid.html
@@ -0,0 +1,27 @@
+<!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>{{ desc }}</p>
+{% if notes %}<p>{{ notes }}</p>{% 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 element_variants %}
+<span>
+ {% for variant_name in variant.grid_variant_names %}
+ <div>{{ variant_name }}</div>
+ {% endfor %}
+ {% set x_pos = ((loop.index0 % grid_width) | int) * variant.size[0] %}
+ {% set y_pos = ((loop.index0 / grid_width) | int) * variant.size[1] %}
+ <img src="{{ img_reference }}"
+ style="outline: 1px solid;
+ width: {{ variant.size[0] }}px;
+ height: {{ variant.size[1] }}px;
+ object-position: {{ -x_pos }}px {{ -y_pos }}px;
+ object-fit: none;">
+</span>
+
+{% endfor %}
+</div>
diff --git a/tests/wpt/tests/html/canvas/tools/yaml-new/compositing.yaml b/tests/wpt/tests/html/canvas/tools/yaml-new/compositing.yaml
index 6bd0aaad8a5..1db0c590db2 100644
--- a/tests/wpt/tests/html/canvas/tools/yaml-new/compositing.yaml
+++ b/tests/wpt/tests/html/canvas/tools/yaml-new/compositing.yaml
@@ -230,3 +230,179 @@
ctx.globalAlpha = 0.51;
ctx.drawImage(offscreenCanvas2, 0, 0);
@assert pixel 50,25 ==~ 0,255,0,130;
+
+- name: 2d.composite.grid
+ size: [80, 60]
+ code: |
+ ctx.fillStyle = 'rgb(0, 102, 255)';
+ ctx.fillRect(15, 15, 50, 30);
+
+ ctx.translate(25, 20);
+ ctx.rotate(Math.PI / 2);
+ ctx.scale(0.6, 1.2);
+ ctx.translate(-25, -20);
+
+ ctx.globalAlpha = 0.5;
+
+ {{ js_filter_code }}
+ {{ js_shadow_code }}
+
+ ctx.globalCompositeOperation = '{{ variant_names[0] }}'
+
+ {{ js_draw_code }}
+ cairo_reference: |
+ # Background.
+ cr.push_group()
+ cr.set_source_rgb(0, 102/255, 1)
+ cr.rectangle(15, 15, 50, 30)
+ cr.fill()
+ background = cr.pop_group()
+
+ # Foreground.
+ cr.push_group()
+ cr.translate(25, 20)
+ cr.rotate(math.pi / 2)
+ cr.scale(0.6, 1.2)
+ cr.translate(-25, -20)
+ cr.set_source_rgba(52/255, 1, 52/255, 0.5)
+ cr.rectangle(5, 5, 50, 30)
+ cr.fill()
+ foreground = cr.pop_group()
+
+ # Filtered foreground.
+ cr.push_group()
+ {{ cairo_filter_code }}
+ cr.set_source(foreground)
+ cr.paint()
+ filtered_foreground = cr.pop_group()
+
+ {% if cairo_operator != 'SOURCE' %}
+ cr.set_source(background)
+ cr.paint()
+ {% endif %}
+
+ cr.set_operator(cairo.OPERATOR_{{ cairo_operator }})
+
+ {% if cairo_operator != 'SOURCE' %}
+ {{ cairo_shadow_code }}
+ {% endif %}
+
+ cr.set_source(filtered_foreground)
+ cr.paint()
+ fuzzy: maxDifference=0-2; totalPixels=0-10210
+ variants_layout:
+ - single_file
+ - multi_files
+ - multi_files
+ - multi_files
+ grid_width: 6
+ variants:
+ - source-over:
+ cairo_operator: OVER
+ source-in:
+ cairo_operator: IN
+ source-out:
+ cairo_operator: OUT
+ source-atop:
+ cairo_operator: ATOP
+ destination-over:
+ cairo_operator: DEST_OVER
+ destination-in:
+ cairo_operator: DEST_IN
+ destination-out:
+ cairo_operator: DEST_OUT
+ destination-atop:
+ cairo_operator: DEST_ATOP
+ lighter:
+ cairo_operator: ADD
+ copy:
+ cairo_operator: SOURCE
+ xor:
+ cairo_operator: XOR
+ multiply:
+ cairo_operator: MULTIPLY
+ screen:
+ cairo_operator: SCREEN
+ overlay:
+ cairo_operator: OVERLAY
+ darken:
+ cairo_operator: DARKEN
+ lighten:
+ cairo_operator: LIGHTEN
+ color-dodge:
+ cairo_operator: COLOR_DODGE
+ color-burn:
+ cairo_operator: COLOR_BURN
+ hard-light:
+ cairo_operator: HARD_LIGHT
+ soft-light:
+ cairo_operator: SOFT_LIGHT
+ difference:
+ cairo_operator: DIFFERENCE
+ exclusion:
+ cairo_operator: EXCLUSION
+ hue:
+ cairo_operator: HSL_HUE
+ saturation:
+ cairo_operator: HSL_SATURATION
+ color:
+ cairo_operator: HSL_COLOR
+ luminosity:
+ cairo_operator: HSL_LUMINOSITY
+
+ - no_filter:
+ js_filter_code: // No filter.
+ cairo_filter_code: "# No filter."
+ filter:
+ js_filter_code: ctx.filter = 'drop-shadow(5px -5px 0px rgb(255, 154, 0))'
+ cairo_filter_code: |-
+ cr.push_group()
+ cr.set_operator(cairo.OPERATOR_OVER)
+ cr.translate(5, -5) # Filter offset.
+ cr.set_source(foreground)
+ cr.paint()
+ cr.set_operator(cairo.OPERATOR_IN)
+ cr.set_source_rgba(1, 154/255, 0)
+ cr.paint()
+ cr.pop_group_to_source()
+ cr.paint()
+
+ - no_shadow:
+ js_shadow_code: // No shadow.
+ cairo_shadow_code: "# No shadow."
+ shadow:
+ js_shadow_code: |-
+ ctx.shadowOffsetX = 20;
+ ctx.shadowOffsetY = 20;
+ ctx.shadowColor = 'rgb(154, 0, 154)';
+ cairo_shadow_code: |-
+ cr.push_group()
+ cr.set_operator(cairo.OPERATOR_OVER)
+ cr.translate(20, 20) # Shadow offset.
+ cr.set_source(filtered_foreground)
+ cr.paint()
+ cr.set_operator(cairo.OPERATOR_IN)
+ cr.set_source_rgb(154/255, 0, 154/255)
+ cr.paint()
+ cr.pop_group_to_source()
+ cr.paint()
+
+ - fillRect:
+ js_draw_code: |-
+ ctx.fillStyle = 'rgb(52, 255, 52)';
+ ctx.fillRect(5, 5, 50, 30);
+ drawImage:
+ js_draw_code: |-
+ const img_canvas = new OffscreenCanvas({{ size[0] }}, {{ size[1] }});
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, {{ size[0] }}, {{ size[1] }});
+ ctx.drawImage(img_canvas, 5, 5, 50, 30);
+ pattern:
+ js_draw_code: |-
+ const img_canvas = new OffscreenCanvas({{ size[0] }}, {{ size[1] }});
+ const img_ctx = img_canvas.getContext('2d');
+ img_ctx.fillStyle = 'rgb(52, 255, 52)';
+ img_ctx.fillRect(0, 0, {{ size[0] }}, {{ size[1] }});
+ ctx.fillStyle = ctx.createPattern(img_canvas, 'repeat');
+ ctx.fillRect(5, 5, 50, 30);
diff --git a/tests/wpt/tests/html/canvas/tools/yaml-new/text.yaml b/tests/wpt/tests/html/canvas/tools/yaml-new/text.yaml
index 4c2ae798596..78312640c08 100644
--- a/tests/wpt/tests/html/canvas/tools/yaml-new/text.yaml
+++ b/tests/wpt/tests/html/canvas/tools/yaml-new/text.yaml
@@ -2020,6 +2020,200 @@
() => tm.getTextClusters(text.length, text.length + 1) );
}
+- name: 2d.text.measure.text-clusters-position.tentative
+ desc: >-
+ Test that TextMetrics::getTextClusters() returns clusters that are
+ positioned according to the target align and baseline passed as options.
+ size: [500, 500]
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '40px CanvasTest';
+ const text = 'E';
+
+ // Origin for all the measurements is placed at the top left corner.
+ ctx.textAlign = 'left';
+ ctx.textBaseline = 'top';
+ let tm = ctx.measureText(text);
+
+ // X position.
+ @assert Math.abs(tm.getTextClusters({align: 'left'})[0].x) === 0;
+ @assert tm.getTextClusters({align: 'center'})[0].x === 20;
+ @assert tm.getTextClusters({align: 'right'})[0].x === 40;
+
+ // Y position.
+ @assert Math.abs(tm.getTextClusters({baseline: 'top'})[0].y) === 0;
+ @assert tm.getTextClusters({baseline: 'middle'})[0].y === 20;
+ @assert tm.getTextClusters({baseline: 'bottom'})[0].y === 40;
+ @assert tm.getTextClusters({baseline: 'alphabetic'})[0].y === 30;
+ variants:
+ - *load-font-variant-definition
+
+- name: 2d.text.measure.text-clusters-rendering-align.tentative
+ desc: >-
+ Test that fillTextCluster() correctly positions the text, taking into
+ account the textAlign from the context at the time the text was measured.
+ size: [250, 43]
+ code: |
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = '{{ ctx_align }}';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+ reference: |
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = canvas.width / 2;
+ const y = canvas.height / 2;
+
+ ctx.textAlign = '{{ ctx_align }}';
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ ctx.fillText(text, x, y);
+ variants_layout:
+ [single_file]
+ variants:
+ - ctx_align_left:
+ ctx_align: left
+ ctx_align_center:
+ ctx_align: center
+ ctx_align_right:
+ ctx_align: right
+
+- name: 2d.text.measure.text-clusters-rendering-baseline.tentative
+ desc: >-
+ Test that fillTextCluster() correctly positions the text, taking into
+ account the textBaseline from the context at the time the text was measured.
+ size: [180, 43]
+ code: |
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = '{{ ctx_baseline }}';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ // Rendering all clusters with the same (x, y) parameters must be
+ // equivalent to a fillText() call at (x, y).
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+ reference: |
+ ctx.font = '20px serif';
+ const text = 'Test ☺️ א';
+ const x = 20;
+ const y = canvas.height / 2;
+
+ ctx.textBaseline = '{{ ctx_baseline }}';
+ ctx.fillText(text, x, y);
+ variants_layout:
+ [single_file]
+ variants:
+ - ctx_baseline_top:
+ ctx_baseline: top
+ ctx_baseline_middle:
+ ctx_baseline: middle
+ ctx_baseline_bottom:
+ ctx_baseline: bottom
+ ctx_baseline_alphabetic:
+ ctx_baseline: alphabetic
+
+- name: 2d.text.measure.text-clusters-rendering-font-change.tentative
+ desc: >-
+ Test that fillTextCluster() renders in the font used originally when the
+ text was measured, even if the font set on the context has changed since.
+ size: [500, 200]
+ code: |
+ ctx.font = '50px sans-serif';
+ const text = 'Hello ♦️ World!';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ ctx.font = '80px serif';
+
+ const x = 100;
+ const y = 100;
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+ reference: |
+ ctx.font = '50px sans-serif';
+ const text = 'Hello ♦️ World!';
+ let tm = ctx.measureText(text);
+ const clusters = tm.getTextClusters();
+
+ const x = 100;
+ const y = 100;
+ ctx.fillText(text, x, y);
+
+- name: 2d.text.measure.text-clusters-range.tentative
+ desc: >-
+ Test that getTextClusters() and fillTextCluster() correctly render
+ different ranges of the input text.
+ test_type: promise
+ fonts:
+ - CanvasTest
+ size: [400, 300]
+ code: |
+ // Renders all the clusters in the list from position (x, y).
+ function renderClusters(clusters, x, y) {
+ for (const cluster of clusters) {
+ ctx.fillTextCluster(cluster, x, y);
+ }
+ }
+
+ {{ load_font }}
+
+ ctx.font = '50px CanvasTest';
+ ctx.textAlign = 'left';
+ ctx.textBaseline = 'top';
+ const text = 'EEEEE';
+ let tm = ctx.measureText(text);
+
+ // Background color.
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ ctx.fillStyle = '#0f0';
+
+ // Without the first character.
+ renderClusters(tm.getTextClusters(1, 5), 0, 0);
+ @assert pixel 5,5 ==~ 255,0,0,255;
+ @assert pixel 55,5 ==~ 0,255,0,255;
+ @assert pixel 105,5 ==~ 0,255,0,255;
+ @assert pixel 155,5 ==~ 0,255,0,255;
+ @assert pixel 205,5 ==~ 0,255,0,255;
+ // Without the last character.
+ renderClusters(tm.getTextClusters(0, 4), 0, 100);
+ @assert pixel 5,105 ==~ 0,255,0,255;
+ @assert pixel 55,105 ==~ 0,255,0,255;
+ @assert pixel 105,105 ==~ 0,255,0,255;
+ @assert pixel 155,105 ==~ 0,255,0,255;
+ @assert pixel 205,105 ==~ 255,0,0,255;
+ // Only the middle character.
+ renderClusters(tm.getTextClusters(2, 3), 0, 150);
+ @assert pixel 5,155 ==~ 255,0,0,255;
+ @assert pixel 55,155 ==~ 255,0,0,255;
+ @assert pixel 105,155 ==~ 0,255,0,255;
+ @assert pixel 155,155 ==~ 255,0,0,255;
+ @assert pixel 205,155 ==~ 255,0,0,255;
+ variants:
+ - *load-font-variant-definition
+
- name: 2d.text.drawing.style.absolute.spacing
desc: Testing letter spacing and word spacing with absolute length
code: |
diff --git a/tests/wpt/tests/html/dom/documents/dom-tree-accessors/nameditem-names.html b/tests/wpt/tests/html/dom/documents/dom-tree-accessors/nameditem-names.html
index 3f76d85a1bc..111738a1444 100644
--- a/tests/wpt/tests/html/dom/documents/dom-tree-accessors/nameditem-names.html
+++ b/tests/wpt/tests/html/dom/documents/dom-tree-accessors/nameditem-names.html
@@ -52,7 +52,7 @@ test(function() {
}, "An img name appears in a document's property names when the img has no id.");
test(function() {
- assert_true(names.includes("exposed_object"))
+ assert_true(names.includes("exposed_object_with_name"))
}, "An object name appears in a document's property names if the object is exposed.");
test(function() {
diff --git a/tests/wpt/tests/html/dom/elements/the-innertext-and-outertext-properties/innertext-whitespace-pre-line.html b/tests/wpt/tests/html/dom/elements/the-innertext-and-outertext-properties/innertext-whitespace-pre-line.html
new file mode 100644
index 00000000000..c5696df9de8
--- /dev/null
+++ b/tests/wpt/tests/html/dom/elements/the-innertext-and-outertext-properties/innertext-whitespace-pre-line.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<title>innerText with white-space:pre-line</title>
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1923829">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="a" style="white-space: pre-line">one&#10;two&#10;three&#10;four</div>
+
+<div id="b" style="white-space: pre">one&#10;two&#10;three&#10;four</div>
+
+<div id="c" style="white-space: pre-line">
+ one
+ two
+ <!-- comment -->
+ three
+ four
+</div>
+
+<div id="d" style="white-space: pre">
+ one
+ two
+ <!-- comment -->
+ three
+ four
+</div>
+
+<script>
+test(() => {
+ assert_equals(a.innerText, b.innerText);
+}, "innerText should be the same for the pre-line and pre examples");
+
+test(() => {
+ function collapseWhitespace(s) {
+ return s.replace(/ +/g, ' ') // collapse runs of spaces
+ .replace(/ $/mg, '') // strip trailing spaces
+ .replace(/^ /mg, '') // strip leading spaces
+ .replace(/\n\n+/g, '\n') // collapse runs of newlines
+ .replace(/^\n/, ''); // remove any initial newline
+ }
+ assert_equals(c.innerText, collapseWhitespace(d.innerText));
+}, "innerText has collapsed whitespace but preserved newlines with pre-line");
+</script>
diff --git a/tests/wpt/tests/html/rendering/non-replaced-elements/tables/table-align-float-ref.xhtml b/tests/wpt/tests/html/rendering/non-replaced-elements/tables/table-align-float-ref.xhtml
new file mode 100644
index 00000000000..fc6b7860575
--- /dev/null
+++ b/tests/wpt/tests/html/rendering/non-replaced-elements/tables/table-align-float-ref.xhtml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <meta charset="utf-8"/>
+ <title>Table align attribute reference</title>
+ <style type="text/css">
+ table { border: 1px solid black; width: 300px; }
+ .left { float: left; }
+ .center { margin-left: auto; margin-right: auto; }
+ .right { float: right; }
+ </style>
+</head>
+<body>
+ <table class="left">
+ <tr><td>Left aligned table</td></tr>
+ </table>
+ <br/>
+ <table class="center">
+ <tr><td>Center aligned table</td></tr>
+ </table>
+ <br/>
+ <table class="right">
+ <tr><td>Right aligned table</td></tr>
+ </table>
+</body>
+</html> \ No newline at end of file
diff --git a/tests/wpt/tests/html/rendering/non-replaced-elements/tables/table-align-float.xhtml b/tests/wpt/tests/html/rendering/non-replaced-elements/tables/table-align-float.xhtml
new file mode 100644
index 00000000000..05de0d6b280
--- /dev/null
+++ b/tests/wpt/tests/html/rendering/non-replaced-elements/tables/table-align-float.xhtml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <meta charset="utf-8"/>
+ <title>Table align attribute test</title>
+ <link rel="help" href="https://html.spec.whatwg.org/#tables-2"/>
+ <link rel="match" href="table-align-float-ref.xhtml"/>
+ <style type="text/css">
+ table { border: 1px solid black; width: 300px; }
+ </style>
+</head>
+<body>
+ <table align="LEFT">
+ <tr><td>Left aligned table</td></tr>
+ </table>
+ <br/>
+ <table align="CENTER">
+ <tr><td>Center aligned table</td></tr>
+ </table>
+ <br/>
+ <table align="RIGHT">
+ <tr><td>Right aligned table</td></tr>
+ </table>
+</body>
+</html> \ No newline at end of file
diff --git a/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/button-in-popover.tentative.html b/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/button-in-popover.tentative.html
new file mode 100644
index 00000000000..da217f03e15
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/button-in-popover.tentative.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/issues/9799">
+<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>
+
+<style>
+select, select::picker(select) {
+ appearance: base-select;
+}
+</style>
+
+<select>
+ <button id=invoker>invoker</button>
+ <option>one</option>
+ <option>two</option>
+ <button id=popover>popover button</button>
+</select>
+
+<script>
+promise_test(async () => {
+ const select = document.querySelector('select');
+ const invokerButton = document.getElementById('invoker');
+ const popoverButton = document.getElementById('popover');
+
+ await test_driver.click(invokerButton);
+ assert_true(select.matches(':open'),
+ 'Select should open after clicking the invoker button.');
+
+ let popoverButtonClicked = false;
+ popoverButton.onclick = () => popoverButtonClicked = true;
+ await test_driver.click(popoverButton);
+ assert_true(select.matches(':open'),
+ 'Clicking the button should not have closed the popover.');
+ assert_true(popoverButtonClicked,
+ 'The button in the popover should have gotten a click event when clicked.');
+}, 'Buttons in the popover should be rendered and should not close the popover when clicked.');
+</script>
diff --git a/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html b/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html
index 5aa4638f0be..1a5b059997b 100644
--- a/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html
+++ b/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html
@@ -42,6 +42,10 @@
</div>
</select>
+<select id=s7>
+ <input>
+</select>
+
<div id=afterlast>
keep this div after the last test case
</div>
@@ -101,6 +105,13 @@ test(() => {
}, 'Divs and imgs should be allowed as direct children of select and within options without a datalist.');
test(() => {
+ assert_equals(document.getElementById('s7').parentNode, document.body);
+ assert_equals(document.getElementById('s7').innerHTML, `
+ <input>
+`);
+}, 'Input tags should parse inside select instead of closing the select.');
+
+test(() => {
assert_equals(document.getElementById('afterlast').parentNode, document.body);
}, 'The last test should not leave any tags open after parsing.');
</script>
diff --git a/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/popover-dialog-does-not-block-mouse-events.html b/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/popover-dialog-does-not-block-mouse-events.html
new file mode 100644
index 00000000000..97f17410f70
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/popover-dialog-does-not-block-mouse-events.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Popover dialogs should not block mouse events</title>
+<link rel="author" title="Tim Nguyen" href="https://github.com/nt1m">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/interactive-elements.html#the-dialog-element">
+<style>
+ #div {
+ height: 100px;
+ width: 100px;
+ background: red;
+ }
+</style>
+<div id="div"></div>
+<dialog id="dialog" popover="manual"></dialog>
+
+<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>
+promise_test(async () => {
+ const dialog = document.getElementById("dialog");
+ dialog.showPopover();
+
+ const div = document.getElementById("div");
+ div.addEventListener("click", function(event) {
+ div.firedOn = true;
+ div.style.backgroundColor = "green";
+ });
+
+ var absoluteTop = 0;
+ var absoluteLeft = 0;
+ for (var parentNode = div; parentNode; parentNode = parentNode.offsetParent) {
+ absoluteLeft += parentNode.offsetLeft;
+ absoluteTop += parentNode.offsetTop;
+ }
+
+ const x = absoluteLeft + div.offsetWidth / 2;
+ const y = absoluteTop + div.offsetHeight / 2;
+ const actions = new test_driver.Actions()
+ .pointerMove(x, y)
+ .pointerDown()
+ .pointerUp()
+ .pointerMove(0, 0);
+ await actions.send();
+ assert_true(div.firedOn, "div should have gotten a click event.");
+}, "Ensure that popover dialogs do not block mouse events. To test manually, click the red box. The test succeeds if the red box turns green.");
+</script>
diff --git a/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html b/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html
index b30433f4a92..555dc03b019 100644
--- a/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html
+++ b/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html
@@ -1,6 +1,6 @@
<!doctype html>
<link rel="author" href="mailto:jarhar@chromium.org" />
-<link rel=author title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk">
+<link rel="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
<link rel="help" href="https://github.com/whatwg/html/pull/10091" />
<link rel="help" href="https://github.com/whatwg/html/issues/9733" />
<script src="/resources/testharness.js"></script>
@@ -257,5 +257,111 @@
mydialog.close();
await waitForTick();
}, `dialog.${methodName}() should coalesce asynchronous toggle events.`);
+
+ promise_test(async (t) => {
+ let attributeChanges = 0;
+ const mo = new MutationObserver((records) => {
+ attributeChanges += records.length;
+ });
+ mo.observe(mydialog, { attributeFilter: ['open'] });
+ t.add_cleanup(() => {
+ mo.disconnect();
+ });
+ mydialog.addEventListener("beforetoggle", () => {
+ mydialog[methodName]();
+ }, { once: true });
+
+ mydialog[methodName]();
+ assert_true(mydialog.open, "Dialog is open");
+ await waitForTick();
+ mo.takeRecords();
+ assert_equals(attributeChanges, 1, "Should have set open once");
+
+ attributeChanges = 0;
+ mydialog.addEventListener("beforetoggle", () => {
+ mydialog.close();
+ }, { once: true });
+
+ mydialog.close();
+ assert_false(mydialog.open, "Dialog is closed");
+ await waitForTick();
+ mo.takeRecords();
+ assert_equals(attributeChanges, 1, "Should have removed open once");
+ }, `dialog.${methodName}() should not double-set open/close if beforetoggle re-opens`);
+
+ promise_test(async (t) => {
+ const abortController = new AbortController();
+ const signal = abortController.signal;
+ const mydialog = document.getElementById("mydialog");
+ t.add_cleanup(() => {
+ abortController.abort();
+ mydialog.close();
+ document.body.prepend(mydialog);
+ });
+ mydialog.addEventListener("beforetoggle", () => {
+ mydialog.remove();
+ }, { once: true });
+ let toggleEventCounter = 0;
+ mydialog.addEventListener(
+ "toggle",
+ (event) => {
+ toggleEventCounter += 1;
+ },
+ { signal }
+ );
+
+ mydialog[methodName]();
+ assert_false(mydialog.isConnected, "Dialog is not connected");
+ if (methodName == 'show') {
+ assert_true(mydialog.open, "Dialog did open");
+ } else {
+ assert_false(mydialog.open, "Dialog did not open");
+ assert_false(mydialog.matches(':modal'), "Dialog is not modal");
+ }
+ await waitForTick();
+ if (methodName == 'show') {
+ assert_equals(toggleEventCounter, 1, "toggle event was fired");
+ } else {
+ assert_equals(toggleEventCounter, 0, "toggle event not fired");
+ }
+ }, `dialog.${methodName}() should not open if beforetoggle removes`);
+
+ promise_test(async (t) => {
+ const abortController = new AbortController();
+ const signal = abortController.signal;
+ t.add_cleanup(async () => {
+ try { mydialog.hidePopover(); } catch {}
+ try { mydialog.close(); } catch {}
+ mydialog.removeAttribute('popover');
+ abortController.abort();
+ await waitForTick();
+ });
+ mydialog.setAttribute('popover', '');
+ mydialog.addEventListener("beforetoggle", () => {
+ mydialog.showPopover();
+ }, { once: true });
+ let toggleEventCounter = 0;
+ mydialog.addEventListener(
+ "toggle",
+ (event) => {
+ toggleEventCounter += 1;
+ },
+ { signal }
+ );
+
+ mydialog[methodName]();
+ if (methodName == 'show') {
+ assert_true(mydialog.open, "Dialog did open");
+ } else {
+ assert_false(mydialog.open, "Dialog did not open");
+ assert_false(mydialog.matches(':modal'), "Dialog is not modal");
+ }
+ await waitForTick();
+ if (methodName == 'show') {
+ assert_equals(toggleEventCounter, 2, "toggle event was fired for show+showPopover");
+ } else {
+ assert_equals(toggleEventCounter, 1, "toggle event was fired for showPopover");
+ }
+ }, `dialog.${methodName}() should not open if beforetoggle calls showPopover`);
});
</script>
diff --git a/tests/wpt/tests/html/webappapis/update-rendering/child-document-raf-order.html b/tests/wpt/tests/html/webappapis/update-rendering/child-document-raf-order.html
index eccc1bde7fb..222c1af444e 100644
--- a/tests/wpt/tests/html/webappapis/update-rendering/child-document-raf-order.html
+++ b/tests/wpt/tests/html/webappapis/update-rendering/child-document-raf-order.html
@@ -47,17 +47,6 @@ callbacks for each.
<script>
-// Split array into chunks of len.
-function chunk (arr, len) {
- var chunks = [],
- i = 0,
- n = arr.length;
- while (i < n) {
- chunks.push(arr.slice(i, i += len));
- }
- return chunks;
-}
-
async_test(function (t) {
step_timeout(setup, 0);
@@ -119,20 +108,9 @@ async_test(function (t) {
});
let finish = t.step_func(function() {
-
- // The test requests rafs recursively,
- // but since all three rafs run as part of the same "update the rendering" task,
- // they should always come in a triplet.
- assert_equals(notification_sequence.length % 3, 0);
-
- let chunks = chunk(notification_sequence, 3);
- for (var i = 0; i < chunks.length; i++) {
- // Assert correct ordering per triplet of rafs.
- assert_array_equals(chunks[i],
- ["parent_raf", "first_child_raf", "second_child_raf"],
- "expected order of notifications");
- }
-
+ assert_array_equals(notification_sequence,
+ ["parent_raf", "first_child_raf", "second_child_raf"],
+ "expected order of notifications");
t.done();
});
});
diff --git a/tests/wpt/tests/interfaces/turtledove.idl b/tests/wpt/tests/interfaces/turtledove.idl
index ff48d311914..0309f5047b3 100644
--- a/tests/wpt/tests/interfaces/turtledove.idl
+++ b/tests/wpt/tests/interfaces/turtledove.idl
@@ -15,6 +15,7 @@ dictionary AuctionAd {
USVString buyerReportingId;
USVString buyerAndSellerReportingId;
+ sequence<USVString> selectableBuyerAndSellerReportingIds;
sequence<USVString> allowedReportingOrigins;
DOMString adRenderId;
};
@@ -89,16 +90,16 @@ dictionary AuctionAdConfig {
sequence<USVString> interestGroupBuyers;
Promise<any> auctionSignals;
Promise<any> sellerSignals;
- Promise<DOMString> directFromSellerSignalsHeaderAdSlot;
- Promise<record<USVString, USVString>> deprecatedRenderURLReplacements;
+ Promise<DOMString?> directFromSellerSignalsHeaderAdSlot;
+ Promise<record<USVString, USVString>?> deprecatedRenderURLReplacements;
unsigned long long sellerTimeout;
unsigned short sellerExperimentGroupId;
- Promise<record<USVString, any>> perBuyerSignals;
- Promise<record<USVString, unsigned long long>> perBuyerTimeouts;
- Promise<record<USVString, unsigned long long>> perBuyerCumulativeTimeouts;
+ Promise<record<USVString, any>?> perBuyerSignals;
+ Promise<record<USVString, unsigned long long>?> perBuyerTimeouts;
+ Promise<record<USVString, unsigned long long>?> perBuyerCumulativeTimeouts;
unsigned long long reportingTimeout;
USVString sellerCurrency;
- Promise<record<USVString, USVString>> perBuyerCurrencies;
+ Promise<record<USVString, USVString>?> perBuyerCurrencies;
record<USVString, unsigned short> perBuyerMultiBidLimits;
record<USVString, unsigned short> perBuyerGroupLimits;
record<USVString, unsigned short> perBuyerExperimentGroupIds;
@@ -198,6 +199,7 @@ dictionary GenerateBidOutput {
DOMString bidCurrency;
(DOMString or AdRender) render;
any ad;
+ USVString selectedBuyerAndSellerReportingId;
sequence<(DOMString or AdRender)> adComponents;
double adCost;
unrestricted double modelingSignals;
@@ -294,6 +296,7 @@ dictionary ReportingBrowserSignals {
USVString componentSeller;
USVString buyerAndSellerReportingId;
+ USVString selectedBuyerAndSellerReportingId;
};
dictionary ReportResultBrowserSignals : ReportingBrowserSignals {
diff --git a/tests/wpt/tests/mediacapture-insertable-streams/VideoTrackGenerator-with-window-tracks.https.html b/tests/wpt/tests/mediacapture-insertable-streams/VideoTrackGenerator-with-window-tracks.https.html
index 36fc4135e23..dfe000fbddb 100644
--- a/tests/wpt/tests/mediacapture-insertable-streams/VideoTrackGenerator-with-window-tracks.https.html
+++ b/tests/wpt/tests/mediacapture-insertable-streams/VideoTrackGenerator-with-window-tracks.https.html
@@ -64,11 +64,15 @@
const blob = new Blob([script], { type: 'text/javascript' });
const url = URL.createObjectURL(blob);
const worker = new Worker(url);
- await new Promise(resolve => worker.onmessage = () => {
- resolve();
- });
- URL.revokeObjectURL(url);
- return worker;
+ try {
+ await new Promise((resolve, reject) => {
+ worker.onmessage = resolve;
+ worker.onerror = (err) => reject(err.message);
+ });
+ return worker;
+ } finally {
+ URL.revokeObjectURL(url);
+ }
}
promise_test(async t => {
diff --git a/tests/wpt/tests/navigation-api/state/cross-document-away-and-back.html b/tests/wpt/tests/navigation-api/state/cross-document-away-and-back.html
index cccaebdf7b9..f531ec67715 100644
--- a/tests/wpt/tests/navigation-api/state/cross-document-away-and-back.html
+++ b/tests/wpt/tests/navigation-api/state/cross-document-away-and-back.html
@@ -1,11 +1,15 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
+<script src="resources/helpers.js"></script>
+<meta name="variant" content="?method=navigate">
+<meta name="variant" content="?method=updateCurrentEntry">
+
<iframe id="i" src="/common/blank.html"></iframe>
<script>
async_test(t => {
window.onload = t.step_func(() => {
- i.contentWindow.navigation.navigate("#", { history: "replace", state: { data : "value" } });
+ updateStateBasedOnTestVariant(i.contentWindow, { data : "value" });
assert_equals(i.contentWindow.navigation.entries().length, 1);
assert_equals(i.contentWindow.navigation.currentEntry.getState().data, "value");
diff --git a/tests/wpt/tests/navigation-api/state/cross-document-location-api.html b/tests/wpt/tests/navigation-api/state/cross-document-location-api.html
index 395d95c6fbe..5a22473e6bb 100644
--- a/tests/wpt/tests/navigation-api/state/cross-document-location-api.html
+++ b/tests/wpt/tests/navigation-api/state/cross-document-location-api.html
@@ -1,11 +1,15 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
+<script src="resources/helpers.js"></script>
+<meta name="variant" content="?method=navigate">
+<meta name="variant" content="?method=updateCurrentEntry">
+
<iframe id="i" src="/common/blank.html"></iframe>
<script>
async_test(t => {
window.onload = t.step_func(() => {
- i.contentWindow.navigation.navigate("#", { history: "replace", state: { data: "value" } });
+ updateStateBasedOnTestVariant(i.contentWindow, { data : "value" });
assert_equals(i.contentWindow.navigation.entries().length, 1);
assert_equals(i.contentWindow.navigation.currentEntry.getState().data, "value");
diff --git a/tests/wpt/tests/navigation-api/state/history-pushState.html b/tests/wpt/tests/navigation-api/state/history-pushState.html
index 7d3c79ba6ca..8c63f72e53b 100644
--- a/tests/wpt/tests/navigation-api/state/history-pushState.html
+++ b/tests/wpt/tests/navigation-api/state/history-pushState.html
@@ -1,9 +1,13 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
+<script src="resources/helpers.js"></script>
+<meta name="variant" content="?method=navigate">
+<meta name="variant" content="?method=updateCurrentEntry">
+
<script>
test(() => {
- navigation.navigate("#", { history: "replace", state: { data: "value" } });
+ updateStateBasedOnTestVariant(window, { data : "value" });
assert_equals(navigation.currentEntry.getState().data, "value");
history.pushState(1, "", "#push");
assert_equals(navigation.currentEntry.getState(), undefined);
diff --git a/tests/wpt/tests/navigation-api/state/history-replaceState.html b/tests/wpt/tests/navigation-api/state/history-replaceState.html
index bdf35616393..7098201caa7 100644
--- a/tests/wpt/tests/navigation-api/state/history-replaceState.html
+++ b/tests/wpt/tests/navigation-api/state/history-replaceState.html
@@ -1,9 +1,13 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
+<script src="resources/helpers.js"></script>
+<meta name="variant" content="?method=navigate">
+<meta name="variant" content="?method=updateCurrentEntry">
+
<script>
test(() => {
- navigation.navigate("#", { history: "replace", state: { data: "value" } });
+ updateStateBasedOnTestVariant(window, { data : "value" });
assert_equals(navigation.currentEntry.getState().data, "value");
history.replaceState(1, "", "#replace");
assert_equals(navigation.currentEntry.getState(), undefined);
diff --git a/tests/wpt/tests/navigation-api/state/location-reload.html b/tests/wpt/tests/navigation-api/state/location-reload.html
index bf1bc105fbf..5a566c66fd5 100644
--- a/tests/wpt/tests/navigation-api/state/location-reload.html
+++ b/tests/wpt/tests/navigation-api/state/location-reload.html
@@ -1,11 +1,15 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
+<script src="resources/helpers.js"></script>
+<meta name="variant" content="?method=navigate">
+<meta name="variant" content="?method=updateCurrentEntry">
+
<iframe id="i" src="/common/blank.html"></iframe>
<script>
async_test(t => {
window.onload = t.step_func(() => {
- i.contentWindow.navigation.navigate("#", { history: "replace", state: { data: "value" } });
+ updateStateBasedOnTestVariant(i.contentWindow, { data : "value" });
assert_equals(i.contentWindow.navigation.entries().length, 1);
assert_equals(i.contentWindow.navigation.currentEntry.getState().data, "value");
diff --git a/tests/wpt/tests/navigation-api/state/resources/helpers.js b/tests/wpt/tests/navigation-api/state/resources/helpers.js
new file mode 100644
index 00000000000..658d267351b
--- /dev/null
+++ b/tests/wpt/tests/navigation-api/state/resources/helpers.js
@@ -0,0 +1,18 @@
+window.updateStateBasedOnTestVariant = (w, state) => {
+ const usp = new URLSearchParams(location.search);
+ const method = usp.get("method");
+
+ switch (method) {
+ case "navigate": {
+ w.navigation.navigate("#", { history: "replace", state });
+ break;
+ }
+ case "updateCurrentEntry": {
+ w.navigation.updateCurrentEntry({ state });
+ break;
+ }
+ default: {
+ assert_unreached(`method must be either "navigate" or "updateCurrentEntry"`);
+ }
+ }
+};
diff --git a/tests/wpt/tests/navigation-api/updateCurrentEntry-method/cross-document-away-and-back.html b/tests/wpt/tests/navigation-api/updateCurrentEntry-method/cross-document-away-and-back.html
deleted file mode 100644
index c37d5e979a0..00000000000
--- a/tests/wpt/tests/navigation-api/updateCurrentEntry-method/cross-document-away-and-back.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!doctype html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<iframe id="i" src="/common/blank.html"></iframe>
-<script>
-async_test(t => {
- window.onload = t.step_func(() => {
- i.contentWindow.navigation.updateCurrentEntry({ state: { data: "value" } });
- assert_equals(i.contentWindow.navigation.entries().length, 1);
- assert_equals(i.contentWindow.navigation.currentEntry.getState().data, "value");
-
- let navigated_back = false;
- i.contentWindow.navigation.navigate("?1");
- i.onload = t.step_func(() => {
- if (navigated_back) {
- let back_entry = i.contentWindow.navigation.currentEntry;
- assert_equals(i.contentWindow.navigation.entries().length, 2);
- assert_equals(back_entry.index, 0);
- assert_equals(back_entry.getState().data, "value");
- t.done();
- } else {
- assert_equals(i.contentWindow.navigation.entries().length, 2);
- assert_equals(i.contentWindow.navigation.currentEntry, i.contentWindow.navigation.entries()[1]);
- assert_equals(i.contentWindow.navigation.currentEntry.getState(), undefined);
- history.back();
- navigated_back = true;
- }
- });
- });
-}, "entry.getState() behavior after navigating away and back");
-</script>
diff --git a/tests/wpt/tests/navigation-api/updateCurrentEntry-method/cross-document-location-api.html b/tests/wpt/tests/navigation-api/updateCurrentEntry-method/cross-document-location-api.html
deleted file mode 100644
index 26191fb8761..00000000000
--- a/tests/wpt/tests/navigation-api/updateCurrentEntry-method/cross-document-location-api.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!doctype html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<iframe id="i" src="/common/blank.html"></iframe>
-<script>
-async_test(t => {
- window.onload = t.step_func(() => {
- i.contentWindow.navigation.updateCurrentEntry({ state: { data: "value" } });
- assert_equals(i.contentWindow.navigation.entries().length, 1);
- assert_equals(i.contentWindow.navigation.currentEntry.getState().data, "value");
-
- i.contentWindow.location.href = "?1";
- i.onload = t.step_func_done(() => {
- assert_equals(i.contentWindow.navigation.entries().length, 2);
- assert_equals(i.contentWindow.navigation.currentEntry.index, 1);
- assert_equals(i.contentWindow.navigation.currentEntry.getState(), undefined);
- });
- });
-}, "entry.getState() behavior after cross-document location API navigation");
-</script>
diff --git a/tests/wpt/tests/navigation-api/updateCurrentEntry-method/history-pushState.html b/tests/wpt/tests/navigation-api/updateCurrentEntry-method/history-pushState.html
deleted file mode 100644
index 852294c64f4..00000000000
--- a/tests/wpt/tests/navigation-api/updateCurrentEntry-method/history-pushState.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!doctype html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-test(() => {
- navigation.updateCurrentEntry({ state : { data : "value" } });
- assert_equals(navigation.currentEntry.getState().data, "value");
- history.pushState(1, "", "#push");
- assert_equals(navigation.currentEntry.getState(), undefined);
-}, "entry.getState() after history.pushState()");
-</script>
diff --git a/tests/wpt/tests/navigation-api/updateCurrentEntry-method/history-replaceState.html b/tests/wpt/tests/navigation-api/updateCurrentEntry-method/history-replaceState.html
deleted file mode 100644
index 3eb91a9a80c..00000000000
--- a/tests/wpt/tests/navigation-api/updateCurrentEntry-method/history-replaceState.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!doctype html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-test(() => {
- navigation.updateCurrentEntry({ state : { data : "value" } });
- assert_equals(navigation.currentEntry.getState().data, "value");
- history.replaceState(1, "", "#replace");
- assert_equals(navigation.currentEntry.getState(), undefined);
-}, "entry.getState() after history.replaceState()");
-</script>
diff --git a/tests/wpt/tests/navigation-api/updateCurrentEntry-method/location-reload.html b/tests/wpt/tests/navigation-api/updateCurrentEntry-method/location-reload.html
deleted file mode 100644
index 8589eeb694e..00000000000
--- a/tests/wpt/tests/navigation-api/updateCurrentEntry-method/location-reload.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!doctype html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<iframe id="i" src="/common/blank.html"></iframe>
-<script>
-async_test(t => {
- window.onload = t.step_func(() => {
- i.contentWindow.navigation.updateCurrentEntry({ state: { data: "value" } });
- assert_equals(i.contentWindow.navigation.entries().length, 1);
- assert_equals(i.contentWindow.navigation.currentEntry.getState().data, "value");
-
- i.contentWindow.location.reload();
- i.onload = t.step_func_done(() => {
- assert_equals(i.contentWindow.navigation.entries().length, 1);
- assert_equals(i.contentWindow.navigation.currentEntry.getState().data, "value");
- });
- });
-}, "entry.getState() after location.reload()");
-</script>
diff --git a/tests/wpt/tests/permissions-policy/resources/digital-credentials-get.html b/tests/wpt/tests/permissions-policy/resources/digital-credentials-get.html
index 489e4291359..543417f230a 100644
--- a/tests/wpt/tests/permissions-policy/resources/digital-credentials-get.html
+++ b/tests/wpt/tests/permissions-policy/resources/digital-credentials-get.html
@@ -27,6 +27,7 @@
window.parent.postMessage({ type, enabled }, "*");
}
}
+ test_driver.set_test_context(parent);
window.onload = notify;
</script>
<body>
diff --git a/tests/wpt/tests/sanitizer-api/html5lib-basics.tentative.html b/tests/wpt/tests/sanitizer-api/html5lib-basics.tentative.html
new file mode 100644
index 00000000000..1df4d49f704
--- /dev/null
+++ b/tests/wpt/tests/sanitizer-api/html5lib-basics.tentative.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<head>
+<title>Basic setHTMLUnsafe test cases</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/html5lib-testcase-support.js"></script
+</head>
+<body>
+<script type="html5lib-tests">
+#data
+Hello!
+#document
+| "Hello!"
+
+#data
+<p>bla
+#document
+| <p>
+| "bla"
+
+#data
+<p id=abc def='123'>texty<!-- xxx -->textz
+#document
+| <p>
+| def="123"
+| id="abc"
+| "texty"
+| <!-- xxx -->
+| "textz"
+
+#data
+<p>Hello <b>World</b><span>!
+#document
+| <p>
+| "Hello "
+| <b>
+| "World"
+| <span>
+| "!"
+
+#data
+<p>A template example.<template>Hello <b>World</b></template>!
+#document
+| <p>
+| "A template example."
+| <template>
+| content
+| "Hello "
+| <b>
+| "World"
+| "!"
+
+#data
+<td>Interesting parse context.</td>
+#document-fragment
+table
+#document
+| <tbody>
+| <tr>
+| <td>
+| "Interesting parse context."
+
+#data
+<p>A rather boring parse context.
+#document-fragment
+p
+#document
+| <p>
+| "A rather boring parse context."
+
+</script>
+<script>
+// This runs a number of simple test cases that test setHTMLUnsafe, and
+// setHTMLUnsafe vs innerHTML. This purposely doesn't include "advanced" test
+// cases where the behaviours of those two methodsis supposed to differ.
+//
+// This sort of also doubles as unit tests for html5lib-testcase-support.js
+html5lib_testcases_from_script().forEach((testcase, index) => {
+ test(_ => {
+ const context = document.createElement(testcase["document-fragment"] ?? "div");
+ context.setHTMLUnsafe(testcase.data);
+ assert_testcase(context, testcase);
+ }, `Testcase #${index} with .setHTMLUnsafe("${testcase.data}")`);
+
+ test(_ => {
+ const context_element = testcase["document-fragment"] ?? "div";
+ const context = document.createElement(context_element);
+ const context2 = document.createElement(context_element);
+
+ context.setHTMLUnsafe(testcase.data);
+ context2.innerHTML = testcase.data;
+ assert_subtree_equals(context, context2);
+ }, `Testcase #${index}, .innerHTML matches .setHTMLUnsafe`);
+});
+</script>
diff --git a/tests/wpt/tests/sanitizer-api/support/html5lib-testcase-support.js b/tests/wpt/tests/sanitizer-api/support/html5lib-testcase-support.js
new file mode 100644
index 00000000000..4f15e46a7eb
--- /dev/null
+++ b/tests/wpt/tests/sanitizer-api/support/html5lib-testcase-support.js
@@ -0,0 +1,196 @@
+// This library supports HTML5lib-style test cases.
+//
+// The HTMLlib test case format describes an actual DOM tree. For testing, and
+// particular for testing of DOM parsers and DOM parser-related functionality,
+// this has the advantage of being able to represent edge cases.
+//
+// Example: If `.replaceWithChildren` is called on the `<span>` element as a
+// result of parsing `"<p>Hello<span>World</span></p>"`, then this results in
+// a tree with two adjacent text nodes. This behaviour will affect subsequent
+// DOM operations and should thus be tested. The HTML5lib format makes it easy
+// to describe the expected result unambiguously.
+//
+// References:
+// - HTML5lib: https://github.com/html5lib
+// - HTML5lib testcases: https://github.com/html5lib/html5lib-tests/tree/master/tree-construction
+// - test case format description:
+// https://github.com/html5lib/html5lib-tests/blob/master/tree-construction/README.md
+//
+// The main "API" is:
+//
+// - parse_html5lib_testcases(string)
+// This returns an array of dictionaries, where the dictionary contains the
+// the text of the test file, keyed by the lines starting with a hashtag.
+//
+// E.g. #data\nbla results in [{data: "bla"}].
+//
+// - html5lib_testcases_from_script()
+// Wrapper for parse_html5lib_testcases that gets the test data from a script
+// element with type "html5lib-tests". This allows to specify the test data
+// in the test file, but requires working around closing script tags.
+//
+// - html5lib_testcases_from_response(response_promise)
+// Wrapper for parse_html5lib_testcases that gets the data from a Response
+// Promise, as is returned from `fetch()`, and returns a Promise for the array
+// of testcases. This allows getting the test dat from a text resource.
+//
+// - build_node_tree(node, documentstr)
+// This builds a node tree from the "#document" string from a testcase, and
+// appends it to the node argument. Returns node.
+//
+// - assert_subtree_equals(node1, node2)
+// Asserts that the child trees of node1 and node2 are equals. This
+// recursively descends the trees.
+//
+// - assert_testcase(node, testcase)
+// Wrapper for build_node_tree and assert_subtree_equals, for use with a
+// result of parse_html5lib_testcases.
+//
+
+function html5lib_testcases_from_script() {
+ return parse_html5lib_testcases(
+ document.querySelector("script[type='html5lib-tests']").textContent);
+}
+
+function html5lib_testcases_from_response(response_promise) {
+ return response_promise
+ .then(response => response.text())
+ .then(parse_html5lib_testcases);
+}
+
+function add_html5lib_testcase(testcases, current) {
+ for (const item in current) {
+ current[item] = current[item].join("\n");
+ }
+ if (Object.entries(current).length) {
+ testcases.push(current);
+ }
+}
+
+function parse_html5lib_testcases(content) {
+ const testcases = [];
+ var state = undefined;
+ var current = {};
+ for (const line of content.split("\n")) {
+ if (!line) {
+ add_html5lib_testcase(testcases, current);
+ state = undefined;
+ current = {};
+ } else if (line[0] == "#") {
+ state = line.substring(1);
+ current[state] = [];
+ } else if (state) {
+ current[state].push(line);
+ } else {
+ // Error handling is for another day.
+ }
+ }
+ return testcases;
+}
+
+function get_child_at(node, level) {
+ for (i = 0; i < level; i++) {
+ if (is_html_template(node)) {
+ // For <template>, continue with the content fragment.
+ node = node.content;
+ } else {
+ node = node.lastChild;
+ }
+ }
+ return node;
+}
+
+function append_child_at(node, level, child) {
+ get_child_at(node, level).appendChild(child);
+}
+
+function is_element(node) {
+ return node.tagName && node.namespaceURI;
+}
+
+function is_html_template(node) {
+ return is_element(node) && node.tagName == "TEMPLATE" &&
+ node.namespaceURI == "http://www.w3.org/1999/xhtml";
+}
+
+function build_node_tree(root, docstr) {
+ // Format described here:
+ // https://github.com/html5lib/html5lib-tests/blob/master/tree-construction/README.md
+ for (const line of docstr.split("\n")) {
+ const [_, indent, remainder] = line.match(/^\| ( *)(.*)/);
+ const level = indent.length / 2;
+ if (match = remainder.match(/^<([a-z]*)>$/)) {
+ // `Element nodes must be represented by a "<, the tag name string, ">".`
+ append_child_at(root, level, document.createElement(match[1]));
+ } else if (match = remainder.match(/^"([^"]*)"$/)) {
+ // `Text nodes must be the string, in double quotes.`
+ append_child_at(root, level, document.createTextNode(match[1]));
+ } else if (match = remainder.match(/^(.*)="(.*)"$/)) {
+ // `Attribute nodes must have the attribute name string, then an "=" sign,
+ // then the attribute value in double quotes (").`
+ get_child_at(root, level).setAttribute(match[1], match[2]);
+ } else if (match = remainder.match(/^<!--(.*)-->$/)) {
+ // `Comments must be "<" then "!-- " then the data then " -->".`
+ append_child_at(root, level, document.createComment(match[1]));
+ } else if (match = remainder.match(
+ /^<!DOCTYPE ([^ ]*)( "([^"]*)"( "([^"]*)")?)?>$/)) {
+ // `DOCTYPEs must be "<!DOCTYPE " then [... bla bla ...]`
+ append_child_at(root, level,
+ document.implementation.createDocumentType(match[1], match[3], match[5]));
+ } else if (match = remainder.match(/^<?([a-z]*)( (.*))>$/)) {
+ // `Processing instructions must be "<?", then the target, then [...]`
+ append_child_at(root, level, document.createProcessingInstruction(
+ match[1], match[3]));
+ } else if (remainder == "content") {
+ // Template contents are represented by the string "content" with the
+ // children below it.
+ // Nothing to do here; so let's just check we're actually in a template.
+ assert_true(is_html_template(get_child_at(root, level)),
+ "\"content\" only expected as child of a <template>.");
+ } else {
+ assert_unreached(
+ `Unknown line type. Maybe test data is malformed. ("${line}")`);
+ }
+ }
+ return root;
+}
+
+function assert_subtree_equals(node1, node2) {
+ // Iterate in parallel over both trees.
+ const tree1 = document.createNodeIterator(node1);
+ const tree2 = document.createNodeIterator(node2);
+ // Skip the root/context node, so that we can re-use the test with different
+ // context types.
+ var current1 = tree1.nextNode();
+ var current2 = tree2.nextNode();
+ do {
+ current1 = tree1.nextNode();
+ current2 = tree2.nextNode();
+
+ // Conceptually, we only want to check whether a.isEqualNode(b). But that
+ // yields terrible error messages ("expected true but got false"). With
+ // this being a test suite and all, let's invest a bit of effort into nice
+ // error messages.
+ if (current1 && !current1.isEqualNode(current2)) {
+ let breadcrumbs = "";
+ let current = current1;
+ while (current) {
+ const here = is_element(current) ? `<${current.tagName}>` : `${current}`;
+ breadcrumbs = `${here} / ${breadcrumbs}`;
+ current = current.parentNode;
+ }
+ breadcrumbs = breadcrumbs.substring(0, breadcrumbs.length - 3);
+ assert_true(current1.isEqualNode(current2),
+ `${current1}.isEqual(${current2}) fails. Path: ${breadcrumbs}.`);
+ }
+ } while (current1);
+
+ // Ensure that both iterators have come to an end.
+ assert_false(!!current2, "Additional nodes at the of node2.");
+}
+
+function assert_testcase(node, testcase) {
+ const context = document.createElement(testcase["document-fragment"] ?? "div");
+ const tree = build_node_tree(context, testcase.document);
+ assert_subtree_equals(node, tree);
+}
diff --git a/tests/wpt/tests/scroll-animations/css/animation-timeline-computed.html b/tests/wpt/tests/scroll-animations/css/animation-timeline-computed.html
index 1e621eee531..51454f6853d 100644
--- a/tests/wpt/tests/scroll-animations/css/animation-timeline-computed.html
+++ b/tests/wpt/tests/scroll-animations/css/animation-timeline-computed.html
@@ -69,5 +69,8 @@ test_computed_value('animation-timeline', 'view(y 1px auto)');
test_computed_value('animation-timeline', 'view(1px y)', 'view(y 1px)');
test_computed_value('animation-timeline', 'view(y auto)', 'view(y)');
test_computed_value('animation-timeline', 'view(y auto auto)', 'view(y)');
+test_computed_value('animation-timeline', 'view(10% 10px)', 'view(10% 10px)');
+test_computed_value('animation-timeline', 'view(auto calc(1% + 1px))');
+test_computed_value('animation-timeline', 'view(2em calc(1% + 1em))', 'view(32px calc(1% + 16px))');
</script>
diff --git a/tests/wpt/tests/scroll-animations/css/animation-timeline-parsing.html b/tests/wpt/tests/scroll-animations/css/animation-timeline-parsing.html
index 9e3c1078b5b..44e9caf002e 100644
--- a/tests/wpt/tests/scroll-animations/css/animation-timeline-parsing.html
+++ b/tests/wpt/tests/scroll-animations/css/animation-timeline-parsing.html
@@ -75,6 +75,7 @@ test_valid_value('animation-timeline', 'view(1px)');
test_valid_value('animation-timeline', 'view(1px 1px)', 'view(1px)');
test_valid_value('animation-timeline', 'view(1px auto)');
test_valid_value('animation-timeline', 'view(auto calc(1% + 1px))');
+test_valid_value('animation-timeline', 'view(2em calc(1% + 1em))');
test_valid_value('animation-timeline', 'view(auto)', 'view()');
test_valid_value('animation-timeline', 'view(auto auto)', 'view()');
diff --git a/tests/wpt/tests/scroll-animations/scroll-timelines/setting-current-time.html b/tests/wpt/tests/scroll-animations/scroll-timelines/setting-current-time.html
index f6c826db699..5daa459bbeb 100644
--- a/tests/wpt/tests/scroll-animations/scroll-timelines/setting-current-time.html
+++ b/tests/wpt/tests/scroll-animations/scroll-timelines/setting-current-time.html
@@ -42,13 +42,13 @@ promise_test(async t => {
promise_test(async t => {
const animation = createScrollLinkedAnimation(t);
- assert_throws_dom('NotSupportedError', () => {
+ assert_throws_js(TypeError, () => {
animation.currentTime = CSSNumericValue.parse("300");
});
- assert_throws_dom('NotSupportedError', () => {
+ assert_throws_js(TypeError, () => {
animation.currentTime = CSSNumericValue.parse("300ms");
});
- assert_throws_dom('NotSupportedError', () => {
+ assert_throws_js(TypeError, () => {
animation.currentTime = CSSNumericValue.parse("0.3s");
});
}, 'Setting the current time to an absolute time value throws exception');
diff --git a/tests/wpt/tests/scroll-animations/scroll-timelines/setting-start-time.html b/tests/wpt/tests/scroll-animations/scroll-timelines/setting-start-time.html
index aae1849565b..d950eb8188d 100644
--- a/tests/wpt/tests/scroll-animations/scroll-timelines/setting-start-time.html
+++ b/tests/wpt/tests/scroll-animations/scroll-timelines/setting-start-time.html
@@ -26,13 +26,13 @@
promise_test(async t => {
const animation = createScrollLinkedAnimation(t);
- assert_throws_dom('NotSupportedError', () => {
+ assert_throws_js(TypeError, () => {
animation.startTime = CSSNumericValue.parse("300");
});
- assert_throws_dom('NotSupportedError', () => {
+ assert_throws_js(TypeError, () => {
animation.startTime = CSSNumericValue.parse("300ms");
});
- assert_throws_dom('NotSupportedError', () => {
+ assert_throws_js(TypeError, () => {
animation.startTime = CSSNumericValue.parse("0.3s");
});
}, 'Setting the start time to an absolute time value throws exception');
diff --git a/tests/wpt/tests/selection/caret-position-should-be-correct-while-moveup-movedown.html b/tests/wpt/tests/selection/caret-position-should-be-correct-while-moveup-movedown.html
new file mode 100644
index 00000000000..45d95a96b04
--- /dev/null
+++ b/tests/wpt/tests/selection/caret-position-should-be-correct-while-moveup-movedown.html
@@ -0,0 +1,450 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <style>
+ .vertical-lr {
+ writing-mode: vertical-lr;
+ border: 1px solid black;
+ padding: 10px;
+ width: 100px;
+ height: 200px;
+ }
+ .vertical-rl {
+ writing-mode: vertical-rl;
+ border: 1px solid black;
+ padding: 10px;
+ width: 100px;
+ height: 200px;
+ }
+ </style>
+ </head>
+ <body>
+ <div contenteditable id="horizontal">text1<br />text2</div>
+ <div contenteditable class="vertical-lr" id="vertical_lr">
+ text1<br />
+ text2
+ </div>
+ <div contenteditable class="vertical-rl" id="vertical_rl">
+ text1<br />
+ text2
+ </div>
+
+ <script>
+ const horizontal = document.getElementById("horizontal");
+ const verticalLR = document.getElementById("vertical_lr");
+ const verticalRL = document.getElementById("vertical_rl");
+ const tests = [
+ {
+ elementUnderTest: horizontal,
+ startNode: horizontal.childNodes[2],
+ endNode: horizontal.childNodes[0],
+ anchorOffset: horizontal.childNodes[2].textContent.indexOf(
+ horizontal.childNodes[2].textContent.trim()
+ ),
+ focusOffset:
+ horizontal.childNodes[2].textContent.indexOf(
+ horizontal.childNodes[2].textContent.trim()
+ ) + horizontal.childNodes[2].textContent.trim().length,
+ direction: "backward",
+ granularity: "line",
+ description:
+ "Caret position should be correct in moving up horizontal div when selection was left to right with line granularity",
+ },
+ {
+ elementUnderTest: horizontal,
+ startNode: horizontal.childNodes[2],
+ endNode: horizontal.childNodes[0],
+ anchorOffset:
+ horizontal.childNodes[2].textContent.indexOf(
+ horizontal.childNodes[2].textContent.trim()
+ ) + horizontal.childNodes[2].textContent.trim().length,
+ focusOffset: horizontal.childNodes[2].textContent.indexOf(
+ horizontal.childNodes[2].textContent.trim()
+ ),
+ direction: "backward",
+ granularity: "line",
+ description:
+ "Caret position should be correct in moving up horizontal div when selection was right to left with line granularity",
+ },
+ {
+ elementUnderTest: horizontal,
+ startNode: horizontal.childNodes[0],
+ endNode: horizontal.childNodes[2],
+ anchorOffset: horizontal.childNodes[0].textContent.indexOf(
+ horizontal.childNodes[0].textContent.trim()
+ ),
+ focusOffset:
+ horizontal.childNodes[0].textContent.indexOf(
+ horizontal.childNodes[0].textContent.trim()
+ ) + horizontal.childNodes[0].textContent.trim().length,
+ direction: "forward",
+ granularity: "line",
+ description:
+ "Caret position should be correct in moving down horizontal div when selection was left to right with line granularity",
+ },
+ {
+ elementUnderTest: horizontal,
+ startNode: horizontal.childNodes[0],
+ endNode: horizontal.childNodes[2],
+ anchorOffset:
+ horizontal.childNodes[0].textContent.indexOf(
+ horizontal.childNodes[0].textContent.trim()
+ ) + horizontal.childNodes[0].textContent.trim().length,
+ focusOffset: horizontal.childNodes[0].textContent.indexOf(
+ horizontal.childNodes[0].textContent.trim()
+ ),
+ direction: "forward",
+ granularity: "line",
+ description:
+ "Caret position should be correct in moving down horizontal div when selection was right to left with line granularity",
+ },
+ {
+ elementUnderTest: horizontal,
+ startNode: horizontal.childNodes[2],
+ endNode: horizontal.childNodes[0],
+ anchorOffset: horizontal.childNodes[2].textContent.indexOf(
+ horizontal.childNodes[2].textContent.trim()
+ ),
+ focusOffset:
+ horizontal.childNodes[2].textContent.indexOf(
+ horizontal.childNodes[2].textContent.trim()
+ ) + horizontal.childNodes[2].textContent.trim().length,
+ direction: "backward",
+ granularity: "paragraph",
+ description:
+ "Caret position should be correct in moving up horizontal div when selection was left to right with paragraph granularity",
+ },
+ {
+ elementUnderTest: horizontal,
+ startNode: horizontal.childNodes[2],
+ endNode: horizontal.childNodes[0],
+ anchorOffset:
+ horizontal.childNodes[2].textContent.indexOf(
+ horizontal.childNodes[2].textContent.trim()
+ ) + horizontal.childNodes[2].textContent.trim().length,
+ focusOffset: horizontal.childNodes[2].textContent.indexOf(
+ horizontal.childNodes[2].textContent.trim()
+ ),
+ direction: "backward",
+ granularity: "paragraph",
+ description:
+ "Caret position should be correct in moving up horizontal div when selection was right to left with paragraph granularity",
+ },
+ {
+ elementUnderTest: horizontal,
+ startNode: horizontal.childNodes[0],
+ endNode: horizontal.childNodes[2],
+ anchorOffset: horizontal.childNodes[0].textContent.indexOf(
+ horizontal.childNodes[0].textContent.trim()
+ ),
+ focusOffset:
+ horizontal.childNodes[0].textContent.indexOf(
+ horizontal.childNodes[0].textContent.trim()
+ ) + horizontal.childNodes[0].textContent.trim().length,
+ direction: "forward",
+ granularity: "paragraph",
+ description:
+ "Caret position should be correct in moving down horizontal div when selection was left to right with paragraph granularity",
+ },
+ {
+ elementUnderTest: horizontal,
+ startNode: horizontal.childNodes[0],
+ endNode: horizontal.childNodes[2],
+ anchorOffset:
+ horizontal.childNodes[0].textContent.indexOf(
+ horizontal.childNodes[0].textContent.trim()
+ ) + horizontal.childNodes[0].textContent.trim().length,
+ focusOffset: horizontal.childNodes[0].textContent.indexOf(
+ horizontal.childNodes[0].textContent.trim()
+ ),
+ direction: "forward",
+ granularity: "paragraph",
+ description:
+ "Caret position should be correct in moving down horizontal div when selection was right to left with paragraph granularity",
+ },
+ {
+ elementUnderTest: verticalLR,
+ startNode: verticalLR.childNodes[0],
+ endNode: verticalLR.childNodes[2],
+ anchorOffset: verticalLR.childNodes[0].textContent.indexOf(
+ verticalLR.childNodes[0].textContent.trim()
+ ),
+ focusOffset:
+ verticalLR.childNodes[0].textContent.indexOf(
+ verticalLR.childNodes[0].textContent.trim()
+ ) + verticalLR.childNodes[0].textContent.trim().length,
+ direction: "forward",
+ granularity: "line",
+ description:
+ "Caret position should be correct in move right with line granularity for vertical-lr div when selection was top to bottom",
+ },
+ {
+ elementUnderTest: verticalLR,
+ startNode: verticalLR.childNodes[0],
+ endNode: verticalLR.childNodes[2],
+ anchorOffset:
+ verticalLR.childNodes[0].textContent.indexOf(
+ verticalLR.childNodes[0].textContent.trim()
+ ) + verticalLR.childNodes[0].textContent.trim().length,
+ focusOffset: verticalLR.childNodes[0].textContent.indexOf(
+ verticalLR.childNodes[0].textContent.trim()
+ ),
+ direction: "forward",
+ granularity: "line",
+ description:
+ "Caret position should be correct in move right with line granularity for vertical-lr div when selection was bottom to top",
+ },
+ {
+ elementUnderTest: verticalLR,
+ startNode: verticalLR.childNodes[2],
+ endNode: verticalLR.childNodes[0],
+ anchorOffset: verticalLR.childNodes[2].textContent.indexOf(
+ verticalLR.childNodes[2].textContent.trim()
+ ),
+ focusOffset:
+ verticalLR.childNodes[2].textContent.indexOf(
+ verticalLR.childNodes[2].textContent.trim()
+ ) + verticalLR.childNodes[2].textContent.trim().length,
+ direction: "backward",
+ granularity: "line",
+ description:
+ "Caret position should be correct in move left with line granularity for vertical-lr div when selection was top to bottom",
+ },
+ {
+ elementUnderTest: verticalLR,
+ startNode: verticalLR.childNodes[2],
+ endNode: verticalLR.childNodes[0],
+ anchorOffset:
+ verticalLR.childNodes[2].textContent.indexOf(
+ verticalLR.childNodes[2].textContent.trim()
+ ) + verticalLR.childNodes[2].textContent.trim().length,
+ focusOffset: verticalLR.childNodes[2].textContent.indexOf(
+ verticalLR.childNodes[2].textContent.trim()
+ ),
+ direction: "backward",
+ granularity: "line",
+ description:
+ "Caret position should be correct in move left with line granularity for vertical-lr div when selection was bottom to top",
+ },
+ {
+ elementUnderTest: verticalLR,
+ startNode: verticalLR.childNodes[0],
+ endNode: verticalLR.childNodes[2],
+ anchorOffset: verticalLR.childNodes[0].textContent.indexOf(
+ verticalLR.childNodes[0].textContent.trim()
+ ),
+ focusOffset:
+ verticalLR.childNodes[0].textContent.indexOf(
+ verticalLR.childNodes[0].textContent.trim()
+ ) + verticalLR.childNodes[0].textContent.trim().length,
+ direction: "forward",
+ granularity: "paragraph",
+ description:
+ "Caret position should be correct in move right with paragraph granularity for vertical-lr div when selection was top to bottom",
+ },
+ {
+ elementUnderTest: verticalLR,
+ startNode: verticalLR.childNodes[0],
+ endNode: verticalLR.childNodes[2],
+ anchorOffset:
+ verticalLR.childNodes[0].textContent.indexOf(
+ verticalLR.childNodes[0].textContent.trim()
+ ) + verticalLR.childNodes[0].textContent.trim().length,
+ focusOffset: verticalLR.childNodes[0].textContent.indexOf(
+ verticalLR.childNodes[0].textContent.trim()
+ ),
+ direction: "forward",
+ granularity: "paragraph",
+ description:
+ "Caret position should be correct in move right with paragraph granularity for vertical-lr div when selection was bottom to top",
+ },
+ {
+ elementUnderTest: verticalLR,
+ startNode: verticalLR.childNodes[2],
+ endNode: verticalLR.childNodes[0],
+ anchorOffset: verticalLR.childNodes[2].textContent.indexOf(
+ verticalLR.childNodes[2].textContent.trim()
+ ),
+ focusOffset:
+ verticalLR.childNodes[2].textContent.indexOf(
+ verticalLR.childNodes[2].textContent.trim()
+ ) + verticalLR.childNodes[2].textContent.trim().length,
+ direction: "backward",
+ granularity: "paragraph",
+ description:
+ "Caret position should be correct in move left with paragraph granularity for vertical-lr div when selection was top to bottom",
+ },
+ {
+ elementUnderTest: verticalLR,
+ startNode: verticalLR.childNodes[2],
+ endNode: verticalLR.childNodes[0],
+ anchorOffset:
+ verticalLR.childNodes[2].textContent.indexOf(
+ verticalLR.childNodes[2].textContent.trim()
+ ) + verticalLR.childNodes[2].textContent.trim().length,
+ focusOffset: verticalLR.childNodes[2].textContent.indexOf(
+ verticalLR.childNodes[2].textContent.trim()
+ ),
+ direction: "backward",
+ granularity: "paragraph",
+ description:
+ "Caret position should be correct in move left with paragraph granularity for vertical-lr div when selection was bottom to top",
+ },
+ {
+ elementUnderTest: verticalLR,
+ startNode: verticalLR.childNodes[0],
+ endNode: verticalLR.childNodes[2],
+ anchorOffset: verticalLR.childNodes[0].textContent.indexOf(
+ verticalLR.childNodes[0].textContent.trim()
+ ),
+ focusOffset:
+ verticalLR.childNodes[0].textContent.indexOf(
+ verticalLR.childNodes[0].textContent.trim()
+ ) + verticalLR.childNodes[0].textContent.trim().length,
+ direction: "forward",
+ granularity: "line",
+ description:
+ "Caret position should be correct in move left with line granularity for vertical-rl div when selection was top to bottom",
+ },
+ {
+ elementUnderTest: verticalLR,
+ startNode: verticalLR.childNodes[0],
+ endNode: verticalLR.childNodes[2],
+ anchorOffset:
+ verticalLR.childNodes[0].textContent.indexOf(
+ verticalLR.childNodes[0].textContent.trim()
+ ) + verticalLR.childNodes[0].textContent.trim().length,
+ focusOffset: verticalLR.childNodes[0].textContent.indexOf(
+ verticalLR.childNodes[0].textContent.trim()
+ ),
+ direction: "forward",
+ granularity: "line",
+ description:
+ "Caret position should be correct in move left with line granularity for vertical-rl div when selection was bottom to top",
+ },
+ {
+ elementUnderTest: verticalLR,
+ startNode: verticalLR.childNodes[2],
+ endNode: verticalLR.childNodes[0],
+ anchorOffset: verticalLR.childNodes[2].textContent.indexOf(
+ verticalLR.childNodes[2].textContent.trim()
+ ),
+ focusOffset:
+ verticalLR.childNodes[2].textContent.indexOf(
+ verticalLR.childNodes[2].textContent.trim()
+ ) + verticalLR.childNodes[2].textContent.trim().length,
+ direction: "backward",
+ granularity: "line",
+ description:
+ "Caret position should be correct in move right with line granularity for vertical-rl div when selection was top to bottom",
+ },
+ {
+ elementUnderTest: verticalLR,
+ startNode: verticalLR.childNodes[2],
+ endNode: verticalLR.childNodes[0],
+ anchorOffset:
+ verticalLR.childNodes[2].textContent.indexOf(
+ verticalLR.childNodes[2].textContent.trim()
+ ) + verticalLR.childNodes[2].textContent.trim().length,
+ focusOffset: verticalLR.childNodes[2].textContent.indexOf(
+ verticalLR.childNodes[2].textContent.trim()
+ ),
+ direction: "backward",
+ granularity: "line",
+ description:
+ "Caret position should be correct in move right with line granularity for vertical-rl div when selection was bottom to top",
+ },
+ {
+ elementUnderTest: verticalLR,
+ startNode: verticalLR.childNodes[0],
+ endNode: verticalLR.childNodes[2],
+ anchorOffset: verticalLR.childNodes[0].textContent.indexOf(
+ verticalLR.childNodes[0].textContent.trim()
+ ),
+ focusOffset:
+ verticalLR.childNodes[0].textContent.indexOf(
+ verticalLR.childNodes[0].textContent.trim()
+ ) + verticalLR.childNodes[0].textContent.trim().length,
+ direction: "forward",
+ granularity: "line",
+ description:
+ "Caret position should be correct in move left with paragraph granularity for vertical-rl div when selection was top to bottom",
+ },
+ {
+ elementUnderTest: verticalLR,
+ startNode: verticalLR.childNodes[0],
+ endNode: verticalLR.childNodes[2],
+ anchorOffset:
+ verticalLR.childNodes[0].textContent.indexOf(
+ verticalLR.childNodes[0].textContent.trim()
+ ) + verticalLR.childNodes[0].textContent.trim().length,
+ focusOffset: verticalLR.childNodes[0].textContent.indexOf(
+ verticalLR.childNodes[0].textContent.trim()
+ ),
+ direction: "forward",
+ granularity: "line",
+ description:
+ "Caret position should be correct in move left with paragraph granularity for vertical-rl div when selection was bottom to top",
+ },
+ {
+ elementUnderTest: verticalLR,
+ startNode: verticalLR.childNodes[2],
+ endNode: verticalLR.childNodes[0],
+ anchorOffset: verticalLR.childNodes[2].textContent.indexOf(
+ verticalLR.childNodes[2].textContent.trim()
+ ),
+ focusOffset:
+ verticalLR.childNodes[2].textContent.indexOf(
+ verticalLR.childNodes[2].textContent.trim()
+ ) + verticalLR.childNodes[2].textContent.trim().length,
+ direction: "backward",
+ granularity: "line",
+ description:
+ "Caret position should be correct in move right with paragraph granularity for vertical-rl div when selection was top to bottom",
+ },
+ {
+ elementUnderTest: verticalLR,
+ startNode: verticalLR.childNodes[2],
+ endNode: verticalLR.childNodes[0],
+ anchorOffset:
+ verticalLR.childNodes[2].textContent.indexOf(
+ verticalLR.childNodes[2].textContent.trim()
+ ) + verticalLR.childNodes[2].textContent.trim().length,
+ focusOffset: verticalLR.childNodes[2].textContent.indexOf(
+ verticalLR.childNodes[2].textContent.trim()
+ ),
+ direction: "backward",
+ granularity: "line",
+ description:
+ "Caret position should be correct in move right with paragraph granularity for vertical-rl div when selection was bottom to top",
+ },
+ ];
+ for (const testData of tests) {
+ test(function () {
+ // Get the selection object and set startNode to it.
+ const selection = window.getSelection();
+ selection.removeAllRanges();
+ selection.setBaseAndExtent(
+ testData.startNode,
+ testData.anchorOffset,
+ testData.startNode,
+ testData.focusOffset
+ );
+ // Modify the selection as per the direction and granularity of the test
+ testData.elementUnderTest.focus();
+ selection.modify(
+ "move",
+ testData.direction,
+ testData.granularity
+ );
+ // After modification, the selection should should have collapsed and should be on the endNode of the test with offset same as the initial focus offset
+ assert_true(selection.isCollapsed);
+ assert_equals(selection.focusOffset, testData.focusOffset);
+ assert_equals(selection.focusNode, testData.endNode);
+ }, testData.description);
+ }
+ </script>
+ </body>
+</html>
diff --git a/tests/wpt/tests/selection/shadow-dom/tentative/Selection-getComposedRanges-collapsed.html b/tests/wpt/tests/selection/shadow-dom/tentative/Selection-getComposedRanges-collapsed.html
index 99ab82eb39c..3ea6e0c62c7 100644
--- a/tests/wpt/tests/selection/shadow-dom/tentative/Selection-getComposedRanges-collapsed.html
+++ b/tests/wpt/tests/selection/shadow-dom/tentative/Selection-getComposedRanges-collapsed.html
@@ -14,7 +14,7 @@
</div>
<div id="host2">
<template shadowrootmode=open>D</template>
- <div id=b>B - not slotted</div>
+ B - not slotted
</div>
</div>
@@ -25,20 +25,6 @@ const d = host2.shadowRoot;
test(() => {
const sel = getSelection();
- sel.setBaseAndExtent(b, 0, c, 0);
- assert_equals(sel.getRangeAt(0).startContainer, b);
- assert_equals(sel.getRangeAt(0).startOffset, 0);
- assert_equals(sel.getRangeAt(0).endContainer, b);
- assert_equals(sel.getRangeAt(0).endOffset, 0);
-
- assert_equals(sel.getComposedRanges()[0].startContainer, b);
- assert_equals(sel.getComposedRanges()[0].startOffset, 0);
- assert_equals(sel.getComposedRanges()[0].endContainer, b);
- assert_equals(sel.getComposedRanges()[0].endOffset, 0);
-}, 'Setting the range to nodes that aren\'t in the same tree collapses both composed and non-composed ranges.');
-
-test(() => {
- const sel = getSelection();
sel.setBaseAndExtent(c, 0, d, 0);
assert_equals(sel.getRangeAt(0).startContainer, d);
diff --git a/tests/wpt/tests/selection/shadow-dom/tentative/Selection-getComposedRanges-dom-mutations-removal.html b/tests/wpt/tests/selection/shadow-dom/tentative/Selection-getComposedRanges-dom-mutations-removal.html
new file mode 100644
index 00000000000..d89dcb2ce9d
--- /dev/null
+++ b/tests/wpt/tests/selection/shadow-dom/tentative/Selection-getComposedRanges-dom-mutations-removal.html
@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<html>
+<body>
+<meta name="author" href="mailto:dizhangg@chromium.org">
+<link rel="help" href="https://w3c.github.io/selection-api/#dom-selection-getcomposedranges">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta name="variant" content="?mode=closed">
+<meta name="variant" content="?mode=open">
+
+<div id="container"></div>
+
+<script>
+
+const mode = (new URLSearchParams(document.location.search)).get("mode");
+
+test(() => {
+ container.innerHTML = 'a<div id="host"></div>b';
+ const host = container.querySelector('#host');
+ const shadowRoot = host.attachShadow({ mode });
+ shadowRoot.innerHTML = 'hello, world';
+ getSelection().setBaseAndExtent(shadowRoot.firstChild, 7, container, 2);
+ const rangeBefore = getSelection().getComposedRanges({ shadowRoots: [shadowRoot] })[0];
+ host.remove();
+ const rangeAfter = getSelection().getComposedRanges({ shadowRoots: [shadowRoot] })[0];
+
+ assert_equals(rangeBefore.startContainer, shadowRoot.firstChild, 'StaticRange does not update on new mutation.');
+ assert_equals(rangeBefore.startOffset, 7);
+ assert_equals(rangeBefore.endContainer, container);
+ assert_equals(rangeBefore.endOffset, 2);
+
+ assert_equals(rangeAfter.startContainer, container, 'collapsed to the host parent: container');
+ assert_equals(rangeAfter.startOffset, 1);
+ assert_equals(rangeAfter.endContainer, container);
+ assert_equals(rangeAfter.endOffset, 1);
+}, 'Range is fully in shadow tree. Removing shadow host collapses composed StaticRange. Note it does not update previously returned composed StaticRange.');
+
+test(() => {
+ container.innerHTML = '<div id="wrapper">a<div id="host"></div>b</div>';
+ const wrapper = container.querySelector('#wrapper');
+ const host = container.querySelector('#host');
+ const shadowRoot = host.attachShadow({ mode });
+ shadowRoot.innerHTML = 'hello, world';
+ getSelection().setBaseAndExtent(shadowRoot.firstChild, 4, shadowRoot.firstChild, 7);
+ wrapper.remove();
+
+ const rangeAfter = getSelection().getComposedRanges({ shadowRoots: [shadowRoot] })[0];
+ assert_equals(rangeAfter.startContainer, container, 'collapsed to parent of removed node');
+ assert_equals(rangeAfter.startOffset, 0);
+ assert_equals(rangeAfter.endContainer, container);
+ assert_equals(rangeAfter.endOffset, 0);
+}, 'Range is fully in shadow tree. Removing parent of shadow host collapses composed StaticRange.');
+
+test(() => {
+ container.innerHTML = '<div id="hello">Hello,</div><div id="world"> World</div>';
+ getSelection().setBaseAndExtent(hello.firstChild, 1, world.firstChild, 3);
+ hello.firstChild.remove();
+ const rangeAfter = getSelection().getComposedRanges()[0];
+
+ assert_equals(rangeAfter.startContainer, hello);
+ assert_equals(rangeAfter.startOffset, 0);
+ assert_equals(rangeAfter.endContainer, world.firstChild);
+ assert_equals(rangeAfter.endOffset, 3);
+}, 'Range is in light DOM. Removing startContainer rescopes new composed range to its parent.');
+
+test(() => {
+ container.innerHTML = 'a<div id="host"></div>b';
+ const host = container.querySelector('#host');
+ const shadowRoot = host.attachShadow({ mode });
+ shadowRoot.innerHTML = 'hello, world';
+ getSelection().setBaseAndExtent(shadowRoot.firstChild, 7, container, 2);
+ shadowRoot.innerHTML = '';
+ const rangeAfter = getSelection().getComposedRanges({ shadowRoots: [shadowRoot] })[0];
+
+ assert_equals(rangeAfter.startContainer, shadowRoot, 'collapsed to be at the parent shadow root');
+ assert_equals(rangeAfter.startOffset, 0);
+ assert_equals(rangeAfter.endContainer, container);
+ assert_equals(rangeAfter.endOffset, 2);
+}, 'Range is across shadow trees. Replacing shadowRoot content rescopes new composed range to the shadowRoot.');
+
+test(() => {
+ container.innerHTML = [
+ '<div id=host>',
+ '<div id=div1 slot=slot2>slotted content 1</div>',
+ '<div id=div2 slot=slot1>slotted content 2</div>',
+ '</div>'
+ ].join('');
+ const shadowRoot = host.attachShadow({mode: 'open'});
+ shadowRoot.innerHTML = [
+ '<span>before</span>',
+ '<slot name=slot1></slot>',
+ '<span>between</span>',
+ '<slot name=slot2></slot>',
+ '<span>after</span>',
+ ].join('');
+
+ const sel = getSelection();
+ sel.setBaseAndExtent(div1.firstChild, 2, div2.firstChild, 2);
+ div1.remove();
+
+ const rangeAfter = getSelection().getComposedRanges({ shadowRoots: [shadowRoot] })[0];
+ assert_equals(rangeAfter.startContainer, host);
+ assert_equals(rangeAfter.startOffset, 0);
+ assert_equals(rangeAfter.endContainer, div2.firstChild);
+ assert_equals(rangeAfter.endOffset, 2);
+}, 'Range is between two light slotted contents. Removing start container rescopes to its parent in light tree.');
+
+</script>
+</body>
+</html>
diff --git a/tests/wpt/tests/selection/shadow-dom/tentative/Selection-getComposedRanges-slot.html b/tests/wpt/tests/selection/shadow-dom/tentative/Selection-getComposedRanges-slot.html
new file mode 100644
index 00000000000..d9664b0e150
--- /dev/null
+++ b/tests/wpt/tests/selection/shadow-dom/tentative/Selection-getComposedRanges-slot.html
@@ -0,0 +1,124 @@
+<!DOCTYPE html>
+<html>
+<body>
+<meta name="author" href="mailto:dizhangg@chromium.org">
+<meta name="assert" content="Selection's getComposedRanges should return a sequence of static ranges, selecting from slotted content">
+<link rel="help" href="https://w3c.github.io/selection-api/#dom-selection-getcomposedranges">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="container"></div>
+
+<script>
+
+test(() => {
+ container.innerHTML = '<div id=host>Second</div>';
+ const shadowRoot = host.attachShadow({ mode:"open" });
+ shadowRoot.innerHTML = 'First <slot></slot> Third';
+ const second = host.firstChild;
+ const third = shadowRoot.querySelector('slot').nextSibling;
+
+ const sel = getSelection();
+ // Select from slotted second to shadowed third.
+ sel.setBaseAndExtent(second, 3, third, 4);
+
+ assert_equals(sel.getRangeAt(0).startContainer, second);
+ assert_equals(sel.getRangeAt(0).startOffset, 3);
+ assert_equals(sel.getRangeAt(0).endContainer, second, 'Collapsed because crossing shadow tree is not supported for getRangeAt.');
+ assert_equals(sel.getRangeAt(0).endOffset, 3);
+
+ assert_equals(sel.getComposedRanges()[0].startContainer, container);
+ assert_equals(sel.getComposedRanges()[0].startOffset, 0, 'Rescoped because no shadow roots were provided');
+ assert_equals(sel.getComposedRanges()[0].endContainer, second);
+ assert_equals(sel.getComposedRanges()[0].endOffset, 3);
+
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startContainer, third);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startOffset, 4);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endContainer, second);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endOffset, 3);
+
+ // Repeat the test, but reversing base and extent. This should not affect the range's start and end positions.
+ sel.setBaseAndExtent(third, 4, second, 3);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startContainer, third);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startOffset, 4);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endContainer, second);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endOffset, 3);
+}, 'Setting the range to start on slotted content and end in shadow tree, should follow DOM tree order.');
+
+test(() => {
+ container.innerHTML = [
+ '<div id=host>',
+ '<div id=div1 slot=slot2>slotted content 1</div>',
+ '<div id=div2 slot=slot1>slotted content 2</div>',
+ '</div>'
+ ].join('');
+ const shadowRoot = host.attachShadow({mode: 'open'});
+ shadowRoot.innerHTML = [
+ '<span>before</span>',
+ '<slot name=slot1></slot>',
+ '<span>between</span>',
+ '<slot name=slot2></slot>',
+ '<span>after</span>',
+ ].join('');
+
+ const sel = getSelection();
+ // Select from slotted div1 to slotted div2.
+ sel.setBaseAndExtent(div1.firstChild, 2, div2.firstChild, 2);
+
+ assert_equals(sel.getRangeAt(0).startContainer, div1.firstChild);
+ assert_equals(sel.getRangeAt(0).startOffset, 2);
+ assert_equals(sel.getRangeAt(0).endContainer, div2.firstChild, 'Not collapsed because we are not crossing shadow trees.');
+ assert_equals(sel.getRangeAt(0).endOffset, 2);
+
+ assert_equals(sel.getComposedRanges()[0].startContainer, div1.firstChild);
+ assert_equals(sel.getComposedRanges()[0].startOffset, 2);
+ assert_equals(sel.getComposedRanges()[0].endContainer, div2.firstChild, 'Not rescoped because we are not crossing shadow trees.');
+ assert_equals(sel.getComposedRanges()[0].endOffset, 2);
+
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startContainer, div1.firstChild);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startOffset, 2);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endContainer, div2.firstChild);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endOffset, 2);
+
+ // Repeat the test, but reversing base and extent. This should not affect the range's start and end positions.
+ sel.setBaseAndExtent(div2.firstChild, 2, div1.firstChild, 2);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startContainer, div1.firstChild);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startOffset, 2);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endContainer, div2.firstChild);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endOffset, 2);
+}, 'Setting the range to start and end on slotted content, should follow DOM tree order.');
+
+test(() => {
+ container.innerHTML = '<div id=host>Second</div>';
+ const shadowRoot = host.attachShadow({ mode:"open" });
+ shadowRoot.innerHTML = '<span id="first">First</span><span id=third>Third</span>';
+ const second = host.firstChild;
+ const third = shadowRoot.getElementById('third').firstChild;
+
+ const sel = getSelection();
+ // Select from unslotted second to shadowed third.
+ sel.setBaseAndExtent(second, 3, third, 4);
+
+ assert_equals(sel.getRangeAt(0).startContainer, second);
+ assert_equals(sel.getRangeAt(0).startOffset, 3);
+ assert_equals(sel.getRangeAt(0).endContainer, second, 'Collapsed because crossing shadow tree is not supported for getRangeAt.');
+ assert_equals(sel.getRangeAt(0).endOffset, 3);
+
+ assert_equals(sel.getComposedRanges()[0].startContainer, container);
+ assert_equals(sel.getComposedRanges()[0].startOffset, 0, 'Rescoped because no shadow roots were provided');
+ assert_equals(sel.getComposedRanges()[0].endContainer, second);
+ assert_equals(sel.getComposedRanges()[0].endOffset, 3);
+
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startContainer, third);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startOffset, 4);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endContainer, second);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endOffset, 3);
+
+ // Repeat the test, but reversing base and extent. This should not affect the range's start and end positions.
+ sel.setBaseAndExtent(third, 4, second, 3);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startContainer, third);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startOffset, 4);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endContainer, second);
+ assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endOffset, 3);
+}, 'Setting the range to start on unslotted content and end in shadow tree, should follow DOM tree order.');
+</script>
diff --git a/tests/wpt/tests/shadow-dom/focus-navigation/reading-flow/tentative/grid-order-across-scopes.html b/tests/wpt/tests/shadow-dom/focus-navigation/reading-flow/tentative/grid-order-across-scopes.html
index 76e5af8c74b..629bfea2aff 100644
--- a/tests/wpt/tests/shadow-dom/focus-navigation/reading-flow/tentative/grid-order-across-scopes.html
+++ b/tests/wpt/tests/shadow-dom/focus-navigation/reading-flow/tentative/grid-order-across-scopes.html
@@ -18,9 +18,9 @@
}
</style>
-<!-- Since C is a direct reading flow item, it is visited first. -->
-<!-- Since B,A are inside a display: contents, they are visited after. -->
-<div class="test-case" data-expect="C,B,A"
+<!-- Since B,A are inside a display: contents, they are visited together. -->
+<!-- Since B has order 1, its display: contents parent is visited first. -->
+<div class="test-case" data-expect="B,A,C"
data-description="Grid items in shadow host that is a display contents grid item">
<div class=wrapper>
<div style="display: contents">
diff --git a/tests/wpt/tests/shadow-dom/focus-navigation/reading-flow/tentative/grid-order-with-display-contents.html b/tests/wpt/tests/shadow-dom/focus-navigation/reading-flow/tentative/grid-order-with-display-contents.html
index b69f3d20799..6d012f49cea 100644
--- a/tests/wpt/tests/shadow-dom/focus-navigation/reading-flow/tentative/grid-order-with-display-contents.html
+++ b/tests/wpt/tests/shadow-dom/focus-navigation/reading-flow/tentative/grid-order-with-display-contents.html
@@ -19,8 +19,8 @@
}
</style>
-<div class="test-case" data-expect="order1,order3,order2,order4"
- data-description="Items in display contents are sorted in same grid container.">
+<div class="test-case" data-expect="order1,order2,order4,order3"
+ data-description="Items in display contents are sorted in same grid container and are placed in the position where their first child resides.">
<div class="wrapper">
<div style="display: contents">
<button id="order3" style="order: 3">Order 3</button>
@@ -33,8 +33,8 @@
</div>
</div>
-<div class="test-case" data-expect="div1B,order1B,order3B,div2B,order2B,order4B"
- data-description="Items in display contents are sorted in same grid container, with focusable display contents divs at the end of the focus sequence.">
+<div class="test-case" data-expect="div1B,order1B,div2B,order2B,order4B,order3B"
+ data-description="Items in display contents are sorted in same grid container and are placed in the position where their first child resides. The display contents have tabindex and should be focusable.">
<div class="wrapper">
<div id="div1B" style="display: contents" tabindex="0">
<button id="order3B" style="order: 3">Order 3</button>
@@ -47,9 +47,9 @@
</div>
</div>
-<div class="test-case" data-expect="A1,A2,A3,B1,B2,B3,C1,C2,C3,D1,D2,D3"
+<div class="test-case" data-expect="C1,C2,C3,D1,D2,D3,B1,B2,B3,A1,A2,A3"
data-description="Grid items are in nested display contents containers.">
- <div class=box>
+ <div class=wrapper>
<div style="display:contents" tabindex="0" id="A1">
<div style="display:contents" tabindex="0" id="A2">
<button style="order: 4" id="A3">A</button>
diff --git a/tests/wpt/tests/shadow-dom/focus-navigation/reading-flow/tentative/grid-order-with-slots.html b/tests/wpt/tests/shadow-dom/focus-navigation/reading-flow/tentative/grid-order-with-slots.html
index f52c9ebdc81..eff412296d9 100644
--- a/tests/wpt/tests/shadow-dom/focus-navigation/reading-flow/tentative/grid-order-with-slots.html
+++ b/tests/wpt/tests/shadow-dom/focus-navigation/reading-flow/tentative/grid-order-with-slots.html
@@ -55,7 +55,7 @@
</span>
<br>
-<span id="host3" class="test-case" data-expect="host3/o2,host3/o4,o1,o3,o5"
+<span id="host3" class="test-case" data-expect="o1,o3,o5,host3/o2,host3/o4"
data-description="Slot is inside a grid container with reading-flow.">
<template shadowrootmode="open">
<style>
@@ -77,7 +77,7 @@
<br>
<span id="host4" class="test-case"
- data-expect="host4/after,host4/before,b4,a4,d42,d41,d43,c4"
+ data-expect="b4,a4,d42,d41,d43,c4,host4/after,host4/before"
data-description="Slot is a grid with reading-flow inside a grid container with reading-flow.">
<template shadowrootmode="open">
<style>
@@ -120,7 +120,7 @@
</span>
<br>
-<span id="host6" class="test-case" data-expect="host6/after,host6/before,b6,a6"
+<span id="host6" class="test-case" data-expect="b6,a6,host6/after,host6/before"
data-description="Slot is a display contents inside a grid container.">
<template shadowrootmode="open">
<style>
@@ -140,7 +140,7 @@
</span>
<br>
-<span id="host7" class="test-case" data-expect="a7,b7,host7/after,host7/before"
+<span id="host7" class="test-case" data-expect="host7/after,a7,b7,host7/before"
data-description="Slot is a display block inside a grid container.">
<template shadowrootmode="open">
<style>
@@ -150,8 +150,8 @@
}
</style>
<div class="wrapper">
- <button style="order: 4" id="before">Before</button>
- <slot style="display: block" style="order: 4"></slot>
+ <button style="order: 5" id="before">Before</button>
+ <slot style="display: block; order: 4"></slot>
<button style="order: 3" id="after">After</button>
</div>
</template>
diff --git a/tests/wpt/tests/shared-storage/interest-groups.tentative.https.sub.html b/tests/wpt/tests/shared-storage/interest-groups.tentative.https.sub.html
new file mode 100644
index 00000000000..2889500be23
--- /dev/null
+++ b/tests/wpt/tests/shared-storage/interest-groups.tentative.https.sub.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const ig = {
+ owner: window.location.origin,
+ name: 'default name',
+ lifetimeMs: 100000
+ };
+
+ await navigator.joinAdInterestGroup(ig);
+ await sharedStorage.worklet.addModule('resources/simple-module.js');
+
+ const ancestor_key = token();
+ let url0 = generateURL("/shared-storage/resources/frame0.html",
+ [ancestor_key]);
+ let url1 = generateURL("/shared-storage/resources/frame1.html",
+ [ancestor_key]);
+
+ let select_url_result = await sharedStorage.selectURL(
+ "verify-interest-groups", [{url: url0}, {url: url1}],
+ {data: {'expectedOwner': ig.owner, 'expectedName': ig.name},
+ resolveToConfig: true});
+ assert_true(validateSelectURLResult(select_url_result, true));
+ attachFencedFrame(select_url_result, 'opaque-ads');
+ const result = await nextValueFromServer(ancestor_key);
+
+ // This indicates that `interestGroups()` returns expected result.
+ assert_equals(result, "frame1_loaded");
+}, 'Basic test for `interestGroups()` in the shared storage worklet');
+
+</script>
+</body>
diff --git a/tests/wpt/tests/shared-storage/resources/simple-module.js b/tests/wpt/tests/shared-storage/resources/simple-module.js
index 11b650811dc..eeb0ce95b04 100644
--- a/tests/wpt/tests/shared-storage/resources/simple-module.js
+++ b/tests/wpt/tests/shared-storage/resources/simple-module.js
@@ -4,6 +4,13 @@
var globalVar = 0;
+async function busyWaitMs(time_to_wait) {
+ const startTime = Date.now();
+ while (Date.now() - startTime < time_to_wait) {
+
+ }
+}
+
class TestURLSelectionOperation {
async run(urls, data) {
if (data && data.hasOwnProperty('setKey') && data.hasOwnProperty('setValue')) {
@@ -50,8 +57,54 @@ class VerifyKeyNotFound {
}
}
+class VerifyInterestGroups {
+ async run(urls, data) {
+ if (data &&
+ data.hasOwnProperty('expectedOwner') &&
+ data.hasOwnProperty('expectedName')) {
+
+ const groups = await interestGroups();
+
+ if (groups.length !== 1) {
+ return -1;
+ }
+
+ if (groups[0]["owner"] !== data['expectedOwner']) {
+ return -1;
+ }
+
+ if (groups[0]["name"] !== data['expectedName']) {
+ return -1;
+ }
+
+ return 1;
+ }
+ return -1;
+ }
+}
+
+class GetWaitIncrementWithinLockOperation {
+ async run(urls, data) {
+ if (data && data.hasOwnProperty('key')) {
+ await navigator.locks.request("lock0", async (lock) => {
+ let value_read = await sharedStorage.get(data['key']);
+ value_read = value_read ? Number(value_read) : 0;
+
+ await busyWaitMs(100);
+
+ await sharedStorage.set(data['key'], value_read + 1);
+ });
+
+ return 1;
+ }
+ return -1;
+ }
+}
+
register('test-url-selection-operation', TestURLSelectionOperation);
register('increment-global-variable-and-return-original-value-operation',
IncrementGlobalVariableAndReturnOriginalValueOperation);
register('verify-key-value', VerifyKeyValue);
register('verify-key-not-found', VerifyKeyNotFound);
+register('verify-interest-groups', VerifyInterestGroups);
+register('get-wait-increment-within-lock', GetWaitIncrementWithinLockOperation);
diff --git a/tests/wpt/tests/shared-storage/web-locks.tentative.https.sub.html b/tests/wpt/tests/shared-storage/web-locks.tentative.https.sub.html
new file mode 100644
index 00000000000..49a039368a3
--- /dev/null
+++ b/tests/wpt/tests/shared-storage/web-locks.tentative.https.sub.html
@@ -0,0 +1,62 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async t => {
+ let worklet1 = await sharedStorage.createWorklet('resources/simple-module.js');
+ let worklet2 = await sharedStorage.createWorklet('resources/simple-module.js');
+
+ const ancestor_key1 = token();
+ let url1_0 = generateURL("/shared-storage/resources/frame0.html",
+ [ancestor_key1]);
+ let url1_1 = generateURL("/shared-storage/resources/frame1.html",
+ [ancestor_key1]);
+
+ const ancestor_key2 = token();
+ let url2_0 = generateURL("/shared-storage/resources/frame0.html",
+ [ancestor_key2]);
+ let url2_1 = generateURL("/shared-storage/resources/frame1.html",
+ [ancestor_key2]);
+
+ // Two `selectURL()`s run in parallel. Each performs the following steps:
+ // 1. Acquires the lock.
+ // 2. Reads the current value of the given key.
+ // 3. Waits for 100ms.
+ // 4. Increments the value.
+ // 5. Releases the lock.
+ //
+ // Expected behavior: After both operations finish, the value of the given key
+ // should be 2.
+ //
+ // This demonstrates that the lock is effective, preventing the
+ // "get and increment" operations from interleaving. If the lock were not
+ // used, both worklets would likely read 0 and set the value to 1.
+
+ let select_url_result1 = await worklet1.selectURL(
+ "get-wait-increment-within-lock", [{url: url1_0}, {url: url1_1}],
+ {data: {'key': 'key'}, resolveToConfig: true});
+
+ let select_url_result2 = await worklet2.selectURL(
+ "get-wait-increment-within-lock", [{url: url2_0}, {url: url2_1}],
+ {data: {'key': 'key'}, resolveToConfig: true});
+
+ attachFencedFrame(select_url_result1, 'opaque-ads');
+ const result1 = await nextValueFromServer(ancestor_key1);
+ assert_equals(result1, "frame1_loaded");
+
+ attachFencedFrame(select_url_result2, 'opaque-ads');
+ const result2 = await nextValueFromServer(ancestor_key2);
+ assert_equals(result2, "frame1_loaded");
+
+ await verifyKeyValueForOrigin('key', '2', location.origin);
+}, 'Basic test for Web Locks API in the shared storage worklet');
+
+</script>
+</body>
diff --git a/tests/wpt/tests/speculation-rules/prerender/resources/csp-script-src-self.html b/tests/wpt/tests/speculation-rules/prerender/resources/csp-script-src-self.html
index 8dc382068a3..61a8f31396c 100644
--- a/tests/wpt/tests/speculation-rules/prerender/resources/csp-script-src-self.html
+++ b/tests/wpt/tests/speculation-rules/prerender/resources/csp-script-src-self.html
@@ -2,14 +2,14 @@
<head>
<!-- disallow inline script -->
- <meta http-equiv="Content-Security-Policy" content="script-src 'self'">
+ <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'nonce-allowed-inline-script-for-test'">
</head>
<script src="/common/utils.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="utils.js"></script>
<script src="csp-script-src.js"></script>
-<script>
- const params = new URLSearchParams(location.search);
- writeValueToServer(params.get('key'), "csp is ignored unexpectedly");
+<script nonce="allowed-inline-script-for-test">
+ const searchParams = new URLSearchParams(location.search);
+ writeValueToServer(searchParams.get('key'), "csp is ignored unexpectedly");
</script>
diff --git a/tests/wpt/tests/storage/quotachange-in-detached-iframe.tentative.https.html b/tests/wpt/tests/storage/quotachange-in-detached-iframe.tentative.https.html
deleted file mode 100644
index 123af50e3ce..00000000000
--- a/tests/wpt/tests/storage/quotachange-in-detached-iframe.tentative.https.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!doctype html>
-<meta charset="utf-8">
-<title>quotachange event on DOMWindow of detached iframe</title>
-<link rel="author" href="jarrydg@chromium.org" title="Jarryd">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<iframe id="iframe"></iframe>
-<script>
-'use strict';
-
-test(t => {
- const iframe = document.getElementById('iframe');
- const frameWindow = iframe.contentWindow;
- const storageManager = frameWindow.navigator.storage;
-
- iframe.parentNode.removeChild(iframe);
- const emptyListener = () => {};
- storageManager.addEventListener('quotachange', emptyListener);
- storageManager.removeEventListener('quotachange', emptyListener);
-}, "Add quotachange listener on detached iframe.");
-</script>
diff --git a/tests/wpt/tests/svg/animations/animate-display-to-none-001.html b/tests/wpt/tests/svg/animations/animate-display-to-none-001.html
new file mode 100644
index 00000000000..ce8e493840e
--- /dev/null
+++ b/tests/wpt/tests/svg/animations/animate-display-to-none-001.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Test that underlying style gets restored when seeking away from the
+ 'to' portion of a SVG/SMIL animation to 'display:none'</title>
+<link rel="help" href="https://www.w3.org/TR/smil-animation/#ToAttribute">
+<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+<link rel="match" href="../struct/reftests/reference/green-100x100.html">
+<script>
+ function go() {
+ svgElem.pauseAnimations();
+
+ /* Seek to 75% of the way through duration, when the animation should be
+ * imposing the "to" value. (This is necessary to trigger the bug
+ * that we're regression-testing for here.) */
+ svgElem.setCurrentTime(3);
+
+ /* Now, seek back to 25% of the way through duration, when the underlying
+ * value should be restored. This should make the green rect show up
+ * in our reftest screenshot. */
+ svgElem.setCurrentTime(1);
+ }
+</script>
+<body onload="go()">
+<svg id="svgElem">
+ <rect width="100" height="100" fill="red"/>
+ <rect width="100" height="100" fill="green">
+ <animate attributeName="display" to="none"
+ begin="0s" dur="4s"/>
+ </rect>
+</svg>
diff --git a/tests/wpt/tests/svg/painting/reftests/small-nested-viewbox-ref.html b/tests/wpt/tests/svg/painting/reftests/small-nested-viewbox-ref.html
new file mode 100644
index 00000000000..f737b09ff49
--- /dev/null
+++ b/tests/wpt/tests/svg/painting/reftests/small-nested-viewbox-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<style>
+ svg {
+ width: 16px;
+ padding: 4px;
+ background: #ccc;
+ color: #000;
+ }
+</style>
+<svg width='16' height='16'>
+ <svg viewBox='0 0 256 256'>
+ <rect width="256" height="256" x="0" y="0" fill="green" />
+ </svg>
+</svg>
diff --git a/tests/wpt/tests/svg/painting/reftests/small-nested-viewbox.html b/tests/wpt/tests/svg/painting/reftests/small-nested-viewbox.html
new file mode 100644
index 00000000000..3d9fb8cb45f
--- /dev/null
+++ b/tests/wpt/tests/svg/painting/reftests/small-nested-viewbox.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1922222">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="match" href="small-nested-viewbox-ref.html">
+<style>
+ svg {
+ width: 16px;
+ padding: 4px;
+ background: #ccc;
+ color: #000;
+ }
+</style>
+<svg viewBox="0 0 4 4">
+ <svg viewBox='0 0 256 256'>
+ <rect width="256" height="256" x="0" y="0" fill="green" />
+ </svg>
+</svg>
diff --git a/tests/wpt/tests/tools/certs/cacert.key b/tests/wpt/tests/tools/certs/cacert.key
index 421cae4c51a..dd47af3f939 100644
--- a/tests/wpt/tests/tools/certs/cacert.key
+++ b/tests/wpt/tests/tools/certs/cacert.key
@@ -1,30 +1,30 @@
-----BEGIN ENCRYPTED PRIVATE KEY-----
-MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQISJq4lddWxR0CAggA
-MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECNwjuqbwzC5YBIIEyGihC3NgVhjk
-hIu+a8kWhGQvYRyBB0Da0IKdJeNx4KUrSqGdseH84Fss3pv0IpP35okkQ2M7Ityr
-bmrS1XeEFJB6ghBNNodAk/nB1HdRdIfwOy8DYA20kD+loe5UMx5i+hwbJUPrSlKq
-KeJIvn5TahKPi480iQ6NwtHcpmwjtG6gbS4zDa0x1Oe1UrtyTKo5VHRNexXiqjxS
-AwTjAQJXHoZCVh275gppqu58Sh+XKz9vQ0UMUogc50v8+lXCHb4EAQeD4uO5p+8M
-DveSV31RSBfT7ZjeF+5u08gdEpTvZVF21Jn9OR4PzHX/sGf13RboLEmy3k3dRWVS
-40ux4U61WEij7oM9oXrL9429K3CesNPB+HOdmqVi2Y/NviX4UdFdOb2oJqs4CA6L
-ERqD/Q2SL1KaWQmvFfsg6OPWp4Q6mrGC+Qj0nH3Tkw6l3QUktCqPly6ZaH4Whf3X
-0pzDov1r9LMcfqA3MPWevTkjJUFIqigSp9On/ofzLTLXRzmZfh5cpEvSrOQTJ0jV
-prVdKT+2rEFLEG3rNG5dj73ADxlagO/3bgI/Kvy80Jf95x1BTG/1nOuTJKZ99Q+K
-6KrxZNQdVqfoOJlI+uV1rc25ufY1ttHXTCozKDL2+xVqByL9FnqtnlSJc27PayF4
-r7gQNp8fdjruBPt+hyhVkCrg/LhPx0bSQQZYZ/DYFaFcKow25AGUlJbTipgp/YDb
-mBBLYoyqfK6BXSQc1NGYvj/jMkJnaL5TcsHUYPB66225PCPl9xr8lug6dtTFeIg0
-/lGeB0ppGtu4npfSV1YBaKvNfs0EWKK0wbarbLl97yoGBOnT5cTe9Mzkohry3Uoc
-AUCed1Enx2fFela9XzVQsrzoqQUtXuRrFOH/7avyncpRoRAJ7OzsLiVtAO2uq9Eo
-wERu5IviHABHrn7EQZnTPpVEWfoOol9zu5vnG4rlvgffe7Mobx0eC1xlK37J+sez
-x3hmOcKoJZx2PXsaxLX7vaF/PgO8vt2KGciJ9s3nS4QubZnFOmoPj87hUg+f0y3i
-wY8Xea+rJeiLurX4S9ZlUuN8/xroYIMPS1KuP7pT6lUlmQONy/vECZsHhjvHVybh
-pC9Q13W5bW7vaOOWHEBz/poh1AlnNQjELhBQ2sv1OYWHZAvP+vw2n/P9uTCvg4Rl
-34fCAsrh4gd35DH1VEwFwKQh7QuexR7Cxrrtw0Ac7XOU8Fx2ktrf65gV7zN/TrZK
-H2JuEjDbWXqpAy7Y2+WpldueCx8GN10eere1G1S89AVD2LR+SB4n1CrCgwBf4JFK
-soqYTUsK6jSIaM9NY0LxykwaT2WD7lRIFu826GnMLQ2C3LgFUtxms1uiAdfwe/J+
-Dtsx8z6CKJ0fkNXbx/kMKEfY8EmMShWwU3kAbUlMZezUZLlynuqOyF/ahML538bC
-/12tvDds8/n8ZAwS3uLrawxTSOUD3AbVi80brsyF3dfavycUY5ViI7i/5Ie/mIt0
-acX0VWH0mSZgSUeox0pPtB8B6ow3/DIGrdZ5r34Hm4XT1VynMm0jgAq7AUv3gVwJ
-GUMWU6teGv+Jov/CKUwfe0xWgVqcd/aJgVS1U8pu729l5WBhHTxh2xVK3ciBN8bv
-UeDxQ//R4iyzwXG352JHpA==
+MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIQ5KidoYVfxkCAggA
+MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECMn0jRuVwL1yBIIEyP+RfjlPlBdC
+KpYXU3bQMGIXnYeQLoaaGjVGtsOsTs5qtvFVMkU2dbSmJHS81n4s8F2fDO0R8QiR
+EICZJsD8/A16teQrxBy29ZSlpKNZQyGJkaJSoyPgLHBTMWJDvYKlu407xzoxXnx6
+FDVdTrVNmza0tdG2MN9r/hAuZoobWYyjJrazELB5yTTm2ZFNT7H9gF+K2eTDa/g5
+1cTeUBDNoC7ejtILyJALBNcN6eGnXZeeQLg1Dx93aUObSUpiYrqn9Q4zhzOUkaYw
+jvErFMQvU9YW0HFN/J2YVbvlC/jsk6l3rFFObiWHkwhKJc2+pXu9z6Hhv/o1i7uu
+XlXcNPD+poqsmrhOvEjmTK4Og8QvEcoR/lOUWBBhgLqtkD88SHJrqBb5JStaAStH
+c/Q+oYnox3VAhMU0sB8thg2KQ+piTGLQP/2aD1NJvNul2JEB9zAcVAoCSCz1mc8P
+yGyvoZKGBmvqEskX0JMCnx6sLKOlKtqFF2/9Uair/6vrQND8MLU/ksjzzUncb24n
+jokua7HbmrBw7GKQH+75/0nJWOMusTZtrwxCVKWJL3M6LQ9N4NaP0nbvfj54lyVy
+lGBD6W9fXB3/4FjmIFEqd9T+ltgmJlHSUUox3avXS3PAuGfaIFYZ4Tjoik1uYIt4
+S3NMwH6ysI+4UrU1D/1UJl+7/KSLo/k+hq0hH/0D0XEva8FDq4/4HrX843awR0Em
+BUVE7MVIF0hHpbpZ/znV5LFY4czXlgpp3B32ac07i4iJCDk8KCclyCjyMWEFQ87O
+zIMk8h/BjiP1Uzyr0wGFjyYP2gu7nmuzjrBAkIlWQ9xU9aiTfwQkEkMo7RJA4M1b
+DC9Vdt4Mfzv603UdwAF8BVozgWxONV37VLbAu4r0ENw0C2rf9ZGxO1D9KITjVVF8
+xcSWsm7n0VATqd5MB6sUyzc7AuyQbewQ1AMsTNv5baxLooka/NZTcfqXQmD08C7O
+pXJP3kUJweNXw6lUsjtR0VYe0MJOeo2oe/CLoDv+xej4Ez5xTPDAdzIJEk6K8Y7C
+jCcIhTz2WOiTA2MDE1UmY8lZJzaWNjNfetGcfIBh00YYcsmSVByr/YbKgh7KN1Rb
+Qek2k0l390jLOG64t1MM6QaNCDX11bq+pS2hSVyivfE7olrrWjxdjHFOlFqcHRVE
+8+lMewf6RfO8iYZtHNgcVFYZcTyo/wbf9fEN5YAuoG++3U6vTITtWhXp9GoRGZ/i
+EBfJzvuFt2FU5GbBub9n3fC/d+iOUeVl8jtZ3+xK5MAHdbTs1E4+AW9goU8pSXcF
+JEJcF4AAj76XbKH0U+jC2umrkFOlVXP/hnuPxZcKDhaHVBB0Z8xSHo6RClUc/+rP
+pgfeMvFf4tnEdGPdj2ZUc808nilzJ63jB+cVuZJB7lnGQCPMH8k+pnBSFkJmk+To
+vk2HckfrW1d3rZ59jHBPySEbv8a7wLm+adSJGtG1CK8wHKhhGyXbgpE1OTtLWUec
+n//yDEvVhs/p8HDmRvARBdc93CLWhM/YhPLzSrItCFuPWOMuOTXINZGb4KqQixcN
+yb6GjBGNwNnXjDlpj23vlxUBYS3iRnOit84aPH1JdAxElTc8oI63siwjc5LoUhQZ
+cY5MQqTzu2MhIeEwgqlXmQ==
-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/wpt/tests/tools/certs/cacert.pem b/tests/wpt/tests/tools/certs/cacert.pem
index cf16ae8aea3..7b3fb3da14d 100644
--- a/tests/wpt/tests/tools/certs/cacert.pem
+++ b/tests/wpt/tests/tools/certs/cacert.pem
@@ -1,125 +1,125 @@
-----BEGIN CERTIFICATE-----
-MIIW5zCCFc+gAwIBAgIDAb4YMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMMEndl
-Yi1wbGF0Zm9ybS10ZXN0czAeFw0yNDA5MTIwMTAzMTBaFw0yNTA5MTIwMTAzMTBa
-MB0xGzAZBgNVBAMMEndlYi1wbGF0Zm9ybS10ZXN0czCCASIwDQYJKoZIhvcNAQEB
-BQADggEPADCCAQoCggEBAKk/RuiyVSsKvV1yaETX9S6zQ4V0zMsjbWZOTZ09NoIj
-r/vMnmrthOzGsUoU2tArgEFsWA2drKwNJqsp4aXuit4F2lNoP4Fp16KrT6k2NQyY
-hRJltaPhfLYpZHX4KBKyu5zojxVnbrxxEgbp+F/GcVHmwR9bZImCWJKJwWdP/zrM
-JLHvXAHXk+h1PiovC1U3EU0iOcLCQM4jTimvoKdgcDe06vjHlFk43pM7Y6AnHxai
-g/GAJufGhkOfm4re+bow5akZinFt68uvwL198mcl/76ozLQaU2qPP/EAzV8jNdf7
-HK8JNX2sGP+QItSO1EPsDZwjWTlcaE/PaXIyffUiWZsCAwEAAaOCFC4wghQqMAwG
-A1UdEwQFMAMBAf8wHQYDVR0OBBYEFP5kQf3rJdJUaqbhNvYSKlb5gva1MEcGA1Ud
-IwRAMD6AFP5kQf3rJdJUaqbhNvYSKlb5gva1oSGkHzAdMRswGQYDVQQDDBJ3ZWIt
-cGxhdGZvcm0tdGVzdHOCAwG+GDALBgNVHQ8EBAMCAgQwggoFBgNVHR4Eggn8MIIJ
-+KCCCfQwE4IRd2ViLXBsYXRmb3JtLnRlc3QwF4IVbm90LXdlYi1wbGF0Zm9ybS50
-ZXN0MBeCFXd3dy53ZWItcGxhdGZvcm0udGVzdDAYghZ3d3cyLndlYi1wbGF0Zm9y
-bS50ZXN0MBiCFnd3dzEud2ViLXBsYXRmb3JtLnRlc3QwG4IZd3d3Lnd3dy53ZWIt
-cGxhdGZvcm0udGVzdDAbghl3d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3
-dy53d3cxLndlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dzIud3d3LndlYi1wbGF0Zm9y
-bS50ZXN0MByCGnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dzEud3d3
-LndlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0
-MByCGnd3dy53d3cyLndlYi1wbGF0Zm9ybS50ZXN0MB2CG3d3dzEud3d3Mi53ZWIt
-cGxhdGZvcm0udGVzdDAdght3d3cyLnd3dzEud2ViLXBsYXRmb3JtLnRlc3QwHYIb
-d3d3Mi53d3cyLndlYi1wbGF0Zm9ybS50ZXN0MB2CG3d3dzEud3d3MS53ZWItcGxh
-dGZvcm0udGVzdDAfgh13d3cud3d3Lm5vdC13ZWItcGxhdGZvcm0udGVzdDAggh53
-d3cud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwIIIed3d3Lnd3dzIubm90LXdl
-Yi1wbGF0Zm9ybS50ZXN0MCCCHnhuLS1sdmUtNmxhZC53ZWItcGxhdGZvcm0udGVz
-dDAggh53d3cyLnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwIIIed3d3MS53d3cu
-bm90LXdlYi1wbGF0Zm9ybS50ZXN0MCGCH3d3dzIud3d3Mi5ub3Qtd2ViLXBsYXRm
-b3JtLnRlc3QwIYIfd3d3MS53d3cyLm5vdC13ZWItcGxhdGZvcm0udGVzdDAhgh93
-d3cxLnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCGCH3d3dzIud3d3MS5ub3Qt
-d2ViLXBsYXRmb3JtLnRlc3QwJIIieG4tLWx2ZS02bGFkLm5vdC13ZWItcGxhdGZv
-cm0udGVzdDAkgiJ3d3cueG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0MCSC
-InhuLS1sdmUtNmxhZC53d3cud2ViLXBsYXRmb3JtLnRlc3QwJYIjd3d3MS54bi0t
-bHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3QwJYIjd3d3Mi54bi0tbHZlLTZsYWQu
-d2ViLXBsYXRmb3JtLnRlc3QwJYIjeG4tLWx2ZS02bGFkLnd3dzEud2ViLXBsYXRm
-b3JtLnRlc3QwJYIjeG4tLWx2ZS02bGFkLnd3dzIud2ViLXBsYXRmb3JtLnRlc3Qw
-KIImd3d3LnhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwKIImeG4t
-LWx2ZS02bGFkLnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwKYInd3d3Mi54bi0t
-bHZlLTZsYWQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCmCJ3huLS1sdmUtNmxhZC53
-d3cxLm5vdC13ZWItcGxhdGZvcm0udGVzdDApgid3d3cxLnhuLS1sdmUtNmxhZC5u
-b3Qtd2ViLXBsYXRmb3JtLnRlc3QwKYIneG4tLWx2ZS02bGFkLnd3dzIubm90LXdl
-Yi1wbGF0Zm9ybS50ZXN0MCuCKXhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLndlYi1w
-bGF0Zm9ybS50ZXN0MC2CK3huLS1sdmUtNmxhZC54bi0tbHZlLTZsYWQud2ViLXBs
-YXRmb3JtLnRlc3QwL4Itd3d3LnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLndlYi1w
-bGF0Zm9ybS50ZXN0MC+CLXhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnd3dy53ZWIt
-cGxhdGZvcm0udGVzdDAvgi14bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2Vi
-LXBsYXRmb3JtLnRlc3QwMIIueG4tLW44ajZkczUzbHd3a3JxaHYyOGEud3d3Mi53
-ZWItcGxhdGZvcm0udGVzdDAwgi54bi0tbjhqNmRzNTNsd3drcnFodjI4YS53d3cx
-LndlYi1wbGF0Zm9ybS50ZXN0MDCCLnd3dzEueG4tLW44ajZkczUzbHd3a3JxaHYy
-OGEud2ViLXBsYXRmb3JtLnRlc3QwMIIud3d3Mi54bi0tbjhqNmRzNTNsd3drcnFo
-djI4YS53ZWItcGxhdGZvcm0udGVzdDAxgi94bi0tbHZlLTZsYWQueG4tLWx2ZS02
-bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdDAzgjF4bi0tbjhqNmRzNTNsd3drcnFo
-djI4YS53d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0MDOCMXd3dy54bi0tbjhqNmRz
-NTNsd3drcnFodjI4YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwNIIyeG4tLW44ajZk
-czUzbHd3a3JxaHYyOGEud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwNIIyeG4t
-LW44ajZkczUzbHd3a3JxaHYyOGEud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3Qw
-NIIyd3d3MS54bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBsYXRmb3Jt
-LnRlc3QwNIIyd3d3Mi54bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBs
-YXRmb3JtLnRlc3QwOII2eG4tLWx2ZS02bGFkLnhuLS1uOGo2ZHM1M2x3d2tycWh2
-MjhhLndlYi1wbGF0Zm9ybS50ZXN0MDiCNnhuLS1uOGo2ZHM1M2x3d2tycWh2Mjhh
-LnhuLS1sdmUtNmxhZC53ZWItcGxhdGZvcm0udGVzdDA8gjp4bi0tbHZlLTZsYWQu
-eG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MDyC
-OnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBs
-YXRmb3JtLnRlc3QwQ4JBeG4tLW44ajZkczUzbHd3a3JxaHYyOGEueG4tLW44ajZk
-czUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3QwR4JFeG4tLW44ajZkczUz
-bHd3a3JxaHYyOGEueG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0
-Zm9ybS50ZXN0MBMGA1UdJQQMMAoGCCsGAQUFBwMBMIIJhQYDVR0RBIIJfDCCCXiC
-EXdlYi1wbGF0Zm9ybS50ZXN0ghVub3Qtd2ViLXBsYXRmb3JtLnRlc3SCFXd3dy53
-ZWItcGxhdGZvcm0udGVzdIIWd3d3Mi53ZWItcGxhdGZvcm0udGVzdIIWd3d3MS53
-ZWItcGxhdGZvcm0udGVzdIIZd3d3Lnd3dy53ZWItcGxhdGZvcm0udGVzdIIZd3d3
-Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIad3d3Lnd3dzEud2ViLXBsYXRmb3JtLnRl
-c3SCGnd3dzIud3d3LndlYi1wbGF0Zm9ybS50ZXN0ghp3d3cxLm5vdC13ZWItcGxh
-dGZvcm0udGVzdIIad3d3MS53d3cud2ViLXBsYXRmb3JtLnRlc3SCGnd3dzIubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0ghp3d3cud3d3Mi53ZWItcGxhdGZvcm0udGVzdIIb
-d3d3MS53d3cyLndlYi1wbGF0Zm9ybS50ZXN0ght3d3cyLnd3dzEud2ViLXBsYXRm
-b3JtLnRlc3SCG3d3dzIud3d3Mi53ZWItcGxhdGZvcm0udGVzdIIbd3d3MS53d3cx
-LndlYi1wbGF0Zm9ybS50ZXN0gh13d3cud3d3Lm5vdC13ZWItcGxhdGZvcm0udGVz
-dIIed3d3Lnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0gh53d3cud3d3Mi5ub3Qt
-d2ViLXBsYXRmb3JtLnRlc3SCHnhuLS1sdmUtNmxhZC53ZWItcGxhdGZvcm0udGVz
-dIIed3d3Mi53d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0gh53d3cxLnd3dy5ub3Qt
-d2ViLXBsYXRmb3JtLnRlc3SCH3d3dzIud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRl
-c3SCH3d3dzEud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzEud3d3MS5u
-b3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzIud3d3MS5ub3Qtd2ViLXBsYXRmb3Jt
-LnRlc3SCInhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCInd3dy54
-bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3SCInhuLS1sdmUtNmxhZC53d3cu
-d2ViLXBsYXRmb3JtLnRlc3SCI3d3dzEueG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9y
-bS50ZXN0giN3d3cyLnhuLS1sdmUtNmxhZC53ZWItcGxhdGZvcm0udGVzdIIjeG4t
-LWx2ZS02bGFkLnd3dzEud2ViLXBsYXRmb3JtLnRlc3SCI3huLS1sdmUtNmxhZC53
-d3cyLndlYi1wbGF0Zm9ybS50ZXN0giZ3d3cueG4tLWx2ZS02bGFkLm5vdC13ZWIt
-cGxhdGZvcm0udGVzdIImeG4tLWx2ZS02bGFkLnd3dy5ub3Qtd2ViLXBsYXRmb3Jt
-LnRlc3SCJ3d3dzIueG4tLWx2ZS02bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdIIn
-eG4tLWx2ZS02bGFkLnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0gid3d3cxLnhu
-LS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCJ3huLS1sdmUtNmxhZC53
-d3cyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIpeG4tLW44ajZkczUzbHd3a3JxaHYy
-OGEud2ViLXBsYXRmb3JtLnRlc3SCK3huLS1sdmUtNmxhZC54bi0tbHZlLTZsYWQu
-d2ViLXBsYXRmb3JtLnRlc3SCLXd3dy54bi0tbjhqNmRzNTNsd3drcnFodjI4YS53
-ZWItcGxhdGZvcm0udGVzdIIteG4tLW44ajZkczUzbHd3a3JxaHYyOGEud3d3Lndl
-Yi1wbGF0Zm9ybS50ZXN0gi14bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2Vi
-LXBsYXRmb3JtLnRlc3SCLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnd3dzIud2Vi
-LXBsYXRmb3JtLnRlc3SCLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnd3dzEud2Vi
-LXBsYXRmb3JtLnRlc3SCLnd3dzEueG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2Vi
-LXBsYXRmb3JtLnRlc3SCLnd3dzIueG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2Vi
-LXBsYXRmb3JtLnRlc3SCL3huLS1sdmUtNmxhZC54bi0tbHZlLTZsYWQubm90LXdl
-Yi1wbGF0Zm9ybS50ZXN0gjF4bi0tbjhqNmRzNTNsd3drcnFodjI4YS53d3cubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0gjF3d3cueG4tLW44ajZkczUzbHd3a3JxaHYyOGEu
-bm90LXdlYi1wbGF0Zm9ybS50ZXN0gjJ4bi0tbjhqNmRzNTNsd3drcnFodjI4YS53
-d3cxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIyeG4tLW44ajZkczUzbHd3a3JxaHYy
-OGEud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCMnd3dzEueG4tLW44ajZkczUz
-bHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50ZXN0gjJ3d3cyLnhuLS1uOGo2
-ZHM1M2x3d2tycWh2MjhhLm5vdC13ZWItcGxhdGZvcm0udGVzdII2eG4tLWx2ZS02
-bGFkLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLndlYi1wbGF0Zm9ybS50ZXN0gjZ4
-bi0tbjhqNmRzNTNsd3drcnFodjI4YS54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3Jt
-LnRlc3SCOnhuLS1sdmUtNmxhZC54bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qt
-d2ViLXBsYXRmb3JtLnRlc3SCOnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnhuLS1s
-dmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCQXhuLS1uOGo2ZHM1M2x3d2ty
-cWh2MjhhLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLndlYi1wbGF0Zm9ybS50ZXN0
-gkV4bi0tbjhqNmRzNTNsd3drcnFodjI4YS54bi0tbjhqNmRzNTNsd3drcnFodjI4
-YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwDQYJKoZIhvcNAQELBQADggEBAG0UL9KU
-qA8vHcdylWhvBI3cITzCn1kyX31Lr/9x68SEMV50pY7AFZMEBTVT1OzACzk9rc/p
-OIRo1m+Z5CGhng6wOThjFtfYTmOvSqlLdYr/AOND9PvJ8iR4zbXpwTSQgiVBgW3u
-aIYbBHbrOTD7mFdcrIo8nPc6seilpbzcEvLLAiGV7qgLvJXrC6lIg2eKXQHCuZO1
-SpQKhKi1+11JvbU3d9h96iVLG4WOVxmhALkJJvAZ7kPaTs76md4G6/B7WcO+F5wc
-oEgnZoLU0rDMPDFCWsKLWVadseJiRCMs6Nrjog8Y1bMQPLTzCDO/8l2h8Ny1lxWx
-GfyYQSXWV8lnS0w=
+MIIW5TCCFc2gAwIBAgICBIIwDQYJKoZIhvcNAQELBQAwHTEbMBkGA1UEAwwSd2Vi
+LXBsYXRmb3JtLXRlc3RzMB4XDTI0MTAxMjAxMDQ0NloXDTI1MTAxMjAxMDQ0Nlow
+HTEbMBkGA1UEAwwSd2ViLXBsYXRmb3JtLXRlc3RzMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEA03kHWKuFeT1xtYw3M/hYmoGe9ZM26J2WIPIVD0SOU86w
+g+2L5JwllOH5L4i6vSz4qV2NAYnpSCUNNIGk7F8YLWFXP8O8GDMgjg1V/JDYCPj5
+KFa6bAjLhHD9tLKVcRn7h6L7Y7FYWkYm6LWNOctg5UTbZVUEcCq0xeZKJXGJFguV
+RK9CTz5wWUxYN3LvdAnW2XyryPqyUZSHcF55zYJBLDNUxkdPjI7nLS/y+WryIK89
+47RhiwbI9yI26Ir3IcFy2xLjs5+qo1DJcfCVC/m/8+86tgiSqmJwTJUW/cAVSd51
+F5X0P2SSP2YZctEXSInSUDMFmdQMecpxQBZV2pWNjQIDAQABo4IULTCCFCkwDAYD
+VR0TBAUwAwEB/zAdBgNVHQ4EFgQUyWVn3/hgxfvg9xXR7Vttc+Jz1OcwRgYDVR0j
+BD8wPYAUyWVn3/hgxfvg9xXR7Vttc+Jz1OehIaQfMB0xGzAZBgNVBAMMEndlYi1w
+bGF0Zm9ybS10ZXN0c4ICBIIwCwYDVR0PBAQDAgIEMIIKBQYDVR0eBIIJ/DCCCfig
+ggn0MBOCEXdlYi1wbGF0Zm9ybS50ZXN0MBeCFXd3dy53ZWItcGxhdGZvcm0udGVz
+dDAXghVub3Qtd2ViLXBsYXRmb3JtLnRlc3QwGIIWd3d3MS53ZWItcGxhdGZvcm0u
+dGVzdDAYghZ3d3cyLndlYi1wbGF0Zm9ybS50ZXN0MBuCGXd3dy53d3cud2ViLXBs
+YXRmb3JtLnRlc3QwG4IZd3d3Lm5vdC13ZWItcGxhdGZvcm0udGVzdDAcghp3d3cy
+Lnd3dy53ZWItcGxhdGZvcm0udGVzdDAcghp3d3cxLm5vdC13ZWItcGxhdGZvcm0u
+dGVzdDAcghp3d3cyLm5vdC13ZWItcGxhdGZvcm0udGVzdDAcghp3d3cud3d3MS53
+ZWItcGxhdGZvcm0udGVzdDAcghp3d3cud3d3Mi53ZWItcGxhdGZvcm0udGVzdDAc
+ghp3d3cxLnd3dy53ZWItcGxhdGZvcm0udGVzdDAdght3d3cyLnd3dzIud2ViLXBs
+YXRmb3JtLnRlc3QwHYIbd3d3MS53d3cxLndlYi1wbGF0Zm9ybS50ZXN0MB2CG3d3
+dzIud3d3MS53ZWItcGxhdGZvcm0udGVzdDAdght3d3cxLnd3dzIud2ViLXBsYXRm
+b3JtLnRlc3QwH4Idd3d3Lnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwIIIed3d3
+Lnd3dzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCCCHnd3dzIud3d3Lm5vdC13ZWIt
+cGxhdGZvcm0udGVzdDAggh53d3cud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3Qw
+IIIeeG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0MCCCHnd3dzEud3d3Lm5v
+dC13ZWItcGxhdGZvcm0udGVzdDAhgh93d3cxLnd3dzIubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0MCGCH3d3dzIud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwIYIfd3d3
+Mi53d3cyLm5vdC13ZWItcGxhdGZvcm0udGVzdDAhgh93d3cxLnd3dzEubm90LXdl
+Yi1wbGF0Zm9ybS50ZXN0MCSCInhuLS1sdmUtNmxhZC53d3cud2ViLXBsYXRmb3Jt
+LnRlc3QwJIIid3d3LnhuLS1sdmUtNmxhZC53ZWItcGxhdGZvcm0udGVzdDAkgiJ4
+bi0tbHZlLTZsYWQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCWCI3d3dzEueG4tLWx2
+ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0MCWCI3huLS1sdmUtNmxhZC53d3cxLndl
+Yi1wbGF0Zm9ybS50ZXN0MCWCI3d3dzIueG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9y
+bS50ZXN0MCWCI3huLS1sdmUtNmxhZC53d3cyLndlYi1wbGF0Zm9ybS50ZXN0MCiC
+Jnd3dy54bi0tbHZlLTZsYWQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCiCJnhuLS1s
+dmUtNmxhZC53d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCmCJ3d3dzIueG4tLWx2
+ZS02bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdDApgid4bi0tbHZlLTZsYWQud3d3
+MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwKYIneG4tLWx2ZS02bGFkLnd3dzIubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0MCmCJ3d3dzEueG4tLWx2ZS02bGFkLm5vdC13ZWIt
+cGxhdGZvcm0udGVzdDArgil4bi0tbjhqNmRzNTNsd3drcnFodjI4YS53ZWItcGxh
+dGZvcm0udGVzdDAtgit4bi0tbHZlLTZsYWQueG4tLWx2ZS02bGFkLndlYi1wbGF0
+Zm9ybS50ZXN0MC+CLXd3dy54bi0tbjhqNmRzNTNsd3drcnFodjI4YS53ZWItcGxh
+dGZvcm0udGVzdDAvgi14bi0tbjhqNmRzNTNsd3drcnFodjI4YS53d3cud2ViLXBs
+YXRmb3JtLnRlc3QwL4IteG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdlYi1w
+bGF0Zm9ybS50ZXN0MDCCLnd3dzEueG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2Vi
+LXBsYXRmb3JtLnRlc3QwMIIueG4tLW44ajZkczUzbHd3a3JxaHYyOGEud3d3MS53
+ZWItcGxhdGZvcm0udGVzdDAwgi54bi0tbjhqNmRzNTNsd3drcnFodjI4YS53d3cy
+LndlYi1wbGF0Zm9ybS50ZXN0MDCCLnd3dzIueG4tLW44ajZkczUzbHd3a3JxaHYy
+OGEud2ViLXBsYXRmb3JtLnRlc3QwMYIveG4tLWx2ZS02bGFkLnhuLS1sdmUtNmxh
+ZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwM4Ixd3d3LnhuLS1uOGo2ZHM1M2x3d2ty
+cWh2MjhhLm5vdC13ZWItcGxhdGZvcm0udGVzdDAzgjF4bi0tbjhqNmRzNTNsd3dr
+cnFodjI4YS53d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0MDSCMnd3dzEueG4tLW44
+ajZkczUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MDSCMnhuLS1u
+OGo2ZHM1M2x3d2tycWh2MjhhLnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MDSC
+Mnd3dzIueG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50
+ZXN0MDSCMnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnd3dzIubm90LXdlYi1wbGF0
+Zm9ybS50ZXN0MDiCNnhuLS1sdmUtNmxhZC54bi0tbjhqNmRzNTNsd3drcnFodjI4
+YS53ZWItcGxhdGZvcm0udGVzdDA4gjZ4bi0tbjhqNmRzNTNsd3drcnFodjI4YS54
+bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3QwPII6eG4tLWx2ZS02bGFkLnhu
+LS1uOGo2ZHM1M2x3d2tycWh2MjhhLm5vdC13ZWItcGxhdGZvcm0udGVzdDA8gjp4
+bi0tbjhqNmRzNTNsd3drcnFodjI4YS54bi0tbHZlLTZsYWQubm90LXdlYi1wbGF0
+Zm9ybS50ZXN0MEOCQXhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnhuLS1uOGo2ZHM1
+M2x3d2tycWh2MjhhLndlYi1wbGF0Zm9ybS50ZXN0MEeCRXhuLS1uOGo2ZHM1M2x3
+d2tycWh2MjhhLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLm5vdC13ZWItcGxhdGZv
+cm0udGVzdDATBgNVHSUEDDAKBggrBgEFBQcDATCCCYUGA1UdEQSCCXwwggl4ghF3
+ZWItcGxhdGZvcm0udGVzdIIVd3d3LndlYi1wbGF0Zm9ybS50ZXN0ghVub3Qtd2Vi
+LXBsYXRmb3JtLnRlc3SCFnd3dzEud2ViLXBsYXRmb3JtLnRlc3SCFnd3dzIud2Vi
+LXBsYXRmb3JtLnRlc3SCGXd3dy53d3cud2ViLXBsYXRmb3JtLnRlc3SCGXd3dy5u
+b3Qtd2ViLXBsYXRmb3JtLnRlc3SCGnd3dzIud3d3LndlYi1wbGF0Zm9ybS50ZXN0
+ghp3d3cxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIad3d3Mi5ub3Qtd2ViLXBsYXRm
+b3JtLnRlc3SCGnd3dy53d3cxLndlYi1wbGF0Zm9ybS50ZXN0ghp3d3cud3d3Mi53
+ZWItcGxhdGZvcm0udGVzdIIad3d3MS53d3cud2ViLXBsYXRmb3JtLnRlc3SCG3d3
+dzIud3d3Mi53ZWItcGxhdGZvcm0udGVzdIIbd3d3MS53d3cxLndlYi1wbGF0Zm9y
+bS50ZXN0ght3d3cyLnd3dzEud2ViLXBsYXRmb3JtLnRlc3SCG3d3dzEud3d3Mi53
+ZWItcGxhdGZvcm0udGVzdIIdd3d3Lnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
+Hnd3dy53d3cyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIed3d3Mi53d3cubm90LXdl
+Yi1wbGF0Zm9ybS50ZXN0gh53d3cud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
+HnhuLS1sdmUtNmxhZC53ZWItcGxhdGZvcm0udGVzdIIed3d3MS53d3cubm90LXdl
+Yi1wbGF0Zm9ybS50ZXN0gh93d3cxLnd3dzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0
+gh93d3cyLnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0gh93d3cyLnd3dzIubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0gh93d3cxLnd3dzEubm90LXdlYi1wbGF0Zm9ybS50
+ZXN0giJ4bi0tbHZlLTZsYWQud3d3LndlYi1wbGF0Zm9ybS50ZXN0giJ3d3cueG4t
+LWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0giJ4bi0tbHZlLTZsYWQubm90LXdl
+Yi1wbGF0Zm9ybS50ZXN0giN3d3cxLnhuLS1sdmUtNmxhZC53ZWItcGxhdGZvcm0u
+dGVzdIIjeG4tLWx2ZS02bGFkLnd3dzEud2ViLXBsYXRmb3JtLnRlc3SCI3d3dzIu
+eG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0giN4bi0tbHZlLTZsYWQud3d3
+Mi53ZWItcGxhdGZvcm0udGVzdIImd3d3LnhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBs
+YXRmb3JtLnRlc3SCJnhuLS1sdmUtNmxhZC53d3cubm90LXdlYi1wbGF0Zm9ybS50
+ZXN0gid3d3cyLnhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCJ3hu
+LS1sdmUtNmxhZC53d3cxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIneG4tLWx2ZS02
+bGFkLnd3dzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0gid3d3cxLnhuLS1sdmUtNmxh
+ZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCKXhuLS1uOGo2ZHM1M2x3d2tycWh2Mjhh
+LndlYi1wbGF0Zm9ybS50ZXN0git4bi0tbHZlLTZsYWQueG4tLWx2ZS02bGFkLndl
+Yi1wbGF0Zm9ybS50ZXN0gi13d3cueG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2Vi
+LXBsYXRmb3JtLnRlc3SCLXhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnd3dy53ZWIt
+cGxhdGZvcm0udGVzdIIteG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdlYi1w
+bGF0Zm9ybS50ZXN0gi53d3cxLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLndlYi1w
+bGF0Zm9ybS50ZXN0gi54bi0tbjhqNmRzNTNsd3drcnFodjI4YS53d3cxLndlYi1w
+bGF0Zm9ybS50ZXN0gi54bi0tbjhqNmRzNTNsd3drcnFodjI4YS53d3cyLndlYi1w
+bGF0Zm9ybS50ZXN0gi53d3cyLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLndlYi1w
+bGF0Zm9ybS50ZXN0gi94bi0tbHZlLTZsYWQueG4tLWx2ZS02bGFkLm5vdC13ZWIt
+cGxhdGZvcm0udGVzdIIxd3d3LnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLm5vdC13
+ZWItcGxhdGZvcm0udGVzdIIxeG4tLW44ajZkczUzbHd3a3JxaHYyOGEud3d3Lm5v
+dC13ZWItcGxhdGZvcm0udGVzdIIyd3d3MS54bi0tbjhqNmRzNTNsd3drcnFodjI4
+YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCMnhuLS1uOGo2ZHM1M2x3d2tycWh2Mjhh
+Lnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0gjJ3d3cyLnhuLS1uOGo2ZHM1M2x3
+d2tycWh2MjhhLm5vdC13ZWItcGxhdGZvcm0udGVzdIIyeG4tLW44ajZkczUzbHd3
+a3JxaHYyOGEud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCNnhuLS1sdmUtNmxh
+ZC54bi0tbjhqNmRzNTNsd3drcnFodjI4YS53ZWItcGxhdGZvcm0udGVzdII2eG4t
+LW44ajZkczUzbHd3a3JxaHYyOGEueG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50
+ZXN0gjp4bi0tbHZlLTZsYWQueG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdl
+Yi1wbGF0Zm9ybS50ZXN0gjp4bi0tbjhqNmRzNTNsd3drcnFodjI4YS54bi0tbHZl
+LTZsYWQubm90LXdlYi1wbGF0Zm9ybS50ZXN0gkF4bi0tbjhqNmRzNTNsd3drcnFo
+djI4YS54bi0tbjhqNmRzNTNsd3drcnFodjI4YS53ZWItcGxhdGZvcm0udGVzdIJF
+eG4tLW44ajZkczUzbHd3a3JxaHYyOGEueG4tLW44ajZkczUzbHd3a3JxaHYyOGEu
+bm90LXdlYi1wbGF0Zm9ybS50ZXN0MA0GCSqGSIb3DQEBCwUAA4IBAQBifqUfZhtG
+pcQJgQ86u/1+uO39IfQ7gpLcBVc6YBmZ9NBBkk7Du8+JJ1eDBw+U47usXPkc1oqu
+Nv7k9Gg2Ln0I5mVVVcBUP84z0pxKCc6KKhJXcjSu9dMFBxT/pjDpPQ1WVzPJVmNw
+ywuRlVHQxk5Pc3dXKUAZoti7GoX1yd1xMH8Rz2vL9f7QLW+uVvRbhSp6DcTq8BPJ
+RLni1DQ9J02nHhD/JULUoxp/2HLDdPt/++145Eoy5GlycNcqw7VVraongsVAuG6h
+7zZYthFwc6+81dxaGmsgOG7baljBN4k4Jdjkt6P+0QVodn/+5Sto+Gb1TzoYjYpY
+J9G36zcLRJyc
-----END CERTIFICATE-----
diff --git a/tests/wpt/tests/tools/certs/web-platform.test.key b/tests/wpt/tests/tools/certs/web-platform.test.key
index 0df3f579240..4f68bb3caa0 100644
--- a/tests/wpt/tests/tools/certs/web-platform.test.key
+++ b/tests/wpt/tests/tools/certs/web-platform.test.key
@@ -1,28 +1,28 @@
-----BEGIN PRIVATE KEY-----
-MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDOovdiO3UPxIH0
-s/PB2x3MBLJag+7XqjffxrGB5AOGBoRN+wlnEdUCK79CdFR+O4e30ArCJNzmcODj
-rTaICx6JpL9oqEm8VxR7SLwQR6h/1mN4rK4KnqHVxxiUdDaINzkNzKB1fOSBh+Fc
-9FspIc+1BbAhZYmoAXJ/wzfvCTHeEE+fpoQ8Nb7UdyBNJgsb9u1f8hahAiBrFy1i
-HcG4p10YnUJVOfcIeiVWPjX3EHgbvgUdMuyMW57y83ZH6PQ+gLYAA8DrwT4etOtV
-6YDR+b9Bsq6jWCPFdmcSIGPTTD8IvAepMsgt2Xfx8NUgd4IatpjPZmeU9H55Wxms
-I097LMwtAgMBAAECggEBAKh+urqfQRVaZ53iHyI0SlfSfJzSeC/j3SvcGWKRS04+
-giQUT9Z78/WRNqQ5t6w3XrPEMQGejYJbCQaed5j3eC9E58+vanDpkQn2hWPBCuUz
-LGl6ZXDDabOoZaKoIM9yOFPISA+Fh88XvezOVId1yqkRuk2BPn6Ar5z+0t1X4hHw
-Q9ON3CMFBWrPjUntfvlChmMqXYlOnnd402EGUrm5E5mYQc5En4lEASNneo2uD6GX
-Y72eDCPG/ShvRlunmg7nKn0ciHoH1L55He/V1QdcTqo/dTVX9mEFnvBmx+aV8XDw
-VuRuLujHmXj9RKENOJs7n6W5n/Qd2/OTISzx6vI3PQECgYEA6nAKSK0B0MprZQUt
-vOKETOExr8XMFDsbigt/o8kvXKixZoLYOkAzSObY9oDkCiy5RWdqhS/e1Ufivi9Y
-IFqXmB8rpXeN04zx8z3pzo63ohS6CgWIg63YZ4+KScx00xGKNimb8Kug39onCN8b
-M3Sbri0AGvUCtfHjd4MACGMqvUcCgYEA4aRVy7pF0yMV4wPuwjwzKkdVF9Dh2i9C
-Gd0WDRKrccjtkSL7uy7QKYGYnGjLttOLnxx7GN3GhHWBoCE8kMsSOyMIhWzDv3a3
-LsbP2HI8fWmbmLaU25qMhdfKQiAlLgCJdvSuWzsjbcf3fZ+0LLsCagPF7V0ed9A1
-niy5sohclOsCgYEAi8ZVO1N7O6MUONzHklBzlOrHFweVT5KWLs4AQgTXaiVh776f
-cMuKSDLqtL3QOIjFxa2NAu+xqfP8KmxL3K5mp9odyb/oHXNxZhdJ6U+KCObWrNbz
-t57U4ZnhV3LBTH6uqvBP+0Q43H5Su6VZsGobz9MgtvHRte0MM9s1D8sgVk0CgYEA
-t6eoZV/BwW5HPDVROisBgiH5Mp9DlPDuHlsCvbU6ciyWoJEWz2305DOlYXkyhiZ8
-+A6Yas7n65ww24Lx5vBCcHu9TcwPL2GTC7GqLoQck/9HM+84Dd4nDjFrYJMFcAHj
-4TyaRYtG9O3TlR5N6jJ0bpGPofku+VowqgPBSX0Pze0CgYAbMqrQu/nCK5IC3Yyy
-hkssanrfxV+GXTo351WqFWlHDaImbj4PaPsUR4IYJq62UyOWH8mQ81Rfpl/SKFbW
-AQsCmBT8o5P81iVvLHHdYiyCqLgtLH3m7dgDYOze0BUlm4OUfT5tmewau75wVdiE
-xxjzn20+iZ/rdfKXIE+30AZ3eg==
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDg/mIE/8f6jTVz
+bI2TZwmA+tIws6+TpSuhuot9JbArcIf1JSicQl2itKgDFqM1iktbHeLfYChZw3TS
+QZUyhalfCG3aphUwH1bjGbRAuBHIOS3ncCl/aCvqbIrU3PRpCIVTMfz5OtDlT5CR
+ynwg9qLlxacpiyj9nw2ASEoN3liLWbQOROhuPtvmRKwaFRm7OY669oFwaQqoeDrC
+B9LPlEJiYjWjBZIghnsE1Y0DSV7lz+m7cKYG+PnZKNYfKg7/MV2g5PqWXqEziJBG
+FoicL4Dbsk7X+wvG+T9NwKrQKE0t1sE+oIsRdLLXvp0k++um57IN1KuvK1xV/Mg9
+TeVx/zlpAgMBAAECggEASFMdmTPLygvYcckkXYzSrkZyiLtKJnEC7JM1wb36uowK
++E/AlTJ0PRhLpeqB/nT9MkYSJvIXJnvBMtFoL3xt7KGeBpo612RLnuclXWSOOsm+
+qtYQUOdgrpPDsRdx7c2SZiL8ifVRL1V7SJJJgqMlzCzURnN4csbNJT6Xp4ug9PH/
+sn8kWgZyEPW2MdkbY0APykbkWzXvkyJQ4l9qm3Z1sbWQLHkvyD3aP0fS4EGtOoY7
+shgufnXmkGRkSl3oSg/JT7+z/W0lExyN28O53Wm9kBlHxmSguHpmH8ihQTpuLy8K
+16Xv9k5z+5qJMEg4oC8/VAHGnlV5gCAFayjfypoLnQKBgQDzVDJZPXNS9OUYCJJE
+sOoAHfBul03uili9ThGtwg6rRBzClsd9ldmjqfBEdPF85o/fnRF8Hhp6IAGjP7wv
+JCY0KKUkIl5KweWCfCtYkVzT6d7q0tMaIx/lL69F6XR0aK3GtMH5zfM6tOb+MVs5
+KxGdkQPEYIDNF2UtNbHeRFkNbwKBgQDstcK2WoCOy4kfifSCL4OKpdZrSXT/pTcA
+3YUMjnNcX/XVNXgHU9z+FLf63oN3D0KvmLqPyz0NEX8ew77FxCxU5LcfPYLtDI0o
+J3F7DZYQKk8MSe4HCbQDwMhDw+RHSE+JJICm0V8yrR9UpW0v7tqLrjk+HiSyx+yp
+MkhgVGDqpwKBgQCSuHkngDsykUI2bKytyLNAYM0iEg/GvxrlAtb8G+A2evqQhtRB
+MIMsAYND8/PM6UVlg1MQsSIr83KpWfwBvN1gZAW3tRWAJExckrycSgJcMU/d7kOm
+JfnMeyVHlY5HxvrJryKrmviHtJ74NRCZdxPHG7LWzY28nNfAG/llWXcM9wKBgF+b
+Eifg6efC4YFxkOY8Fp8bWD1BEBZpPowE7MYjiwiWYY5Z6D7danbdG2oiEWs3KLIP
+t9p4NhJfLL7aROVP1K/9KNFfYNApr6G2PKl81U12KTNHcPI6wxB4/uoP5tW7qRQ1
+QBkgm5i2P99KaY1gpbihB9HFDwF+qmG0Q3NU4UglAoGBAI9fosEAe8SthkTZvUxQ
+cqytj++mWX9Yz2ZKthORFwI6Q3FGYBUx1I67Lu7qiWe69frcw3pN2Yt65jc08w10
+TOEorKsvYnZx5vaPNiFicmW+bpgqfAkL/j7GdDrgddDL9NYVbVGDLHWPRqmtBEfa
+fH90hyluwXFzzgKqYmg+GzKu
-----END PRIVATE KEY-----
diff --git a/tests/wpt/tests/tools/certs/web-platform.test.pem b/tests/wpt/tests/tools/certs/web-platform.test.pem
index 1c5859d2066..02a2d94e935 100644
--- a/tests/wpt/tests/tools/certs/web-platform.test.pem
+++ b/tests/wpt/tests/tools/certs/web-platform.test.pem
@@ -1,133 +1,133 @@
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 114201 (0x1be19)
+ Serial Number: 1155 (0x483)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=web-platform-tests
Validity
- Not Before: Sep 12 01:03:10 2024 GMT
- Not After : Sep 12 01:03:10 2025 GMT
+ Not Before: Oct 12 01:04:46 2024 GMT
+ Not After : Oct 12 01:04:46 2025 GMT
Subject: CN=web-platform.test
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
- 00:ce:a2:f7:62:3b:75:0f:c4:81:f4:b3:f3:c1:db:
- 1d:cc:04:b2:5a:83:ee:d7:aa:37:df:c6:b1:81:e4:
- 03:86:06:84:4d:fb:09:67:11:d5:02:2b:bf:42:74:
- 54:7e:3b:87:b7:d0:0a:c2:24:dc:e6:70:e0:e3:ad:
- 36:88:0b:1e:89:a4:bf:68:a8:49:bc:57:14:7b:48:
- bc:10:47:a8:7f:d6:63:78:ac:ae:0a:9e:a1:d5:c7:
- 18:94:74:36:88:37:39:0d:cc:a0:75:7c:e4:81:87:
- e1:5c:f4:5b:29:21:cf:b5:05:b0:21:65:89:a8:01:
- 72:7f:c3:37:ef:09:31:de:10:4f:9f:a6:84:3c:35:
- be:d4:77:20:4d:26:0b:1b:f6:ed:5f:f2:16:a1:02:
- 20:6b:17:2d:62:1d:c1:b8:a7:5d:18:9d:42:55:39:
- f7:08:7a:25:56:3e:35:f7:10:78:1b:be:05:1d:32:
- ec:8c:5b:9e:f2:f3:76:47:e8:f4:3e:80:b6:00:03:
- c0:eb:c1:3e:1e:b4:eb:55:e9:80:d1:f9:bf:41:b2:
- ae:a3:58:23:c5:76:67:12:20:63:d3:4c:3f:08:bc:
- 07:a9:32:c8:2d:d9:77:f1:f0:d5:20:77:82:1a:b6:
- 98:cf:66:67:94:f4:7e:79:5b:19:ac:23:4f:7b:2c:
- cc:2d
+ 00:e0:fe:62:04:ff:c7:fa:8d:35:73:6c:8d:93:67:
+ 09:80:fa:d2:30:b3:af:93:a5:2b:a1:ba:8b:7d:25:
+ b0:2b:70:87:f5:25:28:9c:42:5d:a2:b4:a8:03:16:
+ a3:35:8a:4b:5b:1d:e2:df:60:28:59:c3:74:d2:41:
+ 95:32:85:a9:5f:08:6d:da:a6:15:30:1f:56:e3:19:
+ b4:40:b8:11:c8:39:2d:e7:70:29:7f:68:2b:ea:6c:
+ 8a:d4:dc:f4:69:08:85:53:31:fc:f9:3a:d0:e5:4f:
+ 90:91:ca:7c:20:f6:a2:e5:c5:a7:29:8b:28:fd:9f:
+ 0d:80:48:4a:0d:de:58:8b:59:b4:0e:44:e8:6e:3e:
+ db:e6:44:ac:1a:15:19:bb:39:8e:ba:f6:81:70:69:
+ 0a:a8:78:3a:c2:07:d2:cf:94:42:62:62:35:a3:05:
+ 92:20:86:7b:04:d5:8d:03:49:5e:e5:cf:e9:bb:70:
+ a6:06:f8:f9:d9:28:d6:1f:2a:0e:ff:31:5d:a0:e4:
+ fa:96:5e:a1:33:88:90:46:16:88:9c:2f:80:db:b2:
+ 4e:d7:fb:0b:c6:f9:3f:4d:c0:aa:d0:28:4d:2d:d6:
+ c1:3e:a0:8b:11:74:b2:d7:be:9d:24:fb:eb:a6:e7:
+ b2:0d:d4:ab:af:2b:5c:55:fc:c8:3d:4d:e5:71:ff:
+ 39:69
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
X509v3 Subject Key Identifier:
- 43:82:25:04:5A:01:43:01:03:CE:51:1D:0C:4F:F6:48:3A:91:55:1A
+ 6D:E6:53:45:A0:4B:96:3B:B6:C1:D8:5B:E8:C4:E2:2A:9D:9B:A2:BA
X509v3 Authority Key Identifier:
- keyid:FE:64:41:FD:EB:25:D2:54:6A:A6:E1:36:F6:12:2A:56:F9:82:F6:B5
+ keyid:C9:65:67:DF:F8:60:C5:FB:E0:F7:15:D1:ED:5B:6D:73:E2:73:D4:E7
X509v3 Key Usage:
Digital Signature, Non Repudiation, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
X509v3 Subject Alternative Name:
- DNS:web-platform.test, DNS:not-web-platform.test, DNS:www.web-platform.test, DNS:www2.web-platform.test, DNS:www1.web-platform.test, DNS:www.www.web-platform.test, DNS:www.not-web-platform.test, DNS:www.www1.web-platform.test, DNS:www2.www.web-platform.test, DNS:www1.not-web-platform.test, DNS:www1.www.web-platform.test, DNS:www2.not-web-platform.test, DNS:www.www2.web-platform.test, DNS:www1.www2.web-platform.test, DNS:www2.www1.web-platform.test, DNS:www2.www2.web-platform.test, DNS:www1.www1.web-platform.test, DNS:www.www.not-web-platform.test, DNS:www.www1.not-web-platform.test, DNS:www.www2.not-web-platform.test, DNS:xn--lve-6lad.web-platform.test, DNS:www2.www.not-web-platform.test, DNS:www1.www.not-web-platform.test, DNS:www2.www2.not-web-platform.test, DNS:www1.www2.not-web-platform.test, DNS:www1.www1.not-web-platform.test, DNS:www2.www1.not-web-platform.test, DNS:xn--lve-6lad.not-web-platform.test, DNS:www.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.www.web-platform.test, DNS:www1.xn--lve-6lad.web-platform.test, DNS:www2.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.www1.web-platform.test, DNS:xn--lve-6lad.www2.web-platform.test, DNS:www.xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.www.not-web-platform.test, DNS:www2.xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.www1.not-web-platform.test, DNS:www1.xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.www2.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--lve-6lad.xn--lve-6lad.web-platform.test, DNS:www.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www2.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www1.web-platform.test, DNS:www1.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:www2.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--lve-6lad.xn--lve-6lad.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www.not-web-platform.test, DNS:www.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www1.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www2.not-web-platform.test, DNS:www1.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:www2.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--lve-6lad.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--lve-6lad.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test
+ DNS:web-platform.test, DNS:www.web-platform.test, DNS:not-web-platform.test, DNS:www1.web-platform.test, DNS:www2.web-platform.test, DNS:www.www.web-platform.test, DNS:www.not-web-platform.test, DNS:www2.www.web-platform.test, DNS:www1.not-web-platform.test, DNS:www2.not-web-platform.test, DNS:www.www1.web-platform.test, DNS:www.www2.web-platform.test, DNS:www1.www.web-platform.test, DNS:www2.www2.web-platform.test, DNS:www1.www1.web-platform.test, DNS:www2.www1.web-platform.test, DNS:www1.www2.web-platform.test, DNS:www.www.not-web-platform.test, DNS:www.www2.not-web-platform.test, DNS:www2.www.not-web-platform.test, DNS:www.www1.not-web-platform.test, DNS:xn--lve-6lad.web-platform.test, DNS:www1.www.not-web-platform.test, DNS:www1.www2.not-web-platform.test, DNS:www2.www1.not-web-platform.test, DNS:www2.www2.not-web-platform.test, DNS:www1.www1.not-web-platform.test, DNS:xn--lve-6lad.www.web-platform.test, DNS:www.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.not-web-platform.test, DNS:www1.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.www1.web-platform.test, DNS:www2.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.www2.web-platform.test, DNS:www.xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.www.not-web-platform.test, DNS:www2.xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.www1.not-web-platform.test, DNS:xn--lve-6lad.www2.not-web-platform.test, DNS:www1.xn--lve-6lad.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--lve-6lad.xn--lve-6lad.web-platform.test, DNS:www.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:www1.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www1.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www2.web-platform.test, DNS:www2.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--lve-6lad.xn--lve-6lad.not-web-platform.test, DNS:www.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www.not-web-platform.test, DNS:www1.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www1.not-web-platform.test, DNS:www2.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www2.not-web-platform.test, DNS:xn--lve-6lad.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--lve-6lad.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test
Signature Algorithm: sha256WithRSAEncryption
- 84:56:ff:85:c0:76:43:19:5a:7c:3d:e7:bf:19:f3:32:2d:18:
- 1b:fd:4c:2d:ff:be:73:d7:b0:ae:d9:1f:c4:a6:ae:c3:73:38:
- e7:ae:17:3a:e9:5e:d0:4a:f0:9b:d1:ca:6f:d9:8b:83:91:9e:
- 17:00:42:f2:52:8e:58:04:dd:49:71:c1:ed:d2:e9:98:c8:dc:
- 67:92:bb:60:15:df:37:5b:24:ef:ea:20:05:4d:fe:00:88:c3:
- d7:6c:d3:95:6e:28:c6:7e:dd:f4:fe:dd:bc:06:36:b2:b2:59:
- 2b:62:e1:a3:b8:4e:fc:4d:a9:e7:a7:38:c6:ec:d8:72:17:57:
- c5:f0:b8:c4:f0:e8:87:5e:67:e5:0f:43:a9:cb:1c:7a:f1:d6:
- 30:89:11:3f:ca:90:4a:3c:81:15:90:13:47:32:68:68:75:27:
- 7f:39:e4:cb:d6:c3:5f:c1:a1:90:ff:9e:4c:6d:6a:e2:44:2e:
- 09:d8:85:44:69:f8:55:ab:84:98:83:c6:e7:ed:e0:45:5d:f1:
- 39:4a:d1:92:c8:56:5d:9d:42:9d:b6:02:78:d9:48:a9:7e:ad:
- 45:37:bd:73:e6:ad:fa:c8:15:b3:90:bd:17:ec:9b:ae:63:e9:
- 98:8a:36:da:99:7a:77:0c:8c:a9:98:70:af:97:69:e5:90:c1:
- 4d:99:b2:a5
+ 41:30:c3:35:8a:8c:3c:5d:5d:a3:d7:10:28:81:59:c7:cd:b0:
+ a8:73:8f:1a:d1:36:be:40:86:3c:63:cb:1c:a9:41:26:a0:0c:
+ 6a:cf:b7:cf:76:3f:64:fa:ea:e5:74:9b:57:1d:b2:dd:92:ce:
+ ed:c1:32:ec:65:eb:7d:c2:73:ab:8d:95:33:b3:a3:d2:b0:6d:
+ 81:0d:3f:31:c3:89:23:49:39:da:6f:22:b5:1d:12:97:6e:cc:
+ 20:43:5a:ca:f4:d5:3e:01:be:90:03:b2:4e:f7:9c:e2:97:21:
+ 39:a3:33:8c:45:a4:6c:e9:3a:eb:87:2d:1d:39:e6:d8:bb:b2:
+ 15:01:a4:8f:70:25:61:4f:0f:5f:35:8d:9c:c6:fb:81:3b:52:
+ 15:94:90:e4:ee:d7:3b:b2:b7:68:45:46:bb:56:06:7f:83:73:
+ d9:a8:1c:0d:17:fb:ce:81:5d:1c:0a:4f:0c:75:68:a2:70:64:
+ 6d:de:ad:cf:ac:10:e5:e5:04:1f:e8:12:8d:59:27:e2:9a:76:
+ dd:30:89:bc:2e:22:ac:97:12:86:a0:45:9e:2f:e2:3f:c3:0a:
+ fe:14:6c:2a:28:a6:a3:00:81:d0:53:e2:4d:66:9c:13:9e:e5:
+ 25:02:27:b3:05:62:73:08:49:43:6e:15:74:0d:ed:dc:71:47:
+ 6c:79:53:1d
-----BEGIN CERTIFICATE-----
-MIIMsjCCC5qgAwIBAgIDAb4ZMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMMEndl
-Yi1wbGF0Zm9ybS10ZXN0czAeFw0yNDA5MTIwMTAzMTBaFw0yNTA5MTIwMTAzMTBa
-MBwxGjAYBgNVBAMMEXdlYi1wbGF0Zm9ybS50ZXN0MIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEAzqL3Yjt1D8SB9LPzwdsdzASyWoPu16o338axgeQDhgaE
-TfsJZxHVAiu/QnRUfjuHt9AKwiTc5nDg4602iAseiaS/aKhJvFcUe0i8EEeof9Zj
-eKyuCp6h1ccYlHQ2iDc5DcygdXzkgYfhXPRbKSHPtQWwIWWJqAFyf8M37wkx3hBP
-n6aEPDW+1HcgTSYLG/btX/IWoQIgaxctYh3BuKddGJ1CVTn3CHolVj419xB4G74F
-HTLsjFue8vN2R+j0PoC2AAPA68E+HrTrVemA0fm/QbKuo1gjxXZnEiBj00w/CLwH
-qTLILdl38fDVIHeCGraYz2ZnlPR+eVsZrCNPeyzMLQIDAQABo4IJ+jCCCfYwCQYD
-VR0TBAIwADAdBgNVHQ4EFgQUQ4IlBFoBQwEDzlEdDE/2SDqRVRowHwYDVR0jBBgw
-FoAU/mRB/esl0lRqpuE29hIqVvmC9rUwCwYDVR0PBAQDAgXgMBMGA1UdJQQMMAoG
-CCsGAQUFBwMBMIIJhQYDVR0RBIIJfDCCCXiCEXdlYi1wbGF0Zm9ybS50ZXN0ghVu
-b3Qtd2ViLXBsYXRmb3JtLnRlc3SCFXd3dy53ZWItcGxhdGZvcm0udGVzdIIWd3d3
-Mi53ZWItcGxhdGZvcm0udGVzdIIWd3d3MS53ZWItcGxhdGZvcm0udGVzdIIZd3d3
-Lnd3dy53ZWItcGxhdGZvcm0udGVzdIIZd3d3Lm5vdC13ZWItcGxhdGZvcm0udGVz
-dIIad3d3Lnd3dzEud2ViLXBsYXRmb3JtLnRlc3SCGnd3dzIud3d3LndlYi1wbGF0
-Zm9ybS50ZXN0ghp3d3cxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIad3d3MS53d3cu
-d2ViLXBsYXRmb3JtLnRlc3SCGnd3dzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghp3
-d3cud3d3Mi53ZWItcGxhdGZvcm0udGVzdIIbd3d3MS53d3cyLndlYi1wbGF0Zm9y
-bS50ZXN0ght3d3cyLnd3dzEud2ViLXBsYXRmb3JtLnRlc3SCG3d3dzIud3d3Mi53
-ZWItcGxhdGZvcm0udGVzdIIbd3d3MS53d3cxLndlYi1wbGF0Zm9ybS50ZXN0gh13
-d3cud3d3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIed3d3Lnd3dzEubm90LXdlYi1w
-bGF0Zm9ybS50ZXN0gh53d3cud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCHnhu
-LS1sdmUtNmxhZC53ZWItcGxhdGZvcm0udGVzdIIed3d3Mi53d3cubm90LXdlYi1w
-bGF0Zm9ybS50ZXN0gh53d3cxLnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3
-dzIud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzEud3d3Mi5ub3Qtd2Vi
-LXBsYXRmb3JtLnRlc3SCH3d3dzEud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
-H3d3dzIud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCInhuLS1sdmUtNmxhZC5u
-b3Qtd2ViLXBsYXRmb3JtLnRlc3SCInd3dy54bi0tbHZlLTZsYWQud2ViLXBsYXRm
-b3JtLnRlc3SCInhuLS1sdmUtNmxhZC53d3cud2ViLXBsYXRmb3JtLnRlc3SCI3d3
-dzEueG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0giN3d3cyLnhuLS1sdmUt
-NmxhZC53ZWItcGxhdGZvcm0udGVzdIIjeG4tLWx2ZS02bGFkLnd3dzEud2ViLXBs
-YXRmb3JtLnRlc3SCI3huLS1sdmUtNmxhZC53d3cyLndlYi1wbGF0Zm9ybS50ZXN0
-giZ3d3cueG4tLWx2ZS02bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdIImeG4tLWx2
-ZS02bGFkLnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCJ3d3dzIueG4tLWx2ZS02
-bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdIIneG4tLWx2ZS02bGFkLnd3dzEubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0gid3d3cxLnhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBs
-YXRmb3JtLnRlc3SCJ3huLS1sdmUtNmxhZC53d3cyLm5vdC13ZWItcGxhdGZvcm0u
-dGVzdIIpeG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3SC
-K3huLS1sdmUtNmxhZC54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3SCLXd3
-dy54bi0tbjhqNmRzNTNsd3drcnFodjI4YS53ZWItcGxhdGZvcm0udGVzdIIteG4t
-LW44ajZkczUzbHd3a3JxaHYyOGEud3d3LndlYi1wbGF0Zm9ybS50ZXN0gi14bi0t
-bjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCLnhuLS1u
-OGo2ZHM1M2x3d2tycWh2MjhhLnd3dzIud2ViLXBsYXRmb3JtLnRlc3SCLnhuLS1u
-OGo2ZHM1M2x3d2tycWh2MjhhLnd3dzEud2ViLXBsYXRmb3JtLnRlc3SCLnd3dzEu
-eG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3SCLnd3dzIu
-eG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3SCL3huLS1s
-dmUtNmxhZC54bi0tbHZlLTZsYWQubm90LXdlYi1wbGF0Zm9ybS50ZXN0gjF4bi0t
-bjhqNmRzNTNsd3drcnFodjI4YS53d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0gjF3
-d3cueG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50ZXN0
-gjJ4bi0tbjhqNmRzNTNsd3drcnFodjI4YS53d3cxLm5vdC13ZWItcGxhdGZvcm0u
-dGVzdIIyeG4tLW44ajZkczUzbHd3a3JxaHYyOGEud3d3Mi5ub3Qtd2ViLXBsYXRm
-b3JtLnRlc3SCMnd3dzEueG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdlYi1w
-bGF0Zm9ybS50ZXN0gjJ3d3cyLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLm5vdC13
-ZWItcGxhdGZvcm0udGVzdII2eG4tLWx2ZS02bGFkLnhuLS1uOGo2ZHM1M2x3d2ty
-cWh2MjhhLndlYi1wbGF0Zm9ybS50ZXN0gjZ4bi0tbjhqNmRzNTNsd3drcnFodjI4
-YS54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3SCOnhuLS1sdmUtNmxhZC54
-bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCOnhu
-LS1uOGo2ZHM1M2x3d2tycWh2MjhhLnhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRm
-b3JtLnRlc3SCQXhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnhuLS1uOGo2ZHM1M2x3
-d2tycWh2MjhhLndlYi1wbGF0Zm9ybS50ZXN0gkV4bi0tbjhqNmRzNTNsd3drcnFo
-djI4YS54bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBsYXRmb3JtLnRl
-c3QwDQYJKoZIhvcNAQELBQADggEBAIRW/4XAdkMZWnw9578Z8zItGBv9TC3/vnPX
-sK7ZH8SmrsNzOOeuFzrpXtBK8JvRym/Zi4ORnhcAQvJSjlgE3Ulxwe3S6ZjI3GeS
-u2AV3zdbJO/qIAVN/gCIw9ds05VuKMZ+3fT+3bwGNrKyWSti4aO4TvxNqeenOMbs
-2HIXV8XwuMTw6IdeZ+UPQ6nLHHrx1jCJET/KkEo8gRWQE0cyaGh1J3855MvWw1/B
-oZD/nkxtauJELgnYhURp+FWrhJiDxuft4EVd8TlK0ZLIVl2dQp22AnjZSKl+rUU3
-vXPmrfrIFbOQvRfsm65j6ZiKNtqZencMjKmYcK+XaeWQwU2ZsqU=
+MIIMsTCCC5mgAwIBAgICBIMwDQYJKoZIhvcNAQELBQAwHTEbMBkGA1UEAwwSd2Vi
+LXBsYXRmb3JtLXRlc3RzMB4XDTI0MTAxMjAxMDQ0NloXDTI1MTAxMjAxMDQ0Nlow
+HDEaMBgGA1UEAwwRd2ViLXBsYXRmb3JtLnRlc3QwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQDg/mIE/8f6jTVzbI2TZwmA+tIws6+TpSuhuot9JbArcIf1
+JSicQl2itKgDFqM1iktbHeLfYChZw3TSQZUyhalfCG3aphUwH1bjGbRAuBHIOS3n
+cCl/aCvqbIrU3PRpCIVTMfz5OtDlT5CRynwg9qLlxacpiyj9nw2ASEoN3liLWbQO
+ROhuPtvmRKwaFRm7OY669oFwaQqoeDrCB9LPlEJiYjWjBZIghnsE1Y0DSV7lz+m7
+cKYG+PnZKNYfKg7/MV2g5PqWXqEziJBGFoicL4Dbsk7X+wvG+T9NwKrQKE0t1sE+
+oIsRdLLXvp0k++um57IN1KuvK1xV/Mg9TeVx/zlpAgMBAAGjggn6MIIJ9jAJBgNV
+HRMEAjAAMB0GA1UdDgQWBBRt5lNFoEuWO7bB2FvoxOIqnZuiujAfBgNVHSMEGDAW
+gBTJZWff+GDF++D3FdHtW21z4nPU5zALBgNVHQ8EBAMCBeAwEwYDVR0lBAwwCgYI
+KwYBBQUHAwEwggmFBgNVHREEggl8MIIJeIIRd2ViLXBsYXRmb3JtLnRlc3SCFXd3
+dy53ZWItcGxhdGZvcm0udGVzdIIVbm90LXdlYi1wbGF0Zm9ybS50ZXN0ghZ3d3cx
+LndlYi1wbGF0Zm9ybS50ZXN0ghZ3d3cyLndlYi1wbGF0Zm9ybS50ZXN0ghl3d3cu
+d3d3LndlYi1wbGF0Zm9ybS50ZXN0ghl3d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0
+ghp3d3cyLnd3dy53ZWItcGxhdGZvcm0udGVzdIIad3d3MS5ub3Qtd2ViLXBsYXRm
+b3JtLnRlc3SCGnd3dzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghp3d3cud3d3MS53
+ZWItcGxhdGZvcm0udGVzdIIad3d3Lnd3dzIud2ViLXBsYXRmb3JtLnRlc3SCGnd3
+dzEud3d3LndlYi1wbGF0Zm9ybS50ZXN0ght3d3cyLnd3dzIud2ViLXBsYXRmb3Jt
+LnRlc3SCG3d3dzEud3d3MS53ZWItcGxhdGZvcm0udGVzdIIbd3d3Mi53d3cxLndl
+Yi1wbGF0Zm9ybS50ZXN0ght3d3cxLnd3dzIud2ViLXBsYXRmb3JtLnRlc3SCHXd3
+dy53d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0gh53d3cud3d3Mi5ub3Qtd2ViLXBs
+YXRmb3JtLnRlc3SCHnd3dzIud3d3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIed3d3
+Lnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0gh54bi0tbHZlLTZsYWQud2ViLXBs
+YXRmb3JtLnRlc3SCHnd3dzEud3d3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIfd3d3
+MS53d3cyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIfd3d3Mi53d3cxLm5vdC13ZWIt
+cGxhdGZvcm0udGVzdIIfd3d3Mi53d3cyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIf
+d3d3MS53d3cxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIieG4tLWx2ZS02bGFkLnd3
+dy53ZWItcGxhdGZvcm0udGVzdIIid3d3LnhuLS1sdmUtNmxhZC53ZWItcGxhdGZv
+cm0udGVzdIIieG4tLWx2ZS02bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdIIjd3d3
+MS54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3SCI3huLS1sdmUtNmxhZC53
+d3cxLndlYi1wbGF0Zm9ybS50ZXN0giN3d3cyLnhuLS1sdmUtNmxhZC53ZWItcGxh
+dGZvcm0udGVzdIIjeG4tLWx2ZS02bGFkLnd3dzIud2ViLXBsYXRmb3JtLnRlc3SC
+Jnd3dy54bi0tbHZlLTZsYWQubm90LXdlYi1wbGF0Zm9ybS50ZXN0giZ4bi0tbHZl
+LTZsYWQud3d3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIInd3d3Mi54bi0tbHZlLTZs
+YWQubm90LXdlYi1wbGF0Zm9ybS50ZXN0gid4bi0tbHZlLTZsYWQud3d3MS5ub3Qt
+d2ViLXBsYXRmb3JtLnRlc3SCJ3huLS1sdmUtNmxhZC53d3cyLm5vdC13ZWItcGxh
+dGZvcm0udGVzdIInd3d3MS54bi0tbHZlLTZsYWQubm90LXdlYi1wbGF0Zm9ybS50
+ZXN0gil4bi0tbjhqNmRzNTNsd3drcnFodjI4YS53ZWItcGxhdGZvcm0udGVzdIIr
+eG4tLWx2ZS02bGFkLnhuLS1sdmUtNmxhZC53ZWItcGxhdGZvcm0udGVzdIItd3d3
+LnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLndlYi1wbGF0Zm9ybS50ZXN0gi14bi0t
+bjhqNmRzNTNsd3drcnFodjI4YS53d3cud2ViLXBsYXRmb3JtLnRlc3SCLXhuLS1u
+OGo2ZHM1M2x3d2tycWh2MjhhLm5vdC13ZWItcGxhdGZvcm0udGVzdIIud3d3MS54
+bi0tbjhqNmRzNTNsd3drcnFodjI4YS53ZWItcGxhdGZvcm0udGVzdIIueG4tLW44
+ajZkczUzbHd3a3JxaHYyOGEud3d3MS53ZWItcGxhdGZvcm0udGVzdIIueG4tLW44
+ajZkczUzbHd3a3JxaHYyOGEud3d3Mi53ZWItcGxhdGZvcm0udGVzdIIud3d3Mi54
+bi0tbjhqNmRzNTNsd3drcnFodjI4YS53ZWItcGxhdGZvcm0udGVzdIIveG4tLWx2
+ZS02bGFkLnhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCMXd3dy54
+bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCMXhu
+LS1uOGo2ZHM1M2x3d2tycWh2MjhhLnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
+Mnd3dzEueG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50
+ZXN0gjJ4bi0tbjhqNmRzNTNsd3drcnFodjI4YS53d3cxLm5vdC13ZWItcGxhdGZv
+cm0udGVzdIIyd3d3Mi54bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBs
+YXRmb3JtLnRlc3SCMnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnd3dzIubm90LXdl
+Yi1wbGF0Zm9ybS50ZXN0gjZ4bi0tbHZlLTZsYWQueG4tLW44ajZkczUzbHd3a3Jx
+aHYyOGEud2ViLXBsYXRmb3JtLnRlc3SCNnhuLS1uOGo2ZHM1M2x3d2tycWh2Mjhh
+LnhuLS1sdmUtNmxhZC53ZWItcGxhdGZvcm0udGVzdII6eG4tLWx2ZS02bGFkLnhu
+LS1uOGo2ZHM1M2x3d2tycWh2MjhhLm5vdC13ZWItcGxhdGZvcm0udGVzdII6eG4t
+LW44ajZkczUzbHd3a3JxaHYyOGEueG4tLWx2ZS02bGFkLm5vdC13ZWItcGxhdGZv
+cm0udGVzdIJBeG4tLW44ajZkczUzbHd3a3JxaHYyOGEueG4tLW44ajZkczUzbHd3
+a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3SCRXhuLS1uOGo2ZHM1M2x3d2tycWh2
+MjhhLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLm5vdC13ZWItcGxhdGZvcm0udGVz
+dDANBgkqhkiG9w0BAQsFAAOCAQEAQTDDNYqMPF1do9cQKIFZx82wqHOPGtE2vkCG
+PGPLHKlBJqAMas+3z3Y/ZPrq5XSbVx2y3ZLO7cEy7GXrfcJzq42VM7Oj0rBtgQ0/
+McOJI0k52m8itR0Sl27MIENayvTVPgG+kAOyTvec4pchOaMzjEWkbOk664ctHTnm
+2LuyFQGkj3AlYU8PXzWNnMb7gTtSFZSQ5O7XO7K3aEVGu1YGf4Nz2agcDRf7zoFd
+HApPDHVoonBkbd6tz6wQ5eUEH+gSjVkn4pp23TCJvC4irJcShqBFni/iP8MK/hRs
+KiimowCB0FPiTWacE57lJQInswVicwhJQ24VdA3t3HFHbHlTHQ==
-----END CERTIFICATE-----
diff --git a/tests/wpt/tests/tools/ci/jobs.py b/tests/wpt/tests/tools/ci/jobs.py
index fe8eaae069e..a831d24bebe 100644
--- a/tests/wpt/tests/tools/ci/jobs.py
+++ b/tests/wpt/tests/tools/ci/jobs.py
@@ -1,8 +1,10 @@
# mypy: allow-untyped-defs
import argparse
+import json
import os
import re
+import sys
from ..wpt.testfiles import branch_point, files_changed
from tools import localpaths # noqa: F401
@@ -138,6 +140,7 @@ def create_parser():
parser.add_argument("revish", default=None, help="Commits to consider. Defaults to the commits on the current branch", nargs="?")
parser.add_argument("--all", help="List all jobs unconditionally.", action="store_true")
parser.add_argument("--includes", default=None, help="Jobs to check for. Return code is 0 if all jobs are found, otherwise 1", nargs="*")
+ parser.add_argument("--json", action="store_true", help="Output jobs as JSON, instead of one per line")
return parser
@@ -145,7 +148,11 @@ def run(**kwargs):
paths = get_paths(**kwargs)
jobs = get_jobs(paths, **kwargs)
if not kwargs["includes"]:
- for item in sorted(jobs):
- print(item)
+ if kwargs["json"]:
+ json.dump(sorted(jobs), sys.stdout, indent=2)
+ sys.stdout.write("\n")
+ else:
+ for item in sorted(jobs):
+ print(item)
else:
return 0 if set(kwargs["includes"]).issubset(jobs) else 1
diff --git a/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/chrome_spki_certs.py b/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/chrome_spki_certs.py
index 08ff16145cc..875ae3ea4a7 100644
--- a/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/chrome_spki_certs.py
+++ b/tests/wpt/tests/tools/wptrunner/wptrunner/browsers/chrome_spki_certs.py
@@ -2,7 +2,7 @@
# DO NOT EDIT MANUALLY.
# tools/certs/web-platform.test.pem
-WPT_FINGERPRINT = 'VoVeIyoD19UQniB0BHgC6THv+UvAkHror0gVsRketZQ='
+WPT_FINGERPRINT = '9cAz+9IkfB5eNjE005taHs+0OZkHahOazSQq3xQqQHo='
# signed-exchange/resources/127.0.0.1.sxg.pem
SXG_WPT_FINGERPRINT = '0Rt4mT6SJXojEMHTnKnlJ/hBKMBcI4kteBlhR1eTTdk='
diff --git a/tests/wpt/tests/tools/wptrunner/wptrunner/executors/executorchrome.py b/tests/wpt/tests/tools/wptrunner/wptrunner/executors/executorchrome.py
index 53c11f133e5..914c5d1c0e3 100644
--- a/tests/wpt/tests/tools/wptrunner/wptrunner/executors/executorchrome.py
+++ b/tests/wpt/tests/tools/wptrunner/wptrunner/executors/executorchrome.py
@@ -80,66 +80,28 @@ class ChromeDriverTestharnessProtocolPart(WebDriverTestharnessProtocolPart):
The main difference from the default WebDriver testharness implementation is
that the test window can be reused between tests for better performance.
"""
-
- def setup(self):
- super().setup()
- # Handle (an alphanumeric string) that may be set if window reuse is
- # enabled. This state allows the protocol to distinguish the test
- # window from other windows a test itself may create that the "Get
- # Window Handles" command also returns.
- #
- # Because test window persistence is a Chrome-only feature, it's not
- # exposed to the base WebDriver testharness executor.
- self.test_window = None
- self.reuse_window = self.parent.reuse_window
-
- def close_test_window(self):
- if self.test_window:
- self._close_window(self.test_window)
- self.test_window = None
-
- def close_old_windows(self):
- self.webdriver.actions.release()
- for handle in self.webdriver.handles:
- if handle not in {self.runner_handle, self.test_window}:
- self._close_window(handle)
- if not self.reuse_window:
- self.close_test_window()
- self.webdriver.window_handle = self.runner_handle
- # TODO(web-platform-tests/wpt#48078): Find a cross-platform way to clear
+ def reset_browser_state(self):
+ # TODO(web-platform-tests/wpt#48078): Find a cross-vendor way to clear
# cookies for all domains.
self.parent.cdp.execute_cdp_command("Network.clearBrowserCookies")
- return self.runner_handle
-
- def open_test_window(self, window_id):
- if self.test_window:
- # Try to reuse the existing test window by emulating the `about:blank`
- # page with no history you would get with a new window.
- try:
- self.webdriver.window_handle = self.test_window
- # Reset navigation history with Chrome DevTools Protocol:
- # https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-resetNavigationHistory
- self.parent.cdp.execute_cdp_command("Page.resetNavigationHistory")
- self.webdriver.url = "about:blank"
- return
- except error.NoSuchWindowException:
- self.test_window = None
- super().open_test_window(window_id)
-
- def get_test_window(self, window_id, parent, timeout=5):
- if self.test_window:
- return self.test_window
- # Poll the handles endpoint for the test window like the base WebDriver
- # protocol part, but don't bother checking for the serialized
- # WindowProxy (not supported by Chrome currently).
- deadline = time.time() + timeout
- while time.time() < deadline:
- self.test_window = self._poll_handles_for_test_window(parent)
- if self.test_window is not None:
- assert self.test_window != parent
- return self.test_window
- time.sleep(0.03)
- raise Exception("unable to find test window")
+ # Reset default permissions that `test_driver.set_permission(...)` may
+ # have altered.
+ self.parent.cdp.execute_cdp_command("Browser.resetPermissions")
+ # Chromium requires the `background-sync` permission for reporting APIs
+ # to work. Not all embedders (notably, `chrome --headless=old`) grant
+ # `background-sync` by default, so this CDP call ensures the permission
+ # is granted for all origins, in line with the background sync spec's
+ # recommendation [0].
+ #
+ # WebDriver's "Set Permission" command can only act on the test's
+ # origin, which may be too limited.
+ #
+ # [0]: https://wicg.github.io/background-sync/spec/#permission
+ params = {
+ "permission": {"name": "background-sync"},
+ "setting": "granted",
+ }
+ self.parent.cdp.execute_cdp_command("Browser.setPermission", params)
class ChromeDriverFedCMProtocolPart(WebDriverFedCMProtocolPart):
@@ -177,7 +139,6 @@ class ChromeDriverProtocol(WebDriverProtocol):
if base_part.name not in {part.name for part in implements}:
implements.append(base_part)
- reuse_window = False
# Prefix to apply to vendor-specific WebDriver extension commands.
vendor_prefix = "goog"
@@ -225,25 +186,24 @@ class ChromeDriverTestharnessExecutor(WebDriverTestharnessExecutor, _SanitizerMi
def __init__(self, *args, reuse_window=False, **kwargs):
super().__init__(*args, **kwargs)
- self.protocol.reuse_window = reuse_window
+ self.reuse_window = reuse_window
- def setup(self, runner, protocol=None):
- super().setup(runner, protocol)
- # Chromium requires the `background-sync` permission for reporting APIs
- # to work. Not all embedders (notably, `chrome --headless=old`) grant
- # `background-sync` by default, so this CDP call ensures the permission
- # is granted for all origins, in line with the background sync spec's
- # recommendation [0].
- #
- # WebDriver's "Set Permission" command can only act on the test's
- # origin, which may be too limited.
- #
- # [0]: https://wicg.github.io/background-sync/spec/#permission
- params = {
- "permission": {"name": "background-sync"},
- "setting": "granted",
- }
- self.protocol.cdp.execute_cdp_command("Browser.setPermission", params)
+ def get_or_create_test_window(self, protocol):
+ test_window = self.protocol.testharness.persistent_test_window
+ if test_window:
+ try:
+ # Mimic the "new window" WebDriver command by loading `about:blank`
+ # with no other browsing history.
+ protocol.base.set_window(test_window)
+ protocol.base.load("about:blank")
+ protocol.cdp.execute_cdp_command("Page.resetNavigationHistory")
+ except error.NoSuchWindowException:
+ test_window = self.protocol.testharness.persistent_test_window = None
+ if not test_window:
+ test_window = super().get_or_create_test_window(protocol)
+ if self.reuse_window:
+ self.protocol.testharness.persistent_test_window = test_window
+ return test_window
def _get_next_message_classic(self, protocol, url, test_window):
try:
diff --git a/tests/wpt/tests/tools/wptrunner/wptrunner/executors/executoredge.py b/tests/wpt/tests/tools/wptrunner/wptrunner/executors/executoredge.py
index 75a3313c55c..95b40bd8db1 100644
--- a/tests/wpt/tests/tools/wptrunner/wptrunner/executors/executoredge.py
+++ b/tests/wpt/tests/tools/wptrunner/wptrunner/executors/executoredge.py
@@ -30,10 +30,6 @@ class EdgeDriverRefTestExecutor(WebDriverRefTestExecutor, _SanitizerMixin): # t
class EdgeDriverTestharnessExecutor(WebDriverTestharnessExecutor, _SanitizerMixin): # type: ignore
protocol_cls = EdgeDriverProtocol
- def __init__(self, *args, reuse_window=False, **kwargs):
- super().__init__(*args, **kwargs)
- self.protocol.reuse_window = reuse_window
-
class EdgeDriverPrintRefTestExecutor(EdgeDriverRefTestExecutor):
protocol_cls = EdgeDriverProtocol
diff --git a/tests/wpt/tests/tools/wptrunner/wptrunner/executors/executorwebdriver.py b/tests/wpt/tests/tools/wptrunner/wptrunner/executors/executorwebdriver.py
index 3c1bdfd7a72..f04d615ee11 100644
--- a/tests/wpt/tests/tools/wptrunner/wptrunner/executors/executorwebdriver.py
+++ b/tests/wpt/tests/tools/wptrunner/wptrunner/executors/executorwebdriver.py
@@ -5,9 +5,7 @@ import json
import os
import socket
import threading
-import time
import traceback
-import uuid
from urllib.parse import urljoin
from .base import (AsyncCallbackHandler,
@@ -82,6 +80,9 @@ class WebDriverBaseProtocolPart(BaseProtocolPart):
body = {"type": "script", "ms": timeout * 1000}
self.webdriver.send_session_command("POST", "timeouts", body)
+ def create_window(self, type="tab", **kwargs):
+ return self.webdriver.new_window(type_hint=type)
+
@property
def current_window(self):
return self.webdriver.window_handle
@@ -226,10 +227,9 @@ class WebDriverTestharnessProtocolPart(TestharnessProtocolPart):
def setup(self):
self.webdriver = self.parent.webdriver
self.runner_handle = None
+ self.persistent_test_window = None
with open(os.path.join(here, "runner.js")) as f:
self.runner_script = f.read()
- with open(os.path.join(here, "window-loaded.js")) as f:
- self.window_loaded_script = f.read()
def load_runner(self, url_protocol):
if self.runner_handle:
@@ -245,10 +245,11 @@ class WebDriverTestharnessProtocolPart(TestharnessProtocolPart):
def close_old_windows(self):
self.webdriver.actions.release()
- handles = [item for item in self.webdriver.handles if item != self.runner_handle]
- for handle in handles:
- self._close_window(handle)
+ for handle in self.webdriver.handles:
+ if handle not in {self.runner_handle, self.persistent_test_window}:
+ self._close_window(handle)
self.webdriver.window_handle = self.runner_handle
+ self.reset_browser_state()
return self.runner_handle
def _close_window(self, window_handle):
@@ -258,65 +259,8 @@ class WebDriverTestharnessProtocolPart(TestharnessProtocolPart):
except webdriver_error.NoSuchWindowException:
pass
- def open_test_window(self, window_id):
- self.webdriver.execute_script(
- "window.open('about:blank', '%s', 'noopener')" % window_id)
-
- def get_test_window(self, window_id, parent, timeout=5):
- """Find the test window amongst all the open windows.
- This is assumed to be either the named window or the one after the parent in the list of
- window handles
-
- :param window_id: The DOM name of the Window
- :param parent: The handle of the runner window
- :param timeout: The time in seconds to wait for the window to appear. This is because in
- some implementations there's a race between calling window.open and the
- window being added to the list of WebDriver accessible windows."""
- test_window = None
- end_time = time.time() + timeout
- while time.time() < end_time:
- try:
- # Try using the JSON serialization of the WindowProxy object,
- # it's in Level 1 but nothing supports it yet
- win_s = self.webdriver.execute_script("return window['%s'];" % window_id)
- win_obj = json.loads(win_s)
- test_window = win_obj["window-fcc6-11e5-b4f8-330a88ab9d7f"]
- except Exception:
- pass
-
- if test_window is None:
- test_window = self._poll_handles_for_test_window(parent)
-
- if test_window is not None:
- assert test_window != parent
- return test_window
-
- time.sleep(0.1)
-
- raise Exception("unable to find test window")
-
- def _poll_handles_for_test_window(self, parent):
- test_window = None
- after = self.webdriver.handles
- if len(after) == 2:
- test_window = next(iter(set(after) - {parent}))
- elif after[0] == parent and len(after) > 2:
- # Hope the first one here is the test window
- test_window = after[1]
- return test_window
-
- def test_window_loaded(self):
- """Wait until the page in the new window has been loaded.
-
- Hereby ignore Javascript execptions that are thrown when
- the document has been unloaded due to a process change.
- """
- while True:
- try:
- self.webdriver.execute_script(self.window_loaded_script, asynchronous=True)
- break
- except webdriver_error.JavascriptErrorException:
- pass
+ def reset_browser_state(self):
+ """Reset browser-wide state that normally persists between tests."""
class WebDriverPrintProtocolPart(PrintProtocolPart):
@@ -828,7 +772,6 @@ class WebDriverTestharnessExecutor(TestharnessExecutor):
self._get_next_message = self._get_next_message_classic
self.close_after_done = close_after_done
- self.window_id = str(uuid.uuid4())
self.cleanup_after_test = cleanup_after_test
def is_alive(self):
@@ -857,7 +800,7 @@ class WebDriverTestharnessExecutor(TestharnessExecutor):
def do_testharness(self, protocol, url, timeout):
# The previous test may not have closed its old windows (if something
# went wrong or if cleanup_after_test was False), so clean up here.
- parent_window = protocol.testharness.close_old_windows()
+ protocol.testharness.close_old_windows()
# If protocol implements `bidi_events`, remove all the existing subscriptions.
if hasattr(protocol, 'bidi_events'):
@@ -865,12 +808,8 @@ class WebDriverTestharnessExecutor(TestharnessExecutor):
protocol.loop.run_until_complete(protocol.bidi_events.unsubscribe_all())
# Now start the test harness
- protocol.testharness.open_test_window(self.window_id)
- test_window = protocol.testharness.get_test_window(self.window_id,
- parent_window,
- timeout=5*self.timeout_multiplier)
+ test_window = self.get_or_create_test_window(protocol)
self.protocol.base.set_window(test_window)
-
# Wait until about:blank has been loaded
protocol.base.execute_script(self.window_loaded_script, asynchronous=True)
@@ -975,6 +914,9 @@ class WebDriverTestharnessExecutor(TestharnessExecutor):
return rv, extra
+ def get_or_create_test_window(self, protocol):
+ return protocol.base.create_window()
+
def _get_next_message_classic(self, protocol, url, _):
"""
Get the next message from the test_driver using the classic WebDriver async script execution. This will block
diff --git a/tests/wpt/tests/tools/wptrunner/wptrunner/executors/protocol.py b/tests/wpt/tests/tools/wptrunner/wptrunner/executors/protocol.py
index 75edc146767..5b59482d9bd 100644
--- a/tests/wpt/tests/tools/wptrunner/wptrunner/executors/protocol.py
+++ b/tests/wpt/tests/tools/wptrunner/wptrunner/executors/protocol.py
@@ -215,6 +215,7 @@ class TestharnessProtocolPart(ProtocolPart):
contains the initial runner page.
:param str url_protocol: "https" or "http" depending on the test metadata.
+ :returns: A browser-specific handle to the runner page.
"""
pass
diff --git a/tests/wpt/tests/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.html b/tests/wpt/tests/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.html
index e4fec3a8a70..af1f982e5a1 100644
--- a/tests/wpt/tests/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.html
+++ b/tests/wpt/tests/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.html
@@ -126,9 +126,17 @@
assert_equals(d.nextSibling, null);
}, "`insertAdjacentHTML(null)` throws.");
+ // Due to a Gecko-specific bug
+ // (https://bugzilla.mozilla.org/show_bug.cgi?id=1270944), adjacent nodes are
+ // merged. Remove the children, to let the test pass on Gecko
+ // too.
+ function removeChildrenBecauseOfGeckoBug(element) {
+ element.innerHTML = null;
+ }
+
// After default policy creation string assignment implicitly calls createHTML.
test(t => {
- let p = window.trustedTypes.createPolicy("default", { createHTML: createHTMLJS }, true);
+ let p = window.trustedTypes.createPolicy("default", { createHTML: createHTMLJS });
var d = document.createElement('div');
container.appendChild(d);
@@ -141,6 +149,8 @@
assert_equals(d.firstChild.nodeType, Node.TEXT_NODE);
assert_equals(d.firstChild.data, RESULTS.HTML);
+ removeChildrenBecauseOfGeckoBug(d);
+
d.insertAdjacentHTML('beforeend', INPUTS.HTML);
assert_equals(d.lastChild.nodeType, Node.TEXT_NODE);
assert_equals(d.lastChild.data, RESULTS.HTML);
@@ -166,6 +176,8 @@
assert_equals(d.firstChild.nodeType, Node.TEXT_NODE);
assert_equals(d.firstChild.data, "null");
+ removeChildrenBecauseOfGeckoBug(d);
+
d.insertAdjacentHTML('beforeend', null);
assert_equals(d.lastChild.nodeType, Node.TEXT_NODE);
assert_equals(d.lastChild.data, "null");
diff --git a/tests/wpt/tests/trusted-types/support/navigation-report-only-support.html b/tests/wpt/tests/trusted-types/support/navigation-report-only-support.html
index a16995ba903..791559f7a19 100644
--- a/tests/wpt/tests/trusted-types/support/navigation-report-only-support.html
+++ b/tests/wpt/tests/trusted-types/support/navigation-report-only-support.html
@@ -1,53 +1,14 @@
<!DOCTYPE html>
<head>
+ <script src="navigation-support.js"></script>
</head>
<body>
<p>Support page for trusted-types-navigation-report-only.*.html tests.</p>
<a id="anchor" href="#">link</a>
+<form>
+ <input id="submit" type="submit">
+</form>
<script>
- const params = new URLSearchParams(location.search);
- if (!!params.get("defaultpolicy")) {
- trustedTypes.createPolicy("default", {
- createScript: s => s.replace("continue", "defaultpolicywashere"),
- });
- }
-
- function bounceEventToOpener(e) {
- const msg = {};
- for (const field of ["effectiveDirective", "sample", "type"]) {
- msg[field] = e[field];
- }
- msg["uri"] = location.href;
- window.opener.postMessage(msg, "*");
- }
-
- // If a navigation is blocked by Trusted Types, we expect this window to
- // throw a SecurityPolicyViolationEvent. If it's not blocked, we expect the
- // loaded frame to through DOMContentLoaded. In either case there should be
- // _some_ event that we can expect.
- document.addEventListener("DOMContentLoaded", bounceEventToOpener);
- document.addEventListener("securitypolicyviolation", bounceEventToOpener);
-
- // Navigate to the non-report-only version of the test. That has the same
- // event listening setup as this, but is a different target URI.
- const target_script = `location.href='${location.href.replace("-report-only", "") + "#continue"}';`;
- const target = `javascript:${target_script}`;
-
- // Navigate the anchor, but only after the content is loaded (so that we
- // won't disturb delivery of that event to the opener.
- const anchor = document.getElementById("anchor");
- anchor.href = target;
-
- if (!!params.get("frame")) {
- const frame = document.createElement("iframe");
- frame.src = "frame-without-trusted-types.html";
- frames.name = "frame";
- document.body.appendChild(frame);
- anchor.target = "frame";
- }
-
- if (!location.hash) {
- document.addEventListener("DOMContentLoaded", _ => anchor.click());
- }
+ navigateToJavascriptURL(/* aReportOnly */ true);
</script>
</body>
diff --git a/tests/wpt/tests/trusted-types/support/navigation-support.html b/tests/wpt/tests/trusted-types/support/navigation-support.html
index c2c8a82f514..47f33c9fb64 100644
--- a/tests/wpt/tests/trusted-types/support/navigation-support.html
+++ b/tests/wpt/tests/trusted-types/support/navigation-support.html
@@ -1,51 +1,14 @@
<!DOCTYPE html>
<head>
+ <script src="navigation-support.js"></script>
</head>
<body>
<p>Support page for trusted-types-navigation.*.html tests.</p>
<a id="anchor" href="#">link</a>
+<form>
+ <input id="submit" type="submit">
+</form>
<script>
- const params = new URLSearchParams(location.search);
- if (!!params.get("defaultpolicy")) {
- trustedTypes.createPolicy("default", {
- createScript: s => s.replace("continue", "defaultpolicywashere"),
- });
- }
-
- function bounceEventToOpener(e) {
- const msg = {};
- for (const field of ["effectiveDirective", "sample", "type"]) {
- msg[field] = e[field];
- }
- msg["uri"] = location.href;
- window.opener.postMessage(msg, "*");
- }
-
- // If a navigation is blocked by Trusted Types, we expect this window to
- // throw a SecurityPolicyViolationEvent. If it's not blocked, we expect the
- // loaded frame to through DOMContentLoaded. In either case there should be
- // _some_ event that we can expect.
- document.addEventListener("DOMContentLoaded", bounceEventToOpener);
- document.addEventListener("securitypolicyviolation", bounceEventToOpener);
-
- // We'll use a javascript:-url to navigate to ourselves, so that we can
- // re-use the messageing mechanisms above. In order to not end up in a loop,
- // we'll only click if we don't find fragment in the current URL.
- const target_script = `location.href='${location.href}&continue';`;
- const target = `javascript:${target_script}`;
-
- const anchor = document.getElementById("anchor");
- anchor.href = target;
-
- if (!!params.get("frame")) {
- const frame = document.createElement("iframe");
- frame.src = "frame-without-trusted-types.html";
- frames.name = "frame";
- document.body.appendChild(frame);
- anchor.target = "frame";
- }
-
- if (!location.hash)
- document.addEventListener("DOMContentLoaded", _ => anchor.click());
+ navigateToJavascriptURL(/* aReportOnly */ false);
</script>
</body>
diff --git a/tests/wpt/tests/trusted-types/support/navigation-support.js b/tests/wpt/tests/trusted-types/support/navigation-support.js
new file mode 100644
index 00000000000..41dce761def
--- /dev/null
+++ b/tests/wpt/tests/trusted-types/support/navigation-support.js
@@ -0,0 +1,75 @@
+const kNavigationAttempted = "navigationattempted=1";
+
+function navigateToJavascriptURL(reportOnly) {
+ let params = new URLSearchParams(location.search);
+
+ if (!!params.get("defaultpolicy")) {
+ trustedTypes.createPolicy("default", {
+ createScript: s => {
+ return s.replace("continue", "defaultpolicywashere")
+ },
+ });
+ }
+
+ function bounceEventToOpener(e) {
+ const msg = {};
+ for (const field of ["effectiveDirective", "sample", "type"]) {
+ msg[field] = e[field];
+ }
+
+ msg["uri"] = location.href;
+ window.opener.postMessage(msg, "*");
+ }
+
+ // If a navigation is blocked by Trusted Types, we expect this window to
+ // throw a SecurityPolicyViolationEvent. If it's not blocked, we expect the
+ // loaded frame to through DOMContentLoaded. In either case there should be
+ // _some_ event that we can expect.
+ document.addEventListener("DOMContentLoaded", bounceEventToOpener);
+ document.addEventListener("securitypolicyviolation", bounceEventToOpener);
+
+ let target_script;
+ if (reportOnly) {
+ // Navigate to the non-report-only version of the test. That has the same
+ // event listening setup as this, but is a different target URI.
+ target_script = `location.href='${location.href.replace("-report-only", "") +
+ (location.href.endsWith(".html") ? "?" : "&") + kNavigationAttempted + "&continue"}';`;
+ } else {
+ // We'll use a javascript:-url to navigate to ourselves, so that we can
+ // re-use the messageing mechanisms above.
+ target_script = `location.href='${location.href + "&" + kNavigationAttempted}&continue';`;
+ }
+
+ function getAndPreparareNavigationElement(javaScriptURL) {
+ let target = "_self";
+ if (!!params.get("frame")) {
+ const frame = document.createElement("iframe");
+ frame.src = "frame-without-trusted-types.html";
+ frames.name = "frame";
+ document.body.appendChild(frame);
+ target = "frame";
+ }
+
+ if (!!params.get("form-submission")) {
+ const submit = document.getElementById("submit");
+
+ // Careful, the IDL attributes are defined in camel-case.
+ submit.formAction = javaScriptURL;
+ submit.formTarget = target;
+
+ return submit;
+ }
+
+ const anchor = document.getElementById("anchor");
+ anchor.href = javaScriptURL;
+ anchor.target = target;
+ return anchor;
+ }
+
+ const navigationElement = getAndPreparareNavigationElement(`javascript:${target_script}`);
+
+ // Prevent loops.
+ if (!location.search.includes(kNavigationAttempted)) {
+ document.addEventListener("DOMContentLoaded", _ => navigationElement.click());
+ }
+}
diff --git a/tests/wpt/tests/trusted-types/trusted-types-navigation.html b/tests/wpt/tests/trusted-types/trusted-types-navigation.html
index 2113711902a..74a25fa3480 100644
--- a/tests/wpt/tests/trusted-types/trusted-types-navigation.html
+++ b/tests/wpt/tests/trusted-types/trusted-types-navigation.html
@@ -2,25 +2,48 @@
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
+ <script src="support/navigation-support.js"></script>
</head>
<body>
<script>
+ "use strict";
+
function expectMessage(filter) {
return new Promise(resolve => {
- window.addEventListener("message", e => { if (filter(e)) resolve(); });
+
+ function listener(e) {
+ if (filter(e)) {
+ window.removeEventListener("message", listener);
+ resolve();
+ }
+ }
+ window.addEventListener("message", listener);
});
}
function expectViolationAsMessage(sample) {
- const filter = e => ((e.data.effectiveDirective == "require-trusted-types-for" ||
- e.data.effectiveDirective == "trusted-types") &&
+ const filter = e => {
+ const result = (e.data.effectiveDirective == "require-trusted-types-for" &&
(!sample || e.data.sample.startsWith(sample)));
+ if (result) {
+ assert_true(true, "Expected violation as message: " + sample);
+ }
+
+ return result;
+ }
return new expectMessage(filter);
}
function expectLoadedAsMessage(uri) {
- const filter = e => (e.data.type == "DOMContentLoaded" &&
+ const filter = e => {
+ const result = (e.data.type == "DOMContentLoaded" &&
(!uri || e.data.uri.endsWith(uri)));
+ if (result) {
+ assert_true(true, "Expected loaded as message: " + uri);
+ }
+
+ return result;
+ }
return new expectMessage(filter);
}
@@ -29,72 +52,116 @@
test.add_cleanup(_ => win.close());
}
- promise_test(t => {
- openWindow(t, "support/navigation-support.html");
- return Promise.all([
- expectLoadedAsMessage("navigation-support.html"),
- expectViolationAsMessage("Location href"),
- ]);
- }, "Navigate a window with javascript:-urls in enforcing mode.");
-
- promise_test(t => {
- openWindow(t, "support/navigation-support.html?defaultpolicy=1");
- return Promise.all([
- expectLoadedAsMessage("navigation-support.html?defaultpolicy=1"),
- expectLoadedAsMessage("navigation-support.html?defaultpolicy=1&defaultpolicywashere"),
- ]);
- }, "Navigate a window with javascript:-urls w/ default policy in enforcing mode.");
-
- promise_test(t => {
- const page = "navigation-report-only-support.html"
- openWindow(t, `support/${page}`);
- return Promise.all([
- expectLoadedAsMessage(page),
- expectLoadedAsMessage("navigation-support.html#continue"),
- ]);
- }, "Navigate a window with javascript:-urls in report-only mode.");
-
- promise_test(t => {
- const page = "navigation-report-only-support.html?defaultpolicy=1";
- openWindow(t, `support/${page}`);
- return Promise.all([
- expectLoadedAsMessage(page),
- expectLoadedAsMessage("navigation-support.html?defaultpolicy=1#defaultpolicywashere"),
- ]);
- }, "Navigate a window with javascript:-urls w/ default policy in report-only mode.");
-
- promise_test(t => {
- openWindow(t, "support/navigation-support.html?frame=1");
- return Promise.all([
- expectLoadedAsMessage("navigation-support.html?frame=1"),
- expectViolationAsMessage("Location href"),
- ]);
- }, "Navigate a frame with javascript:-urls in enforcing mode.");
-
- promise_test(t => {
- openWindow(t, "support/navigation-support.html?defaultpolicy=1&frame=1");
- return Promise.all([
- expectLoadedAsMessage("navigation-support.html?defaultpolicy=1&frame=1"),
- expectLoadedAsMessage("navigation-support.html?defaultpolicy=1&frame=1&defaultpolicywashere"),
- ]);
- }, "Navigate a frame with javascript:-urls w/ default policy in enforcing mode.");
-
- promise_test(t => {
- const page = "navigation-report-only-support.html?frame=1"
- openWindow(t, `support/${page}`);
- return Promise.all([
- expectLoadedAsMessage(page),
- expectLoadedAsMessage("navigation-support.html?frame=1#continue"),
- ]);
- }, "Navigate a frame with javascript:-urls in report-only mode.");
-
- promise_test(t => {
- const page = "navigation-report-only-support.html?defaultpolicy=1&frame=1";
- openWindow(t, `support/${page}`);
- return Promise.all([
- expectLoadedAsMessage(page),
- expectLoadedAsMessage("navigation-support.html?defaultpolicy=1&frame=1#defaultpolicywashere"),
- ]);
- }, "Navigate a frame with javascript:-urls w/ default policy in report-only mode.");
+ const kFormSubmission = "form-submission";
+ // When adding more elements, adapt all functions consuming the existing elements.
+ const kNavigationElements =
+ [
+ "anchor",
+ kFormSubmission,
+ ];
+
+ function maybeAddFormSubmissionToSearchParams(navigationElement, searchParams) {
+ return (navigationElement == kFormSubmission) ?
+ [kFormSubmission + "=1", ...searchParams] : searchParams;
+ }
+
+ function joinToHref(searchParams, originAndPathName) {
+ if (searchParams.length > 0) {
+ return originAndPathName + "?" + searchParams.join("&");
+ }
+
+ return originAndPathName;
+ }
+
+ for (const navigationElement of kNavigationElements) {
+ promise_test(t => {
+ const page = joinToHref(maybeAddFormSubmissionToSearchParams(navigationElement, []),
+ "navigation-support.html");
+ openWindow(t, `support/${page}`);
+ return Promise.all([
+ expectLoadedAsMessage(page),
+ expectViolationAsMessage("Location href"),
+ ]);
+ }, `Navigate a window via ${navigationElement} with javascript:-urls in enforcing mode.`);
+
+ promise_test(t => {
+ const page = joinToHref(maybeAddFormSubmissionToSearchParams(navigationElement, ["defaultpolicy=1"]),
+ "navigation-support.html");
+ openWindow(t, `support/${page}`);
+ return Promise.all([
+ expectLoadedAsMessage(page),
+ expectLoadedAsMessage(page + "&" + kNavigationAttempted + "&defaultpolicywashere"),
+ ]);
+ }, `Navigate a window via ${navigationElement} with javascript:-urls w/ default policy in enforcing mode.`);
+
+ promise_test(t => {
+ const page = joinToHref(maybeAddFormSubmissionToSearchParams(navigationElement, []),
+ "navigation-report-only-support.html");
+ openWindow(t, `support/${page}`);
+ return Promise.all([
+ expectLoadedAsMessage(page),
+ expectLoadedAsMessage(joinToHref(maybeAddFormSubmissionToSearchParams(navigationElement,
+ [kNavigationAttempted, "continue"]), "navigation-support.html")),
+ ]);
+ }, `Navigate a window via ${navigationElement} with javascript:-urls in report-only mode.`);
+
+ promise_test(t => {
+ const page = joinToHref(maybeAddFormSubmissionToSearchParams(navigationElement, ["defaultpolicy=1"]),
+ "navigation-report-only-support.html");
+ openWindow(t, `support/${page}`);
+ return Promise.all([
+ expectLoadedAsMessage(page),
+ expectLoadedAsMessage(joinToHref(maybeAddFormSubmissionToSearchParams(navigationElement,
+ ["defaultpolicy=1", kNavigationAttempted, "defaultpolicywashere"]),
+ "navigation-support.html")),
+ ]);
+ }, `Navigate a window via ${navigationElement} with javascript:-urls w/ default policy in report-only mode.`);
+
+ promise_test(t => {
+ const page = joinToHref(maybeAddFormSubmissionToSearchParams(navigationElement, ["frame=1"]),
+ "navigation-support.html");
+ openWindow(t, `support/${page}`);
+ return Promise.all([
+ expectLoadedAsMessage(page),
+ expectViolationAsMessage("Location href"),
+ ]);
+ }, `Navigate a frame via ${navigationElement} with javascript:-urls in enforcing mode.`);
+
+ promise_test(t => {
+ const page = joinToHref(maybeAddFormSubmissionToSearchParams(navigationElement,
+ ["defaultpolicy=1", "frame=1"]),
+ "navigation-support.html");
+ openWindow(t, `support/${page}`);
+ return Promise.all([
+ expectLoadedAsMessage(page),
+ expectLoadedAsMessage(page + "&" + kNavigationAttempted + "&defaultpolicywashere"),
+ ]);
+ }, `Navigate a frame via ${navigationElement} with javascript:-urls w/ default policy in enforcing mode.`);
+
+ promise_test(t => {
+ const page = joinToHref(maybeAddFormSubmissionToSearchParams(navigationElement, ["frame=1"]),
+ "navigation-report-only-support.html");
+ openWindow(t, `support/${page}`);
+ return Promise.all([
+ expectLoadedAsMessage(page),
+ expectLoadedAsMessage(joinToHref(maybeAddFormSubmissionToSearchParams(navigationElement,
+ ["frame=1", kNavigationAttempted, "continue"]),
+ "navigation-support.html")),
+ ]);
+ }, `Navigate a frame via ${navigationElement} with javascript:-urls in report-only mode.`);
+
+ promise_test(t => {
+ const page = joinToHref(maybeAddFormSubmissionToSearchParams(navigationElement,
+ ["defaultpolicy=1", "frame=1"]),
+ "navigation-report-only-support.html");
+ openWindow(t, `support/${page}`);
+ return Promise.all([
+ expectLoadedAsMessage(page),
+ expectLoadedAsMessage(joinToHref(maybeAddFormSubmissionToSearchParams(navigationElement,
+ ["defaultpolicy=1", "frame=1", kNavigationAttempted, "defaultpolicywashere"]),
+ "navigation-support.html")),
+ ]);
+ }, `Navigate a frame via ${navigationElement} with javascript:-urls w/ default policy in report-only mode.`);
+ }
</script>
</body>
diff --git a/tests/wpt/tests/url/resources/urltestdata.json b/tests/wpt/tests/url/resources/urltestdata.json
index 9dbe5456a96..0ebaf4cd4c4 100644
--- a/tests/wpt/tests/url/resources/urltestdata.json
+++ b/tests/wpt/tests/url/resources/urltestdata.json
@@ -9992,5 +9992,101 @@
"pathname": "/",
"search": "",
"hash": ""
+ },
+ "# Non-special URL and backslashes",
+ {
+ "input": "non-special:\\\\opaque",
+ "base": null,
+ "href": "non-special:\\\\opaque",
+ "origin": "null",
+ "protocol": "non-special:",
+ "username": "",
+ "password": "",
+ "host": "",
+ "hostname": "",
+ "port": "",
+ "pathname": "\\\\opaque",
+ "search": "",
+ "hash": ""
+ },
+ {
+ "input": "non-special:\\\\opaque/path",
+ "base": null,
+ "href": "non-special:\\\\opaque/path",
+ "origin": "null",
+ "protocol": "non-special:",
+ "username": "",
+ "password": "",
+ "host": "",
+ "hostname": "",
+ "port": "",
+ "pathname": "\\\\opaque/path",
+ "search": "",
+ "hash": ""
+ },
+ {
+ "input": "non-special:\\\\opaque\\path",
+ "base": null,
+ "href": "non-special:\\\\opaque\\path",
+ "origin": "null",
+ "protocol": "non-special:",
+ "username": "",
+ "password": "",
+ "host": "",
+ "hostname": "",
+ "port": "",
+ "pathname": "\\\\opaque\\path",
+ "search": "",
+ "hash": ""
+ },
+ {
+ "input": "non-special:\\/opaque",
+ "base": null,
+ "href": "non-special:\\/opaque",
+ "origin": "null",
+ "protocol": "non-special:",
+ "username": "",
+ "password": "",
+ "host": "",
+ "hostname": "",
+ "port": "",
+ "pathname": "\\/opaque",
+ "search": "",
+ "hash": ""
+ },
+ {
+ "input": "non-special:/\\path",
+ "base": null,
+ "href": "non-special:/\\path",
+ "origin": "null",
+ "protocol": "non-special:",
+ "username": "",
+ "password": "",
+ "host": "",
+ "hostname": "",
+ "port": "",
+ "pathname": "/\\path",
+ "search": "",
+ "hash": ""
+ },
+ {
+ "input": "non-special://host\\a",
+ "base": null,
+ "failure": true
+ },
+ {
+ "input": "non-special://host/a\\b",
+ "base": null,
+ "href": "non-special://host/a\\b",
+ "origin": "null",
+ "protocol": "non-special:",
+ "username": "",
+ "password": "",
+ "host": "host",
+ "hostname": "host",
+ "port": "",
+ "pathname": "/a\\b",
+ "search": "",
+ "hash": ""
}
]
diff --git a/tests/wpt/tests/wasm/jsapi/jspi/README.txt b/tests/wpt/tests/wasm/jsapi/jspi/README.txt
new file mode 100644
index 00000000000..c65b9893c6f
--- /dev/null
+++ b/tests/wpt/tests/wasm/jsapi/jspi/README.txt
@@ -0,0 +1,3 @@
+This suite tests JSPI.
+
+The tests are based on wasm spec tests.
diff --git a/tests/wpt/tests/wasm/jsapi/jspi/js-promise-integration.any.js b/tests/wpt/tests/wasm/jsapi/jspi/js-promise-integration.any.js
new file mode 100644
index 00000000000..19de3146f92
--- /dev/null
+++ b/tests/wpt/tests/wasm/jsapi/jspi/js-promise-integration.any.js
@@ -0,0 +1,372 @@
+// META: global=window,dedicatedworker,jsshell
+// META: script=/wasm/jsapi/wasm-module-builder.js
+
+// Test for invalid wrappers
+test(() => {
+ assert_throws_js(TypeError, () => WebAssembly.promising({}),
+ "Argument 0 must be a function");
+ assert_throws_js(TypeError, () => WebAssembly.promising(() => {}),
+ "Argument 0 must be a WebAssembly exported function");
+ assert_throws_js(TypeError, () => WebAssembly.Suspending(() => {}),
+ "WebAssembly.Suspending must be invoked with 'new'");
+ assert_throws_js(TypeError, () => new WebAssembly.Suspending({}),
+ "Argument 0 must be a function");
+
+ function asmModule() {
+ "use asm";
+
+ function x(v) {
+ v = v | 0;
+ }
+ return x;
+ }
+ assert_throws_js(TypeError, () => WebAssembly.promising(asmModule()),
+ "Argument 0 must be a WebAssembly exported function");
+},"Valid use of API");
+
+test(() => {
+ let builder = new WasmModuleBuilder();
+ builder.addGlobal(kWasmI32, true).exportAs('g');
+ builder.addFunction("test", kSig_i_v)
+ .addBody([
+ kExprI32Const, 42,
+ kExprGlobalSet, 0,
+ kExprI32Const, 0
+ ]).exportFunc();
+ let instance = builder.instantiate();
+ let wrapper = WebAssembly.promising(instance.exports.test);
+ wrapper();
+ assert_equals(42, instance.exports.g.value);
+},"Promising function always entered");
+
+promise_test(async () => {
+ let builder = new WasmModuleBuilder();
+ let import_index = builder.addImport('m', 'import', kSig_i_v);
+ builder.addFunction("test", kSig_i_i)
+ .addBody([
+ kExprCallFunction, import_index, // suspend
+ ]).exportFunc();
+ let js_import = () => 42;
+ let instance = builder.instantiate({
+ m: {
+ import: js_import
+ }
+ });
+ let wrapped_export = WebAssembly.promising(instance.exports.test);
+ let export_promise = wrapped_export();
+ assert_true(export_promise instanceof Promise);
+ assert_equals(await export_promise, 42);
+}, "Always get a Promise");
+
+promise_test(async () => {
+ let builder = new WasmModuleBuilder();
+ let import_index = builder.addImport('m', 'import', kSig_i_i);
+ builder.addFunction("test", kSig_i_i)
+ .addBody([
+ kExprLocalGet, 0,
+ kExprCallFunction, import_index, // suspend
+ ]).exportFunc();
+ let js_import = new WebAssembly.Suspending(() => Promise.resolve(42));
+ let instance = builder.instantiate({
+ m: {
+ import: js_import
+ }
+ });
+ let wrapped_export = WebAssembly.promising(instance.exports.test);
+ let export_promise = wrapped_export();
+ assert_true(export_promise instanceof Promise);
+ assert_equals(await export_promise, 42);
+}, "Suspend once");
+
+promise_test(async () => {
+ let builder = new WasmModuleBuilder();
+ builder.addGlobal(kWasmI32, true).exportAs('g');
+ let import_index = builder.addImport('m', 'import', kSig_i_v);
+ // void test() {
+ // for (i = 0; i < 5; ++i) {
+ // g = g + await import();
+ // }
+ // }
+ builder.addFunction("test", kSig_v_i)
+ .addLocals({
+ i32_count: 1
+ })
+ .addBody([
+ kExprI32Const, 5,
+ kExprLocalSet, 1,
+ kExprLoop, kWasmStmt,
+ kExprCallFunction, import_index, // suspend
+ kExprGlobalGet, 0,
+ kExprI32Add,
+ kExprGlobalSet, 0,
+ kExprLocalGet, 1,
+ kExprI32Const, 1,
+ kExprI32Sub,
+ kExprLocalTee, 1,
+ kExprBrIf, 0,
+ kExprEnd,
+ ]).exportFunc();
+ let i = 0;
+
+ function js_import() {
+ return Promise.resolve(++i);
+ };
+ let wasm_js_import = new WebAssembly.Suspending(js_import);
+ let instance = builder.instantiate({
+ m: {
+ import: wasm_js_import
+ }
+ });
+ let wrapped_export = WebAssembly.promising(instance.exports.test);
+ let export_promise = wrapped_export();
+ assert_equals(instance.exports.g.value, 0);
+ assert_true(export_promise instanceof Promise);
+ await export_promise;
+ assert_equals(instance.exports.g.value, 15);
+}, "Suspend/resume in a loop");
+
+promise_test(async () => {
+ let builder = new WasmModuleBuilder();
+ let import_index = builder.addImport('m', 'import', kSig_i_v);
+ builder.addFunction("test", kSig_i_v)
+ .addBody([
+ kExprCallFunction, import_index, // suspend
+ ]).exportFunc();
+ let js_import = new WebAssembly.Suspending(() => Promise.resolve(42));
+ let instance = builder.instantiate({
+ m: {
+ import: js_import
+ }
+ });
+ let wrapped_export = WebAssembly.promising(instance.exports.test);
+ assert_equals(await wrapped_export(), 42);
+
+ // Also try with a JS function with a mismatching arity.
+ js_import = new WebAssembly.Suspending((unused) => Promise.resolve(42));
+ instance = builder.instantiate({
+ m: {
+ import: js_import
+ }
+ });
+ wrapped_export = WebAssembly.promising(instance.exports.test);
+ assert_equals(await wrapped_export(), 42);
+
+ // Also try with a proxy.
+ js_import = new WebAssembly.Suspending(new Proxy(() => Promise.resolve(42), {}));
+ instance = builder.instantiate({
+ m: {
+ import: js_import
+ }
+ });
+ wrapped_export = WebAssembly.promising(instance.exports.test);
+ assert_equals(await wrapped_export(), 42);
+},"Suspending with mismatched args and via Proxy");
+
+function recordAbeforeB() {
+ let AbeforeB = [];
+ let setA = () => {
+ AbeforeB.push("A")
+ }
+ let setB = () => {
+ AbeforeB.push("B")
+ }
+ let isAbeforeB = () =>
+ AbeforeB[0] == "A" && AbeforeB[1] == "B";
+
+ let isBbeforeA = () =>
+ AbeforeB[0] == "B" && AbeforeB[1] == "A";
+
+ return {
+ setA: setA,
+ setB: setB,
+ isAbeforeB: isAbeforeB,
+ isBbeforeA: isBbeforeA,
+ }
+}
+
+promise_test(async () => {
+ let builder = new WasmModuleBuilder();
+ let AbeforeB = recordAbeforeB();
+ let import42_index = builder.addImport('m', 'import42', kSig_i_i);
+ let importSetA_index = builder.addImport('m', 'setA', kSig_v_v);
+ builder.addFunction("test", kSig_i_i)
+ .addBody([
+ kExprLocalGet, 0,
+ kExprCallFunction, import42_index, // suspend?
+ kExprCallFunction, importSetA_index
+ ]).exportFunc();
+ let import42 = new WebAssembly.Suspending(() => Promise.resolve(42));
+ let instance = builder.instantiate({
+ m: {
+ import42: import42,
+ setA: AbeforeB.setA
+ }
+ });
+
+ let wrapped_export = WebAssembly.promising(instance.exports.test);
+
+ let exported_promise = wrapped_export();
+
+ AbeforeB.setB();
+
+ assert_equals(await exported_promise, 42);
+
+ assert_true(AbeforeB.isBbeforeA());
+}, "Make sure we actually suspend");
+
+promise_test(async () => {
+ let builder = new WasmModuleBuilder();
+ let AbeforeB = recordAbeforeB();
+ let import42_index = builder.addImport('m', 'import42', kSig_i_i);
+ let importSetA_index = builder.addImport('m', 'setA', kSig_v_v);
+ builder.addFunction("test", kSig_i_i)
+ .addBody([
+ kExprLocalGet, 0,
+ kExprCallFunction, import42_index, // suspend?
+ kExprCallFunction, importSetA_index
+ ]).exportFunc();
+ let import42 = new WebAssembly.Suspending(() => 42);
+ let instance = builder.instantiate({
+ m: {
+ import42: import42,
+ setA: AbeforeB.setA
+ }
+ });
+
+ let wrapped_export = WebAssembly.promising(instance.exports.test);
+
+ let exported_promise = wrapped_export();
+ AbeforeB.setB();
+ assert_true(AbeforeB.isAbeforeB());
+
+ assert_equals(await exported_promise, 42);
+}, "Do not suspend if the import's return value is not a Promise");
+
+promise_test(async (t) => {
+ let tag = new WebAssembly.Tag({
+ parameters: ['i32']
+ });
+ let builder = new WasmModuleBuilder();
+ let import_index = builder.addImport('m', 'import', kSig_i_i);
+ let tag_index = builder.addImportedTag('m', 'tag', kSig_v_i);
+ builder.addFunction("test", kSig_i_i)
+ .addBody([
+ kExprTry, kWasmI32,
+ kExprLocalGet, 0,
+ kExprCallFunction, import_index,
+ kExprCatch, tag_index,
+ kExprEnd
+ ]).exportFunc();
+
+ function js_import(unused) {
+ return Promise.reject(new WebAssembly.Exception(tag, [42]));
+ };
+ let wasm_js_import = new WebAssembly.Suspending(js_import);
+
+ let instance = builder.instantiate({
+ m: {
+ import: wasm_js_import,
+ tag: tag
+ }
+ });
+ let wrapped_export = WebAssembly.promising(instance.exports.test);
+ let export_promise = wrapped_export();
+ assert_true(export_promise instanceof Promise);
+ assert_equals(await export_promise, 42);
+}, "Catch rejected promise");
+
+async function TestSandwich(suspend) {
+ // Set up a 'sandwich' scenario. The call chain looks like:
+ // top (wasm) -> outer (js) -> bottom (wasm) -> inner (js)
+ // If 'suspend' is true, the inner JS function returns a Promise, which
+ // suspends the bottom wasm function, which returns a Promise, which suspends
+ // the top wasm function, which returns a Promise. The inner Promise
+ // resolves first, which resumes the bottom continuation. Then the outer
+ // promise resolves which resumes the top continuation.
+ // If 'suspend' is false, the bottom JS function returns a regular value and
+ // no computation is suspended.
+ let builder = new WasmModuleBuilder();
+ let inner_index = builder.addImport('m', 'inner', kSig_i_i);
+ let outer_index = builder.addImport('m', 'outer', kSig_i_i);
+ builder.addFunction("top", kSig_i_i)
+ .addBody([
+ kExprLocalGet, 0,
+ kExprCallFunction, outer_index
+ ]).exportFunc();
+ builder.addFunction("bottom", kSig_i_i)
+ .addBody([
+ kExprLocalGet, 0,
+ kExprCallFunction, inner_index
+ ]).exportFunc();
+
+ let inner = new WebAssembly.Suspending(() => suspend ? Promise.resolve(42) : 43);
+
+ let export_inner;
+ let outer = new WebAssembly.Suspending(() => export_inner());
+
+ let instance = builder.instantiate({
+ m: {
+ inner,
+ outer
+ }
+ });
+ export_inner = WebAssembly.promising(instance.exports.bottom);
+ let export_top = WebAssembly.promising(instance.exports.top);
+ let result = export_top();
+ assert_true(result instanceof Promise);
+ if (suspend)
+ assert_equals(await result, 42);
+ else
+ assert_equals(await result, 43);
+}
+
+promise_test(async () => {
+ TestSandwich(true);
+}, "Test sandwich with suspension");
+
+promise_test(async () => {
+ TestSandwich(false);
+}, "Test sandwich with no suspension");
+
+test(() => {
+ // Check that a promising function with no return is allowed.
+ let builder = new WasmModuleBuilder();
+ builder.addFunction("export", kSig_v_v).addBody([]).exportFunc();
+ let instance = builder.instantiate();
+ let export_wrapper = WebAssembly.promising(instance.exports.export);
+ let export_sig = export_wrapper.type();
+ assert_array_equals(export_sig.parameters, []);
+ assert_array_equals(export_sig.results, ['externref']);
+},"Promising with no return");
+
+promise_test(async () => {
+ let builder1 = new WasmModuleBuilder();
+ let import_index = builder1.addImport('m', 'import', kSig_i_v);
+ builder1.addFunction("f", kSig_i_v)
+ .addBody([
+ kExprCallFunction, import_index, // suspend
+ kExprI32Const, 1,
+ kExprI32Add,
+ ]).exportFunc();
+ let js_import = new WebAssembly.Suspending(() => Promise.resolve(1));
+ let instance1 = builder1.instantiate({
+ m: {
+ import: js_import
+ }
+ });
+ let builder2 = new WasmModuleBuilder();
+ import_index = builder2.addImport('m', 'import', kSig_i_v);
+ builder2.addFunction("main", kSig_i_v)
+ .addBody([
+ kExprCallFunction, import_index,
+ kExprI32Const, 1,
+ kExprI32Add,
+ ]).exportFunc();
+ let instance2 = builder2.instantiate({
+ m: {
+ import: instance1.exports.f
+ }
+ });
+ let wrapped_export = WebAssembly.promising(instance2.exports.main);
+ assert_equals(await wrapped_export(), 3);
+},"Suspend two modules"); \ No newline at end of file
diff --git a/tests/wpt/tests/wasm/jsapi/jspi/rejects.any.js b/tests/wpt/tests/wasm/jsapi/jspi/rejects.any.js
new file mode 100644
index 00000000000..3ec3b90592a
--- /dev/null
+++ b/tests/wpt/tests/wasm/jsapi/jspi/rejects.any.js
@@ -0,0 +1,143 @@
+// META: global=window,dedicatedworker,jsshell
+// META: script=/wasm/jsapi/wasm-module-builder.js
+// META: script=/wasm/jsapi/jspi/testharness-additions.js
+
+promise_test(t => {
+ let tag = new WebAssembly.Tag({
+ parameters: []
+ });
+ let builder = new WasmModuleBuilder();
+ import_index = builder.addImport('m', 'import', kSig_i_i);
+ tag_index = builder.addImportedTag('m', 'tag', kSig_v_v);
+ builder.addFunction("test", kSig_i_i)
+ .addBody([
+ kExprLocalGet, 0,
+ kExprCallFunction, import_index,
+ kExprThrow, tag_index
+ ]).exportFunc();
+
+ function js_import() {
+ return Promise.resolve();
+ };
+ let wasm_js_import = new WebAssembly.Suspending(js_import);
+
+ let instance = builder.instantiate({
+ m: {
+ import: wasm_js_import,
+ tag: tag
+ }
+ });
+ let wrapped_export = WebAssembly.promising(instance.exports.test);
+ let export_promise = wrapped_export();
+ assert_true(export_promise instanceof Promise);
+ return promise_rejects_jspi(t, new WebAssembly.Exception(tag, []), export_promise);
+}, "Throw after the first suspension");
+
+// Throw an exception before suspending. The export wrapper should return a
+// promise rejected with the exception.
+promise_test(async (t) => {
+ let tag = new WebAssembly.Tag({
+ parameters: []
+ });
+ let builder = new WasmModuleBuilder();
+ tag_index = builder.addImportedTag('m', 'tag', kSig_v_v);
+ builder.addFunction("test", kSig_i_v)
+ .addBody([
+ kExprThrow, tag_index
+ ]).exportFunc();
+
+ let instance = builder.instantiate({
+ m: {
+ tag: tag
+ }
+ });
+ let wrapped_export = WebAssembly.promising(instance.exports.test);
+ let export_promise = wrapped_export();
+
+ promise_rejects_jspi(t, new WebAssembly.Exception(tag, []), export_promise);
+}, "Throw before suspending");
+
+// Throw an exception after the first resume event, which propagates to the
+// promise wrapper.
+promise_test(async (t) => {
+ let tag = new WebAssembly.Tag({
+ parameters: []
+ });
+ let builder = new WasmModuleBuilder();
+ import_index = builder.addImport('m', 'import', kSig_i_v);
+ tag_index = builder.addImportedTag('m', 'tag', kSig_v_v);
+ builder.addFunction("test", kSig_i_v)
+ .addBody([
+ kExprCallFunction, import_index,
+ kExprThrow, tag_index
+ ]).exportFunc();
+
+ function js_import() {
+ return Promise.resolve(42);
+ };
+ let wasm_js_import = new WebAssembly.Suspending(js_import);
+
+ let instance = builder.instantiate({
+ m: {
+ import: wasm_js_import,
+ tag: tag
+ }
+ });
+ let wrapped_export = WebAssembly.promising(instance.exports.test);
+ let export_promise = wrapped_export();
+
+ promise_rejects_jspi(t, new WebAssembly.Exception(tag, []), export_promise);
+}, "Throw and propagate via Promise");
+
+promise_test(async (t) => {
+ let builder = new WasmModuleBuilder();
+ builder.addFunction("test", kSig_i_v)
+ .addBody([
+ kExprCallFunction, 0
+ ]).exportFunc();
+ let instance = builder.instantiate();
+ let wrapper = WebAssembly.promising(instance.exports.test);
+
+ promise_rejects_js(t, RangeError, wrapper(), "Maximum call stack size exceeded");
+}, "Stack overflow");
+
+promise_test(async (t) => {
+ // The call stack of this test looks like:
+ // export1 -> import1 -> export2 -> import2
+ // Where export1 is "promising" and import2 is "suspending". Returning a
+ // promise from import2 should trap because of the JS import in the middle.
+ let builder = new WasmModuleBuilder();
+ let import1_index = builder.addImport("m", "import1", kSig_i_v);
+ let import2_index = builder.addImport("m", "import2", kSig_i_v);
+ builder.addFunction("export1", kSig_i_v)
+ .addBody([
+ // export1 -> import1 (unwrapped)
+ kExprCallFunction, import1_index,
+ ]).exportFunc();
+ builder.addFunction("export2", kSig_i_v)
+ .addBody([
+ // export2 -> import2 (suspending)
+ kExprCallFunction, import2_index,
+ ]).exportFunc();
+ let instance;
+
+ function import1() {
+ // import1 -> export2 (unwrapped)
+ instance.exports.export2();
+ }
+
+ function import2() {
+ return Promise.resolve(0);
+ }
+ import2 = new WebAssembly.Suspending(import2);
+ instance = builder.instantiate({
+ 'm': {
+ 'import1': import1,
+ 'import2': import2
+ }
+ });
+ // export1 (promising)
+ let wrapper = WebAssembly.promising(instance.exports.export1);
+ promise_rejects_js(t, WebAssembly.RuntimeError, wrapper(),
+ "trying to suspend JS frames");
+}, "Try to suspend JS"); \ No newline at end of file
diff --git a/tests/wpt/tests/wasm/jsapi/jspi/testharness-additions.js b/tests/wpt/tests/wasm/jsapi/jspi/testharness-additions.js
new file mode 100644
index 00000000000..e146c52f96d
--- /dev/null
+++ b/tests/wpt/tests/wasm/jsapi/jspi/testharness-additions.js
@@ -0,0 +1,26 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function assert_throws_jspi(code, func, description) {
+ try {
+ func();
+ } catch (e) {
+ assert_true(
+ e.name === code.name,
+ 'expected exception ' + code.name + ', got ' + e.name);
+ return;
+ }
+ assert_true(
+ false, 'expected exception ' + code.name + ', no exception thrown');
+ }
+
+ function promise_rejects_jspi(test, expected, promise, description) {
+ return promise
+ .then(() => assert_unreached('Should have rejected: ' + description))
+ .catch(function(e) {
+ assert_throws_jspi(expected, function() {
+ throw e;
+ }, description);
+ });
+ }
diff --git a/tests/wpt/tests/wasm/jsapi/memory/assertions.js b/tests/wpt/tests/wasm/jsapi/memory/assertions.js
index b539513adca..1430c523882 100644
--- a/tests/wpt/tests/wasm/jsapi/memory/assertions.js
+++ b/tests/wpt/tests/wasm/jsapi/memory/assertions.js
@@ -26,6 +26,7 @@ function assert_ArrayBuffer(actual, { size=0, shared=false, detached=false }, me
assert_equals(Object.isFrozen(actual), shared, "buffer frozen");
assert_equals(Object.isExtensible(actual), !shared, "buffer extensibility");
}
+globalThis.assert_ArrayBuffer = assert_ArrayBuffer;
function assert_Memory(memory, { size=0, shared=false }) {
assert_equals(Object.getPrototypeOf(memory), WebAssembly.Memory.prototype,
@@ -36,3 +37,4 @@ function assert_Memory(memory, { size=0, shared=false }) {
assert_equals(memory.buffer, memory.buffer, "buffer should be idempotent");
assert_ArrayBuffer(memory.buffer, { size, shared });
}
+globalThis.assert_Memory = assert_Memory;
diff --git a/tests/wpt/tests/wasm/jsapi/table/assertions.js b/tests/wpt/tests/wasm/jsapi/table/assertions.js
index 19cc5c3b92d..4fcd3517a6a 100644
--- a/tests/wpt/tests/wasm/jsapi/table/assertions.js
+++ b/tests/wpt/tests/wasm/jsapi/table/assertions.js
@@ -11,6 +11,7 @@ function assert_equal_to_array(table, expected, message) {
assert_throws_js(RangeError, () => table.get(expected.length + 1),
`${message}: table.get(${expected.length + 1} of ${expected.length})`);
}
+globalThis.assert_equal_to_array = assert_equal_to_array;
function assert_Table(actual, expected) {
assert_equals(Object.getPrototypeOf(actual), WebAssembly.Table.prototype,
@@ -22,3 +23,4 @@ function assert_Table(actual, expected) {
assert_equals(actual.get(i), null, `actual.get(${i})`);
}
}
+globalThis.assert_Table = assert_Table;
diff --git a/tests/wpt/tests/wasm/jsapi/wasm-module-builder.js b/tests/wpt/tests/wasm/jsapi/wasm-module-builder.js
index 90ccc954a5d..7fa196c58c1 100644
--- a/tests/wpt/tests/wasm/jsapi/wasm-module-builder.js
+++ b/tests/wpt/tests/wasm/jsapi/wasm-module-builder.js
@@ -81,6 +81,7 @@ let kWasmSubtypeFinalForm = 0x4f;
let kWasmRecursiveTypeGroupForm = 0x4e;
let kNoSuperType = 0xFFFFFFFF;
+globalThis.kNoSuperType = kNoSuperType;
let kHasMaximumFlag = 1;
let kSharedHasMaximumFlag = 3;
@@ -146,12 +147,27 @@ function wasmRefType(heap_type) {
return {opcode: kWasmRef, heap_type: heap_type};
}
+Object.assign(globalThis, {
+ kWasmStmt, kWasmI32, kWasmI64, kWasmF32, kWasmF64, kWasmS128, kWasmI8,
+ kWasmI16, kWasmNullFuncRef, kWasmNullExternRef, kWasmNullRef, kWasmFuncRef,
+ kWasmAnyFunc, kWasmExternRef, kWasmAnyRef, kWasmEqRef, kWasmI31Ref,
+ kWasmStructRef, kWasmArrayRef, kFuncRefCode, kAnyFuncCode, kExternRefCode,
+ kAnyRefCode, kEqRefCode, kI31RefCode, kNullExternRefCode, kNullFuncRefCode,
+ kStructRefCode, kArrayRefCode, kNullRefCode, kWasmRefNull, kWasmRef,
+ wasmRefNullType, wasmRefType
+});
+
let kExternalFunction = 0;
let kExternalTable = 1;
let kExternalMemory = 2;
let kExternalGlobal = 3;
let kExternalTag = 4;
+Object.assign(globalThis, {
+ kExternalFunction, kExternalTable, kExternalMemory, kExternalGlobal,
+ kExternalTag
+});
+
let kTableZero = 0;
let kMemoryZero = 0;
let kSegmentZero = 0;
@@ -227,6 +243,17 @@ function makeSig_r_xx(r, x) {
return makeSig([x, x], [r]);
}
+Object.assign(globalThis, {
+ kSig_i_i, kSig_l_l, kSig_i_l, kSig_i_ii, kSig_i_iii, kSig_v_iiii, kSig_f_ff,
+ kSig_d_dd, kSig_l_ll, kSig_i_dd, kSig_v_v, kSig_i_v, kSig_l_v, kSig_f_v,
+ kSig_d_v, kSig_v_i, kSig_v_ii, kSig_v_iii, kSig_v_l, kSig_v_d, kSig_v_dd,
+ kSig_v_ddi, kSig_ii_v, kSig_iii_v, kSig_ii_i, kSig_iii_i, kSig_ii_ii,
+ kSig_iii_ii, kSig_v_f, kSig_f_f, kSig_f_d, kSig_d_d, kSig_r_r, kSig_a_a,
+ kSig_i_r, kSig_v_r, kSig_v_a, kSig_v_rr, kSig_v_aa, kSig_r_v, kSig_a_v,
+ kSig_a_i,
+ makeSig, makeSig_v_x, makeSig_v_xx, makeSig_r_v, makeSig_r_x, makeSig_r_xx
+});
+
// Opcodes
let kExprUnreachable = 0x00;
let kExprNop = 0x01;
@@ -553,6 +580,89 @@ let kExprI32x4Eq = 0x2c;
let kExprS1x4AllTrue = 0x75;
let kExprF32x4Min = 0x9e;
+Object.assign(globalThis, {
+ kExprUnreachable, kExprNop, kExprBlock, kExprLoop, kExprIf, kExprElse,
+ kExprTry, kExprCatch, kExprCatchAll, kExprThrow, kExprRethrow, kExprBrOnExn,
+ kExprEnd, kExprBr, kExprBrIf, kExprBrTable, kExprReturn, kExprCallFunction,
+ kExprCallIndirect, kExprReturnCall, kExprReturnCallIndirect, kExprDrop,
+ kExprSelect, kExprLocalGet, kExprLocalSet, kExprLocalTee, kExprGlobalGet,
+ kExprGlobalSet, kExprTableGet, kExprTableSet, kExprI32LoadMem,
+ kExprI64LoadMem, kExprF32LoadMem, kExprF64LoadMem, kExprI32LoadMem8S,
+ kExprI32LoadMem8U, kExprI32LoadMem16S, kExprI32LoadMem16U, kExprI64LoadMem8S,
+ kExprI64LoadMem8U, kExprI64LoadMem16S, kExprI64LoadMem16U, kExprI64LoadMem32S,
+ kExprI64LoadMem32U, kExprI32StoreMem, kExprI64StoreMem, kExprF32StoreMem,
+ kExprF64StoreMem, kExprI32StoreMem8, kExprI32StoreMem16, kExprI64StoreMem8,
+ kExprI64StoreMem16, kExprI64StoreMem32, kExprMemorySize, kExprMemoryGrow,
+ kExprI32Const, kExprI64Const, kExprF32Const, kExprF64Const, kExprI32Eqz,
+ kExprI32Eq, kExprI32Ne, kExprI32LtS, kExprI32LtU, kExprI32GtS, kExprI32GtU,
+ kExprI32LeS, kExprI32LeU, kExprI32GeS, kExprI32GeU, kExprI64Eqz, kExprI64Eq,
+ kExprI64Ne, kExprI64LtS, kExprI64LtU, kExprI64GtS, kExprI64GtU, kExprI64LeS,
+ kExprI64LeU, kExprI64GeS, kExprI64GeU, kExprF32Eq, kExprF32Ne, kExprF32Lt,
+ kExprF32Gt, kExprF32Le, kExprF32Ge, kExprF64Eq, kExprF64Ne, kExprF64Lt,
+ kExprF64Gt, kExprF64Le, kExprF64Ge, kExprI32Clz, kExprI32Ctz, kExprI32Popcnt,
+ kExprI32Add, kExprI32Sub, kExprI32Mul, kExprI32DivS, kExprI32DivU,
+ kExprI32RemS, kExprI32RemU, kExprI32And, kExprI32Ior, kExprI32Xor,
+ kExprI32Shl, kExprI32ShrS, kExprI32ShrU, kExprI32Rol, kExprI32Ror,
+ kExprI64Clz, kExprI64Ctz, kExprI64Popcnt, kExprI64Add, kExprI64Sub,
+ kExprI64Mul, kExprI64DivS, kExprI64DivU, kExprI64RemS, kExprI64RemU,
+ kExprI64And, kExprI64Ior, kExprI64Xor, kExprI64Shl, kExprI64ShrS,
+ kExprI64ShrU, kExprI64Rol, kExprI64Ror, kExprF32Abs, kExprF32Neg,
+ kExprF32Ceil, kExprF32Floor, kExprF32Trunc, kExprF32NearestInt, kExprF32Sqrt,
+ kExprF32Add, kExprF32Sub, kExprF32Mul, kExprF32Div, kExprF32Min, kExprF32Max,
+ kExprF32CopySign, kExprF64Abs, kExprF64Neg, kExprF64Ceil, kExprF64Floor,
+ kExprF64Trunc, kExprF64NearestInt, kExprF64Sqrt, kExprF64Add, kExprF64Sub,
+ kExprF64Mul, kExprF64Div, kExprF64Min, kExprF64Max, kExprF64CopySign,
+ kExprI32ConvertI64, kExprI32SConvertF32, kExprI32UConvertF32,
+ kExprI32SConvertF64, kExprI32UConvertF64, kExprI64SConvertI32,
+ kExprI64UConvertI32, kExprI64SConvertF32, kExprI64UConvertF32,
+ kExprI64SConvertF64, kExprI64UConvertF64, kExprF32SConvertI32,
+ kExprF32UConvertI32, kExprF32SConvertI64, kExprF32UConvertI64,
+ kExprF32ConvertF64, kExprF64SConvertI32, kExprF64UConvertI32,
+ kExprF64SConvertI64, kExprF64UConvertI64, kExprF64ConvertF32,
+ kExprI32ReinterpretF32, kExprI64ReinterpretF64, kExprF32ReinterpretI32,
+ kExprF64ReinterpretI64, kExprI32SExtendI8, kExprI32SExtendI16,
+ kExprI64SExtendI8, kExprI64SExtendI16, kExprI64SExtendI32, kExprRefNull,
+ kExprRefIsNull, kExprRefFunc,
+ GCInstr,
+ kExprStructNew, kExprStructNewDefault, kExprStructGet, kExprStructGetS,
+ kExprStructGetU, kExprStructSet, kExprArrayNew, kExprArrayNewDefault,
+ kExprArrayNewFixed, kExprArrayNewData, kExprArrayNewElem, kExprArrayGet,
+ kExprArrayGetS, kExprArrayGetU, kExprArraySet, kExprArrayLen, kExprArrayFill,
+ kExprArrayCopy, kExprArrayInitData, kExprArrayInitElem, kExprRefTest,
+ kExprRefTestNull, kExprRefCast, kExprRefCastNull, kExprBrOnCast,
+ kExprBrOnCastFail, kExprExternInternalize, kExprExternExternalize,
+ kExprI31New, kExprI31GetS, kExprI31GetU,
+ kExprMemoryInit, kExprDataDrop, kExprMemoryCopy, kExprMemoryFill,
+ kExprTableInit, kExprElemDrop, kExprTableCopy, kExprTableGrow, kExprTableSize,
+ kExprTableFill,
+ kExprAtomicNotify, kExprI32AtomicWait, kExprI64AtomicWait, kExprI32AtomicLoad,
+ kExprI32AtomicLoad8U, kExprI32AtomicLoad16U, kExprI32AtomicStore,
+ kExprI32AtomicStore8U, kExprI32AtomicStore16U, kExprI32AtomicAdd,
+ kExprI32AtomicAdd8U, kExprI32AtomicAdd16U, kExprI32AtomicSub,
+ kExprI32AtomicSub8U, kExprI32AtomicSub16U, kExprI32AtomicAnd,
+ kExprI32AtomicAnd8U, kExprI32AtomicAnd16U, kExprI32AtomicOr,
+ kExprI32AtomicOr8U, kExprI32AtomicOr16U, kExprI32AtomicXor,
+ kExprI32AtomicXor8U, kExprI32AtomicXor16U, kExprI32AtomicExchange,
+ kExprI32AtomicExchange8U, kExprI32AtomicExchange16U,
+ kExprI32AtomicCompareExchange, kExprI32AtomicCompareExchange8U,
+ kExprI32AtomicCompareExchange16U, kExprI64AtomicLoad, kExprI64AtomicLoad8U,
+ kExprI64AtomicLoad16U, kExprI64AtomicLoad32U, kExprI64AtomicStore,
+ kExprI64AtomicStore8U, kExprI64AtomicStore16U, kExprI64AtomicStore32U,
+ kExprI64AtomicAdd, kExprI64AtomicAdd8U, kExprI64AtomicAdd16U,
+ kExprI64AtomicAdd32U, kExprI64AtomicSub, kExprI64AtomicSub8U,
+ kExprI64AtomicSub16U, kExprI64AtomicSub32U, kExprI64AtomicAnd,
+ kExprI64AtomicAnd8U, kExprI64AtomicAnd16U, kExprI64AtomicAnd32U,
+ kExprI64AtomicOr, kExprI64AtomicOr8U, kExprI64AtomicOr16U,
+ kExprI64AtomicOr32U, kExprI64AtomicXor, kExprI64AtomicXor8U,
+ kExprI64AtomicXor16U, kExprI64AtomicXor32U, kExprI64AtomicExchange,
+ kExprI64AtomicExchange8U, kExprI64AtomicExchange16U,
+ kExprI64AtomicExchange32U, kExprI64AtomicCompareExchange,
+ kExprI64AtomicCompareExchange8U, kExprI64AtomicCompareExchange16U,
+ kExprI64AtomicCompareExchange32U,
+ kExprS128LoadMem, kExprS128StoreMem, kExprI32x4Splat, kExprI32x4Eq,
+ kExprS1x4AllTrue, kExprF32x4Min
+});
+
class Binary {
constructor() {
this.length = 0;
diff --git a/tests/wpt/tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-resume-after-suspended.html b/tests/wpt/tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-resume-after-suspended.html
new file mode 100644
index 00000000000..82b17faa5a2
--- /dev/null
+++ b/tests/wpt/tests/webaudio/the-audio-api/the-analysernode-interface/test-analyser-resume-after-suspended.html
@@ -0,0 +1,106 @@
+<!doctype html>
+<meta name="timeout" content="long">
+<title>AnalyzerNode resumed after suspended</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+
+function areFloat32ArraysEqual(arr1, arr2) {
+ if (arr1.length !== arr2.length) {
+ return false;
+ }
+
+ for (let i = 0; i < arr1.length; i++) {
+ if (arr1[i] !== arr2[i]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// This test ensures that calling suspend() does not clear or reset
+// the AnalyserNode, and that after resuming the AudioContext,
+// it continues retrieving valid data without any interruptions.
+promise_test(async () => {
+ function runTest(resolve) {
+ const context = new AudioContext();
+ context.suspend();
+
+ const oscillator = new OscillatorNode(context);
+ oscillator.connect(context.destination);
+ oscillator.start();
+
+ const analyser = new AnalyserNode(context);
+ oscillator.connect(analyser);
+
+ let analyserReadCount = 0;
+ let lastTime = 0;
+ // Time between checks in milliseconds.
+ const interval = 300;
+
+ let previousTimeDomainDataArray =
+ new Float32Array(analyser.frequencyBinCount);
+
+ // The analyser.getFloatTimeDomainData() is called every 300 ms under
+ // suspended or resumed state. If it is a suspended state, the value
+ // from the function should be the same as the previous value. If
+ // it is a resumed state, the value should be different.
+ async function readAnalyserData(timestamp) {
+ if (lastTime === 0) {
+ lastTime = timestamp;
+ }
+
+ const elapsed = timestamp - lastTime;
+
+ // Only run the readAnalyserData every 300ms in order to give enough time
+ // for context to pull the data.
+ if (elapsed >= interval) {
+ analyserReadCount++;
+
+ let shouldSkipAsserts = false;
+ switch (analyserReadCount) {
+ case 1:
+ shouldSkipAsserts = true;
+ break;
+ case 10:
+ await context.suspend();
+ shouldSkipAsserts = true;
+ break;
+ case 5:
+ case 15:
+ await context.resume();
+ shouldSkipAsserts = true;
+ break;
+ case 20:
+ oscillator.stop();
+ resolve();
+ break;
+ default:
+ break;
+ }
+
+ const timeDomainDataArray =
+ new Float32Array(analyser.frequencyBinCount);
+ analyser.getFloatTimeDomainData(timeDomainDataArray);
+
+ if (!shouldSkipAsserts) {
+ let result = areFloat32ArraysEqual(timeDomainDataArray,
+ previousTimeDomainDataArray);
+ context.state === 'suspended' ? assert_true(result)
+ : assert_false(result);
+ }
+
+ previousTimeDomainDataArray.set(timeDomainDataArray);
+ lastTime = timestamp;
+ }
+
+ requestAnimationFrame(readAnalyserData);
+ }
+
+ requestAnimationFrame(readAnalyserData);
+ }
+
+ return new Promise((resolve) => runTest(resolve));
+}, 'AnalyserNode resume after suspended');
+</script>
diff --git a/tests/wpt/tests/webaudio/the-audio-api/the-audiocontext-interface/processing-after-resume.https.html b/tests/wpt/tests/webaudio/the-audio-api/the-audiocontext-interface/processing-after-resume.https.html
index a456f88e186..e000ab124fe 100644
--- a/tests/wpt/tests/webaudio/the-audio-api/the-audiocontext-interface/processing-after-resume.https.html
+++ b/tests/wpt/tests/webaudio/the-audio-api/the-audiocontext-interface/processing-after-resume.https.html
@@ -26,51 +26,30 @@ const modulePath = '/webaudio/the-audio-api/' +
'the-audioworklet-interface/processors/port-processor.js';
promise_test(async () => {
- let construct1;
- async function run_test() {
- const timeBeforeResume = realtime.currentTime;
- // Get the currentTime at the same time with AudioContext.currentTime.
- const {node: node1} = await construct1;
- const constructReply1 = await ping_for_reply(node1);
-
- // Two AudioWorkletNodes are constructed.
- // node1 is constructed before and node2 after the resume() call.
- await realtime.resume();
- const construct2 = get_node_and_reply(realtime);
-
- assert_equals(constructReply1.timeStamp, timeBeforeResume,
- 'construct time before resume');
- const {node: node2, reply: constructReply2} = await construct2;
-
- assert_greater_than_equal(constructReply2.timeStamp, timeBeforeResume,
- 'construct time after resume');
-
- // Suspend the context to freeze time and check that the processing for each
- // node matches the elapsed time.
- await realtime.suspend();
- const timeAfterSuspend = realtime.currentTime;
- const pong1 = await ping_for_reply(node1);
- const pong2 = await ping_for_reply(node2);
- assert_consistent(constructReply1, pong1, timeAfterSuspend, 'node1');
- assert_consistent(constructReply2, pong2, timeAfterSuspend, 'node2');
- assert_equals(pong1.currentFrame, pong2.currentFrame,
- 'currentFrame matches');
- };
-
const realtime = new AudioContext();
await realtime.audioWorklet.addModule(modulePath);
- construct1 = get_node_and_reply(realtime);
-
- if (realtime.state === 'running') {
- realtime.suspend();
- realtime.onstatechange = async (e) => {
- if (e.target.state === 'suspended') {
- e.target.onstatechange = null;
- await run_test();
- }
- };
- } else {
- await run_test();
- }
+ await realtime.suspend();
+ const timeBeforeResume = realtime.currentTime;
+ // Two AudioWorkletNodes are constructed.
+ // node1 is constructed before and node2 after the resume() call.
+ const construct1 = get_node_and_reply(realtime);
+ const resume = realtime.resume();
+ const construct2 = get_node_and_reply(realtime);
+ const {node: node1, reply: constructReply1} = await construct1;
+ assert_equals(constructReply1.timeStamp, timeBeforeResume,
+ 'construct time before resume');
+ const {node: node2, reply: constructReply2} = await construct2;
+ assert_greater_than_equal(constructReply2.timeStamp, timeBeforeResume,
+ 'construct time after resume');
+ await resume;
+ // Suspend the context to freeze time and check that the processing for each
+ // node matches the elapsed time.
+ await realtime.suspend();
+ const timeAfterSuspend = realtime.currentTime;
+ const pong1 = await ping_for_reply(node1);
+ const pong2 = await ping_for_reply(node2);
+ assert_consistent(constructReply1, pong1, timeAfterSuspend, 'node1');
+ assert_consistent(constructReply2, pong2, timeAfterSuspend, 'node2');
+ assert_equals(pong1.currentFrame, pong2.currentFrame, 'currentFrame matches');
});
</script>
diff --git a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/capture_screenshot/frame.py b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/capture_screenshot/frame_tentative.py
index bab97a31d20..bab97a31d20 100644
--- a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/capture_screenshot/frame.py
+++ b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/capture_screenshot/frame_tentative.py
diff --git a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/print/context.py b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/print/context.py
index f8074b71b43..2530eedb1b3 100644
--- a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/print/context.py
+++ b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/print/context.py
@@ -3,7 +3,7 @@ import pytest
pytestmark = pytest.mark.asyncio
-async def test_context(bidi_session, top_context, inline, assert_pdf_content):
+async def test_context_with_frame(bidi_session, top_context, inline, assert_pdf_content):
text = "Test"
url = inline(text)
await bidi_session.browsing_context.navigate(
@@ -13,49 +13,3 @@ async def test_context(bidi_session, top_context, inline, assert_pdf_content):
value = await bidi_session.browsing_context.print(context=top_context["context"])
await assert_pdf_content(value, [{"type": "string", "value": text}])
-
-
-async def test_page_with_iframe(
- bidi_session, top_context, inline, iframe, assert_pdf_content
-):
- text = "Test"
- iframe_content = "Iframe"
- url = inline(f"{text}<br/>{iframe(iframe_content)}")
- await bidi_session.browsing_context.navigate(
- context=top_context["context"], url=url, wait="complete"
- )
-
- whole_page_value = await bidi_session.browsing_context.print(
- context=top_context["context"]
- )
-
- await assert_pdf_content(
- whole_page_value, [{"type": "string", "value": text + iframe_content}]
- )
-
- contexts = await bidi_session.browsing_context.get_tree(root=top_context["context"])
- frame_context = contexts[0]["children"][0]
-
- frame_value = await bidi_session.browsing_context.print(
- context=frame_context["context"]
- )
-
- await assert_pdf_content(frame_value, [{"type": "string", "value": iframe_content}])
-
-
-@pytest.mark.parametrize("domain", ["", "alt"], ids=["same_origin", "cross_origin"])
-async def test_context_origin(
- bidi_session, top_context, inline, iframe, assert_pdf_content, domain
-):
- iframe_content = "Iframe"
- url = inline(f"{iframe(iframe_content, domain=domain)}")
- await bidi_session.browsing_context.navigate(
- context=top_context["context"], url=url, wait="complete"
- )
-
- contexts = await bidi_session.browsing_context.get_tree(root=top_context["context"])
- frame_context = contexts[0]["children"][0]
-
- value = await bidi_session.browsing_context.print(context=frame_context["context"])
-
- await assert_pdf_content(value, [{"type": "string", "value": iframe_content}])
diff --git a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/print/frame_tentative.py b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/print/frame_tentative.py
new file mode 100644
index 00000000000..98972d86245
--- /dev/null
+++ b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/print/frame_tentative.py
@@ -0,0 +1,49 @@
+import pytest
+
+pytestmark = pytest.mark.asyncio
+
+
+async def test_iframe(
+ bidi_session, top_context, inline, iframe, assert_pdf_content
+):
+ text = "Test"
+ iframe_content = "Iframe"
+ url = inline(f"{text}<br/>{iframe(iframe_content)}")
+ await bidi_session.browsing_context.navigate(
+ context=top_context["context"], url=url, wait="complete"
+ )
+
+ whole_page_value = await bidi_session.browsing_context.print(
+ context=top_context["context"]
+ )
+
+ await assert_pdf_content(
+ whole_page_value, [{"type": "string", "value": text + iframe_content}]
+ )
+
+ contexts = await bidi_session.browsing_context.get_tree(root=top_context["context"])
+ frame_context = contexts[0]["children"][0]
+
+ frame_value = await bidi_session.browsing_context.print(
+ context=frame_context["context"]
+ )
+
+ await assert_pdf_content(frame_value, [{"type": "string", "value": iframe_content}])
+
+
+@pytest.mark.parametrize("domain", ["", "alt"], ids=["same_origin", "cross_origin"])
+async def test_iframe_origin(
+ bidi_session, top_context, inline, iframe, assert_pdf_content, domain
+):
+ iframe_content = "Iframe"
+ url = inline(f"{iframe(iframe_content, domain=domain)}")
+ await bidi_session.browsing_context.navigate(
+ context=top_context["context"], url=url, wait="complete"
+ )
+
+ contexts = await bidi_session.browsing_context.get_tree(root=top_context["context"])
+ frame_context = contexts[0]["children"][0]
+
+ value = await bidi_session.browsing_context.print(context=frame_context["context"])
+
+ await assert_pdf_content(value, [{"type": "string", "value": iframe_content}])
diff --git a/tests/wpt/tests/webdriver/tests/bidi/network/__init__.py b/tests/wpt/tests/webdriver/tests/bidi/network/__init__.py
index 0c3338362d3..5decb28a1a9 100644
--- a/tests/wpt/tests/webdriver/tests/bidi/network/__init__.py
+++ b/tests/wpt/tests/webdriver/tests/bidi/network/__init__.py
@@ -1,3 +1,4 @@
+import base64
import random
import urllib
from datetime import datetime, timedelta, timezone
@@ -388,6 +389,8 @@ PAGE_REDIRECT_HTTP_EQUIV = (
PAGE_REDIRECTED_HTML = "/webdriver/tests/bidi/network/support/redirected.html"
PAGE_SERVICEWORKER_HTML = "/webdriver/tests/bidi/network/support/serviceworker.html"
+IMAGE_RESPONSE_BODY = urllib.parse.quote_plus(base64.b64decode(b"iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="))
+
SCRIPT_CONSOLE_LOG = urllib.parse.quote_plus("console.log('test')")
SCRIPT_CONSOLE_LOG_IN_MODULE = urllib.parse.quote_plus("export default function foo() { console.log('from module') }")
diff --git a/tests/wpt/tests/webdriver/tests/bidi/network/before_request_sent/before_request_sent_cached.py b/tests/wpt/tests/webdriver/tests/bidi/network/before_request_sent/before_request_sent_cached.py
index 4177d316c51..a042e7510b4 100644
--- a/tests/wpt/tests/webdriver/tests/bidi/network/before_request_sent/before_request_sent_cached.py
+++ b/tests/wpt/tests/webdriver/tests/bidi/network/before_request_sent/before_request_sent_cached.py
@@ -7,6 +7,7 @@ from .. import (
assert_before_request_sent_event,
get_cached_url,
BEFORE_REQUEST_SENT_EVENT,
+ IMAGE_RESPONSE_BODY,
SCRIPT_CONSOLE_LOG,
SCRIPT_CONSOLE_LOG_IN_MODULE,
STYLESHEET_GREY_BACKGROUND,
@@ -496,3 +497,66 @@ async def tst_page_with_cached_javascript_module(
cached_events[1],
expected_request={"method": "GET", "url": cached_js_module_url},
)
+
+
+@pytest.mark.asyncio
+async def test_page_with_cached_image(
+ bidi_session,
+ url,
+ inline,
+ setup_network_test,
+ top_context,
+):
+ network_events = await setup_network_test(
+ events=[
+ BEFORE_REQUEST_SENT_EVENT,
+ ]
+ )
+ events = network_events[BEFORE_REQUEST_SENT_EVENT]
+
+ cached_image_url = url(get_cached_url("img/png", IMAGE_RESPONSE_BODY))
+ page_with_cached_image = inline(
+ f"""
+ <body>
+ test page with cached image
+ <img src="{cached_image_url}">
+ </body>
+ """,
+ )
+
+ await bidi_session.browsing_context.navigate(
+ context=top_context["context"],
+ url=page_with_cached_image,
+ wait="complete",
+ )
+
+ # Expect two events, one for the document and one for the image.
+ wait = AsyncPoll(bidi_session, timeout=2)
+ await wait.until(lambda _: len(events) >= 2)
+ assert len(events) == 2
+
+ assert_before_request_sent_event(
+ events[0],
+ expected_request={"method": "GET", "url": page_with_cached_image},
+ )
+ assert_before_request_sent_event(
+ events[1],
+ expected_request={"method": "GET", "url": cached_image_url},
+ )
+
+ # Reload the page.
+ await bidi_session.browsing_context.reload(context=top_context["context"])
+
+ # Expect two events, one for the document and one for the image.
+ wait = AsyncPoll(bidi_session, timeout=2)
+ await wait.until(lambda _: len(events) >= 4)
+ assert len(events) == 4
+
+ assert_before_request_sent_event(
+ events[2],
+ expected_request={"method": "GET", "url": page_with_cached_image},
+ )
+ assert_before_request_sent_event(
+ events[3],
+ expected_request={"method": "GET", "url": cached_image_url},
+ )
diff --git a/tests/wpt/tests/webdriver/tests/bidi/network/response_completed/response_completed_cached.py b/tests/wpt/tests/webdriver/tests/bidi/network/response_completed/response_completed_cached.py
index dac13abf61b..0a624dcfaed 100644
--- a/tests/wpt/tests/webdriver/tests/bidi/network/response_completed/response_completed_cached.py
+++ b/tests/wpt/tests/webdriver/tests/bidi/network/response_completed/response_completed_cached.py
@@ -6,6 +6,7 @@ from tests.support.sync import AsyncPoll
from .. import (
assert_response_event,
get_cached_url,
+ IMAGE_RESPONSE_BODY,
PAGE_EMPTY_TEXT,
RESPONSE_COMPLETED_EVENT,
SCRIPT_CONSOLE_LOG,
@@ -665,3 +666,70 @@ async def test_page_with_cached_javascript_module(
expected_request={"method": "GET", "url": cached_js_module_url},
expected_response={"url": cached_js_module_url, "fromCache": True},
)
+
+
+@pytest.mark.asyncio
+async def test_page_with_cached_image(
+ bidi_session,
+ url,
+ inline,
+ setup_network_test,
+ top_context,
+):
+ network_events = await setup_network_test(
+ events=[
+ RESPONSE_COMPLETED_EVENT,
+ ]
+ )
+ events = network_events[RESPONSE_COMPLETED_EVENT]
+
+ cached_image_url = url(get_cached_url("img/png", IMAGE_RESPONSE_BODY))
+ page_with_cached_image = inline(
+ f"""
+ <body>
+ test page with cached image
+ <img src="{cached_image_url}">
+ </body>
+ """,
+ )
+
+ await bidi_session.browsing_context.navigate(
+ context=top_context["context"],
+ url=page_with_cached_image,
+ wait="complete",
+ )
+
+ # Expect two events, one for the document and one for the image.
+ wait = AsyncPoll(bidi_session, timeout=2)
+ await wait.until(lambda _: len(events) >= 2)
+ assert len(events) == 2
+
+ assert_response_event(
+ events[0],
+ expected_request={"method": "GET", "url": page_with_cached_image},
+ expected_response={"url": page_with_cached_image, "fromCache": False},
+ )
+ assert_response_event(
+ events[1],
+ expected_request={"method": "GET", "url": cached_image_url},
+ expected_response={"url": cached_image_url, "fromCache": False},
+ )
+
+ # Reload the page.
+ await bidi_session.browsing_context.reload(context=top_context["context"])
+
+ # Expect two events, one for the document and one for the image.
+ wait = AsyncPoll(bidi_session, timeout=2)
+ await wait.until(lambda _: len(events) >= 4)
+ assert len(events) == 4
+
+ assert_response_event(
+ events[2],
+ expected_request={"method": "GET", "url": page_with_cached_image},
+ expected_response={"url": page_with_cached_image, "fromCache": False},
+ )
+ assert_response_event(
+ events[3],
+ expected_request={"method": "GET", "url": cached_image_url},
+ expected_response={"url": cached_image_url, "fromCache": True},
+ )
diff --git a/tests/wpt/tests/webdriver/tests/bidi/network/response_started/response_started_cached.py b/tests/wpt/tests/webdriver/tests/bidi/network/response_started/response_started_cached.py
index ccb7a97300d..db0a2514c93 100644
--- a/tests/wpt/tests/webdriver/tests/bidi/network/response_started/response_started_cached.py
+++ b/tests/wpt/tests/webdriver/tests/bidi/network/response_started/response_started_cached.py
@@ -6,6 +6,7 @@ from tests.support.sync import AsyncPoll
from .. import (
assert_response_event,
get_cached_url,
+ IMAGE_RESPONSE_BODY,
PAGE_EMPTY_TEXT,
RESPONSE_STARTED_EVENT,
SCRIPT_CONSOLE_LOG,
@@ -677,3 +678,70 @@ async def test_page_with_cached_javascript_module(
expected_request={"method": "GET", "url": cached_js_module_url},
expected_response={"url": cached_js_module_url, "fromCache": True},
)
+
+
+@pytest.mark.asyncio
+async def test_page_with_cached_image(
+ bidi_session,
+ url,
+ inline,
+ setup_network_test,
+ top_context,
+):
+ network_events = await setup_network_test(
+ events=[
+ RESPONSE_STARTED_EVENT,
+ ]
+ )
+ events = network_events[RESPONSE_STARTED_EVENT]
+
+ cached_image_url = url(get_cached_url("img/png", IMAGE_RESPONSE_BODY))
+ page_with_cached_image = inline(
+ f"""
+ <body>
+ test page with cached image
+ <img src="{cached_image_url}">
+ </body>
+ """,
+ )
+
+ await bidi_session.browsing_context.navigate(
+ context=top_context["context"],
+ url=page_with_cached_image,
+ wait="complete",
+ )
+
+ # Expect two events, one for the document and one for the image.
+ wait = AsyncPoll(bidi_session, timeout=2)
+ await wait.until(lambda _: len(events) >= 2)
+ assert len(events) == 2
+
+ assert_response_event(
+ events[0],
+ expected_request={"method": "GET", "url": page_with_cached_image},
+ expected_response={"url": page_with_cached_image, "fromCache": False},
+ )
+ assert_response_event(
+ events[1],
+ expected_request={"method": "GET", "url": cached_image_url},
+ expected_response={"url": cached_image_url, "fromCache": False},
+ )
+
+ # Reload the page.
+ await bidi_session.browsing_context.reload(context=top_context["context"])
+
+ # Expect two events, one for the document and one for the image.
+ wait = AsyncPoll(bidi_session, timeout=2)
+ await wait.until(lambda _: len(events) >= 4)
+ assert len(events) == 4
+
+ assert_response_event(
+ events[2],
+ expected_request={"method": "GET", "url": page_with_cached_image},
+ expected_response={"url": page_with_cached_image, "fromCache": False},
+ )
+ assert_response_event(
+ events[3],
+ expected_request={"method": "GET", "url": cached_image_url},
+ expected_response={"url": cached_image_url, "fromCache": True},
+ )
diff --git a/tests/wpt/tests/webnn/conformance_tests/byob_readtensor.https.any.js b/tests/wpt/tests/webnn/conformance_tests/byob_readtensor.https.any.js
index b99c8704d23..f43cca0ea4e 100644
--- a/tests/wpt/tests/webnn/conformance_tests/byob_readtensor.https.any.js
+++ b/tests/wpt/tests/webnn/conformance_tests/byob_readtensor.https.any.js
@@ -32,7 +32,8 @@ promise_setup(async () => {
mlTensor = await mlContext.createTensor({
dataType: 'int32',
shape: [2, 4],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
});
} catch (e) {
throw new AssertionError(
@@ -141,7 +142,7 @@ promise_test(async (t) => {
const tensor = await mlContext.createTensor({
dataType: 'int32',
shape: [2, 2],
- usage: MLTensorUsage.READ,
+ readable: true,
});
const arrayBufferView = new Int32Array(2 * 2);
const arrayBuffer = arrayBufferView.buffer;
@@ -159,7 +160,7 @@ promise_test(async (t) => {
const tensor = await mlContext.createTensor({
dataType: 'int32',
shape: [2, 2],
- usage: MLTensorUsage.READ,
+ readable: true,
});
const arrayBufferView = new Int32Array(2 * 2);
const arrayBuffer = arrayBufferView.buffer;
diff --git a/tests/wpt/tests/webnn/conformance_tests/dequantizeLinear.https.any.js b/tests/wpt/tests/webnn/conformance_tests/dequantizeLinear.https.any.js
index c6acb042a24..8a04d0e6b8a 100644
--- a/tests/wpt/tests/webnn/conformance_tests/dequantizeLinear.https.any.js
+++ b/tests/wpt/tests/webnn/conformance_tests/dequantizeLinear.https.any.js
@@ -147,6 +147,197 @@ const dequantizeLinearTests = [
}
}
}
+ },
+ {
+ 'name': 'dequantizeLinear uint4 1D tensor with even input size',
+ 'graph': {
+ 'inputs': {
+ 'dequantizeLinearInput': {
+ 'data': [15, 0],
+ 'descriptor': {shape: [2], dataType: 'uint4'},
+ 'constant': true
+ },
+ 'dequantizeLinearScale': {
+ 'data': [1.1202747821807861, 1.1202747821807861],
+ 'descriptor': {shape: [2], dataType: 'float32'},
+ 'constant': true
+ },
+ 'dequantizeLinearZeroPoint': {
+ 'data': [0],
+ 'descriptor': {shape: [], dataType: 'uint4'},
+ 'constant': true
+ }
+ },
+ 'operators': [{
+ 'name': 'dequantizeLinear',
+ 'arguments': [
+ {'input': 'dequantizeLinearInput'},
+ {'scale': 'dequantizeLinearScale'},
+ {'zeroPoint': 'dequantizeLinearZeroPoint'}
+ ],
+ 'outputs': 'dequantizeLinearOutput'
+ }],
+ 'expectedOutputs': {
+ 'dequantizeLinearOutput': {
+ 'data': [16.804121017456055, 0],
+ 'descriptor': {shape: [2], dataType: 'float32'}
+ }
+ }
+ }
+ },
+ {
+ 'name': 'dequantizeLinear uint4 1D tensor with odd input size',
+ 'graph': {
+ 'inputs': {
+ 'dequantizeLinearInput': {
+ 'data': [10, 12, 14],
+ 'descriptor': {shape: [3], dataType: 'uint4'},
+ 'constant': true
+ },
+ 'dequantizeLinearScale': {
+ 'data': [1.1202747821807861],
+ 'descriptor': {shape: [1], dataType: 'float32'},
+ 'constant': true
+ },
+ 'dequantizeLinearZeroPoint': {
+ 'data': [2, 1, 4],
+ 'descriptor': {shape: [3], dataType: 'uint4'},
+ 'constant': true
+ }
+ },
+ 'operators': [{
+ 'name': 'dequantizeLinear',
+ 'arguments': [
+ {'input': 'dequantizeLinearInput'},
+ {'scale': 'dequantizeLinearScale'},
+ {'zeroPoint': 'dequantizeLinearZeroPoint'}
+ ],
+ 'outputs': 'dequantizeLinearOutput'
+ }],
+ 'expectedOutputs': {
+ 'dequantizeLinearOutput': {
+ 'data': [8.962198257446289, 12.323022842407227, 11.202747344970703],
+ 'descriptor': {shape: [3], dataType: 'float32'}
+ }
+ }
+ }
+ },
+ {
+ 'name': 'dequantizeLinear uint4 4D constant tensor broadcasting zeroPoint',
+ 'graph': {
+ 'inputs': {
+ 'dequantizeLinearInput': {
+ 'data': [0, 1, 10, 15],
+ 'descriptor': {shape: [1, 1, 2, 2], dataType: 'uint4'},
+ 'constant': true
+ },
+ 'dequantizeLinearScale': {
+ 'data': [
+ 9.343092918395996,
+ -4.617084980010986,
+ ],
+ 'descriptor': {shape: [2, 1], dataType: 'float32'},
+ 'constant': true
+ },
+ 'dequantizeLinearZeroPoint': {
+ 'data': [2, 3],
+ 'descriptor': {shape: [2], dataType: 'uint4'},
+ 'constant': true
+ }
+ },
+ 'operators': [{
+ 'name': 'dequantizeLinear',
+ 'arguments': [
+ {'input': 'dequantizeLinearInput'},
+ {'scale': 'dequantizeLinearScale'},
+ {'zeroPoint': 'dequantizeLinearZeroPoint'}
+ ],
+ 'outputs': 'dequantizeLinearOutput'
+ }],
+ 'expectedOutputs': {
+ 'dequantizeLinearOutput': {
+ 'data': [
+ -18.686185836791992, -18.686185836791992, -36.93667984008789,
+ -55.40502166748047
+ ],
+ 'descriptor': {shape: [1, 1, 2, 2], dataType: 'float32'}
+ }
+ }
+ }
+ },
+ {
+ 'name': 'dequantizeLinear int4 1D tensor with even size',
+ 'graph': {
+ 'inputs': {
+ 'dequantizeLinearInput': {
+ 'data': [-8, -3],
+ 'descriptor': {shape: [2], dataType: 'int4'},
+ 'constant': true
+ },
+ 'dequantizeLinearScale': {
+ 'data': [1.1202747821807861],
+ 'descriptor': {shape: [], dataType: 'float32'},
+ 'constant': true
+ },
+ 'dequantizeLinearZeroPoint': {
+ 'data': [0, -2],
+ 'descriptor': {shape: [2], dataType: 'int4'},
+ 'constant': true
+ }
+ },
+ 'operators': [{
+ 'name': 'dequantizeLinear',
+ 'arguments': [
+ {'input': 'dequantizeLinearInput'},
+ {'scale': 'dequantizeLinearScale'},
+ {'zeroPoint': 'dequantizeLinearZeroPoint'}
+ ],
+ 'outputs': 'dequantizeLinearOutput'
+ }],
+ 'expectedOutputs': {
+ 'dequantizeLinearOutput': {
+ 'data': [-8.962198257446289, -1.1202747821807861],
+ 'descriptor': {shape: [2], dataType: 'float32'}
+ }
+ }
+ }
+ },
+ {
+ 'name': 'dequantizeLinear int4 1D tensor with odd size',
+ 'graph': {
+ 'inputs': {
+ 'dequantizeLinearInput': {
+ 'data': [-1, 7, 0],
+ 'descriptor': {shape: [3], dataType: 'int4'},
+ 'constant': true
+ },
+ 'dequantizeLinearScale': {
+ 'data': [1.1202747821807861],
+ 'descriptor': {shape: [], dataType: 'float32'},
+ 'constant': true
+ },
+ 'dequantizeLinearZeroPoint': {
+ 'data': [-3, 0, 0],
+ 'descriptor': {shape: [3], dataType: 'int4'},
+ 'constant': true
+ }
+ },
+ 'operators': [{
+ 'name': 'dequantizeLinear',
+ 'arguments': [
+ {'input': 'dequantizeLinearInput'},
+ {'scale': 'dequantizeLinearScale'},
+ {'zeroPoint': 'dequantizeLinearZeroPoint'}
+ ],
+ 'outputs': 'dequantizeLinearOutput'
+ }],
+ 'expectedOutputs': {
+ 'dequantizeLinearOutput': {
+ 'data': [2.2405495643615723, 7.841923713684082, 0],
+ 'descriptor': {shape: [3], dataType: 'float32'}
+ }
+ }
+ }
}
];
diff --git a/tests/wpt/tests/webnn/conformance_tests/gather.https.any.js b/tests/wpt/tests/webnn/conformance_tests/gather.https.any.js
index 3cdd411ecb3..17c31413758 100644
--- a/tests/wpt/tests/webnn/conformance_tests/gather.https.any.js
+++ b/tests/wpt/tests/webnn/conformance_tests/gather.https.any.js
@@ -67,7 +67,7 @@ const gatherTests = [
},
{
'name':
- 'gather float32 1D tensor and int32 0D scalar indices default options',
+ 'gather float32 1D tensor and int64 0D scalar indices default options',
'graph': {
'inputs': {
'gatherInput': {
@@ -85,7 +85,7 @@ const gatherTests = [
},
'gatherIndices': {
'data': [4],
- 'descriptor': {shape: [], dataType: 'int32'},
+ 'descriptor': {shape: [], dataType: 'int64'},
'constant': true
}
},
@@ -104,7 +104,7 @@ const gatherTests = [
},
{
'name':
- 'gather float32 1D tensor and int64 0D scalar indices default options',
+ 'gather float32 1D tensor and int32 0D scalar indices default options',
'graph': {
'inputs': {
'gatherInput': {
@@ -121,8 +121,8 @@ const gatherTests = [
'descriptor': {shape: [24], dataType: 'float32'}
},
'gatherIndices': {
- 'data': [0],
- 'descriptor': {shape: [], dataType: 'int64'},
+ 'data': [4],
+ 'descriptor': {shape: [], dataType: 'int32'},
'constant': true
}
},
@@ -133,14 +133,14 @@ const gatherTests = [
}],
'expectedOutputs': {
'gatherOutput': {
- 'data': [-66.05901336669922],
+ 'data': [89.0337142944336],
'descriptor': {shape: [], dataType: 'float32'}
}
}
}
},
{
- 'name': 'gather float32 1D tensor and int64 1D indices default options',
+ 'name': 'gather float32 1D tensor and int32 1D indices default options',
'graph': {
'inputs': {
'gatherInput': {
@@ -158,7 +158,7 @@ const gatherTests = [
},
'gatherIndices': {
'data': [16, 20, 6, 11, 17, 19, 13, 17],
- 'descriptor': {shape: [8], dataType: 'int64'},
+ 'descriptor': {shape: [8], dataType: 'int32'},
'constant': true
}
},
@@ -180,7 +180,7 @@ const gatherTests = [
}
},
{
- 'name': 'gather float32 1D tensor and int64 2D indices default options',
+ 'name': 'gather float32 1D tensor and int32 2D indices default options',
'graph': {
'inputs': {
'gatherInput': {
@@ -198,7 +198,7 @@ const gatherTests = [
},
'gatherIndices': {
'data': [14, 9, 21, 17],
- 'descriptor': {shape: [2, 2], dataType: 'int64'},
+ 'descriptor': {shape: [2, 2], dataType: 'int32'},
'constant': true
}
},
@@ -219,7 +219,7 @@ const gatherTests = [
}
},
{
- 'name': 'gather float32 1D tensor and int64 3D indices default options',
+ 'name': 'gather float32 1D tensor and int32 3D indices default options',
'graph': {
'inputs': {
'gatherInput': {
@@ -238,7 +238,7 @@ const gatherTests = [
'gatherIndices': {
'data':
[17, 19, 14, 16, 13, 0, 5, 15, 18, 18, 6, 20, 7, 22, 5, 1, 4, 19],
- 'descriptor': {shape: [2, 3, 3], dataType: 'int64'},
+ 'descriptor': {shape: [2, 3, 3], dataType: 'int32'},
'constant': true
}
},
@@ -263,7 +263,7 @@ const gatherTests = [
}
},
{
- 'name': 'gather float32 1D tensor and int64 4D indices default options',
+ 'name': 'gather float32 1D tensor and int32 4D indices default options',
'graph': {
'inputs': {
'gatherInput': {
@@ -281,7 +281,7 @@ const gatherTests = [
},
'gatherIndices': {
'data': [18, 18, 22, 11, 8, 15, 12, 11, 7, 13, 7, 7],
- 'descriptor': {shape: [1, 2, 2, 3], dataType: 'int64'},
+ 'descriptor': {shape: [1, 2, 2, 3], dataType: 'int32'},
'constant': true
}
},
@@ -322,7 +322,7 @@ const gatherTests = [
},
'gatherIndices': {
'data': [11],
- 'descriptor': {shape: [], dataType: 'int64'},
+ 'descriptor': {shape: [], dataType: 'int32'},
'constant': true
}
},
@@ -358,7 +358,7 @@ const gatherTests = [
},
'gatherIndices': {
'data': [1, 10, 9, 0, 3, 5, 3, 8],
- 'descriptor': {shape: [8], dataType: 'int64'},
+ 'descriptor': {shape: [8], dataType: 'int32'},
'constant': true
}
},
@@ -401,7 +401,7 @@ const gatherTests = [
},
'gatherIndices': {
'data': [4, 8, 9, 10],
- 'descriptor': {shape: [2, 2], dataType: 'int64'},
+ 'descriptor': {shape: [2, 2], dataType: 'int32'},
'constant': true
}
},
@@ -441,7 +441,7 @@ const gatherTests = [
},
'gatherIndices': {
'data': [8, 2, 2, 3, 4, 1, 2, 2, 7, 11, 4, 11, 6, 6, 7, 3, 11, 10],
- 'descriptor': {shape: [2, 3, 3], dataType: 'int64'},
+ 'descriptor': {shape: [2, 3, 3], dataType: 'int32'},
'constant': true
}
},
@@ -490,7 +490,7 @@ const gatherTests = [
},
'gatherIndices': {
'data': [6, 9, 7, 3, 4, 7, 4, 3, 7, 7, 6, 0],
- 'descriptor': {shape: [1, 2, 2, 3], dataType: 'int64'},
+ 'descriptor': {shape: [1, 2, 2, 3], dataType: 'int32'},
'constant': true
}
},
@@ -535,7 +535,7 @@ const gatherTests = [
},
'gatherIndices': {
'data': [2, 1, 1, 1],
- 'descriptor': {shape: [2, 2], dataType: 'int64'},
+ 'descriptor': {shape: [2, 2], dataType: 'int32'},
'constant': true
}
},
@@ -583,7 +583,7 @@ const gatherTests = [
},
'gatherIndices': {
'data': [0, 0, 7, 4],
- 'descriptor': {shape: [2, 2], dataType: 'int64'},
+ 'descriptor': {shape: [2, 2], dataType: 'int32'},
'constant': true
}
},
@@ -624,7 +624,7 @@ const gatherTests = [
},
'gatherIndices': {
'data': [3, 2, 2],
- 'descriptor': {shape: [3], dataType: 'int64'},
+ 'descriptor': {shape: [3], dataType: 'int32'},
'constant': true
}
},
@@ -667,7 +667,7 @@ const gatherTests = [
},
'gatherIndices': {
'data': [1, 1, 2],
- 'descriptor': {shape: [3], dataType: 'int64'},
+ 'descriptor': {shape: [3], dataType: 'int32'},
'constant': true
}
},
@@ -713,7 +713,7 @@ const gatherTests = [
},
'gatherIndices': {
'data': [0, 0, 0, 1],
- 'descriptor': {shape: [2, 2], dataType: 'int64'},
+ 'descriptor': {shape: [2, 2], dataType: 'int32'},
'constant': true
}
},
@@ -769,7 +769,7 @@ const gatherTests = [
},
'gatherIndices': {
'data': [0, 0, 7, 4],
- 'descriptor': {shape: [2, 2], dataType: 'int64'},
+ 'descriptor': {shape: [2, 2], dataType: 'int32'},
'constant': true
}
},
@@ -813,7 +813,7 @@ const gatherTests = [
},
'gatherIndices': {
'data': [1],
- 'descriptor': {shape: [], dataType: 'int64'},
+ 'descriptor': {shape: [], dataType: 'int32'},
'constant': true
}
},
diff --git a/tests/wpt/tests/webnn/conformance_tests/gatherND.https.any.js b/tests/wpt/tests/webnn/conformance_tests/gatherND.https.any.js
index e8f31d5617b..b40507d2dce 100644
--- a/tests/wpt/tests/webnn/conformance_tests/gatherND.https.any.js
+++ b/tests/wpt/tests/webnn/conformance_tests/gatherND.https.any.js
@@ -63,7 +63,7 @@ const gatherNDTests = [
}
},
{
- 'name': 'gatherND float32 4D input and 1D indices',
+ 'name': 'gatherND float32 4D input and 1D int32 indices',
'graph': {
'inputs': {
'gatherNDInput': {
@@ -98,6 +98,146 @@ const gatherNDTests = [
}
},
{
+ 'name': 'gatherND float32 4D input and 1D uint32 indices',
+ 'graph': {
+ 'inputs': {
+ 'gatherNDInput': {
+ 'data': [
+ -66.05901336669922, -68.9197006225586, -77.02045440673828,
+ -26.158037185668945, 89.0337142944336, -45.89653396606445,
+ 43.84803771972656, 48.81806945800781, 51.79948425292969,
+ 41.94132614135742, -1.1303654909133911, -50.42131042480469,
+ 90.2870101928711, 55.620765686035156, 44.92119598388672,
+ 56.828636169433594
+ ],
+ 'descriptor': {shape: [2, 2, 2, 2], dataType: 'float32'}
+ },
+ 'gatherNDIndices': {
+ 'data': [1, 0, 0],
+ 'descriptor': {shape: [3], dataType: 'uint32'},
+ 'constant': true
+ }
+ },
+ 'operators': [{
+ 'name': 'gatherND',
+ 'arguments':
+ [{'input': 'gatherNDInput'}, {'indices': 'gatherNDIndices'}],
+ 'outputs': 'gatherNDOutput'
+ }],
+ 'expectedOutputs': {
+ 'gatherNDOutput': {
+ 'data': [51.79948425292969, 41.94132614135742],
+ 'descriptor': {shape: [2], dataType: 'float32'}
+ }
+ }
+ }
+ },
+ {
+ 'name': 'gatherND float32 4D input and 1D int64 indices',
+ 'graph': {
+ 'inputs': {
+ 'gatherNDInput': {
+ 'data': [
+ -66.05901336669922, -68.9197006225586, -77.02045440673828,
+ -26.158037185668945, 89.0337142944336, -45.89653396606445,
+ 43.84803771972656, 48.81806945800781, 51.79948425292969,
+ 41.94132614135742, -1.1303654909133911, -50.42131042480469,
+ 90.2870101928711, 55.620765686035156, 44.92119598388672,
+ 56.828636169433594
+ ],
+ 'descriptor': {shape: [2, 2, 2, 2], dataType: 'float32'}
+ },
+ 'gatherNDIndices': {
+ 'data': [1, 0, 0],
+ 'descriptor': {shape: [3], dataType: 'int64'},
+ 'constant': true
+ }
+ },
+ 'operators': [{
+ 'name': 'gatherND',
+ 'arguments':
+ [{'input': 'gatherNDInput'}, {'indices': 'gatherNDIndices'}],
+ 'outputs': 'gatherNDOutput'
+ }],
+ 'expectedOutputs': {
+ 'gatherNDOutput': {
+ 'data': [51.79948425292969, 41.94132614135742],
+ 'descriptor': {shape: [2], dataType: 'float32'}
+ }
+ }
+ }
+ },
+ {
+ 'name': 'gatherND float32 4D input and 1D minimum indices',
+ 'graph': {
+ 'inputs': {
+ 'gatherNDInput': {
+ 'data': [
+ -66.05901336669922, -68.9197006225586, -77.02045440673828,
+ -26.158037185668945, 89.0337142944336, -45.89653396606445,
+ 43.84803771972656, 48.81806945800781, 51.79948425292969,
+ 41.94132614135742, -1.1303654909133911, -50.42131042480469,
+ 90.2870101928711, 55.620765686035156, 44.92119598388672,
+ 56.828636169433594
+ ],
+ 'descriptor': {shape: [2, 2, 2, 2], dataType: 'float32'}
+ },
+ 'gatherNDIndices': {
+ 'data': [-2, -2, -2],
+ 'descriptor': {shape: [3], dataType: 'int64'},
+ 'constant': true
+ }
+ },
+ 'operators': [{
+ 'name': 'gatherND',
+ 'arguments':
+ [{'input': 'gatherNDInput'}, {'indices': 'gatherNDIndices'}],
+ 'outputs': 'gatherNDOutput'
+ }],
+ 'expectedOutputs': {
+ 'gatherNDOutput': {
+ 'data': [-66.05901336669922, -68.9197006225586],
+ 'descriptor': {shape: [2], dataType: 'float32'}
+ }
+ }
+ }
+ },
+ {
+ 'name': 'gatherND float32 4D input and 1D maximum indices',
+ 'graph': {
+ 'inputs': {
+ 'gatherNDInput': {
+ 'data': [
+ -66.05901336669922, -68.9197006225586, -77.02045440673828,
+ -26.158037185668945, 89.0337142944336, -45.89653396606445,
+ 43.84803771972656, 48.81806945800781, 51.79948425292969,
+ 41.94132614135742, -1.1303654909133911, -50.42131042480469,
+ 90.2870101928711, 55.620765686035156, 44.92119598388672,
+ 56.828636169433594
+ ],
+ 'descriptor': {shape: [2, 2, 2, 2], dataType: 'float32'}
+ },
+ 'gatherNDIndices': {
+ 'data': [1, 1, 1],
+ 'descriptor': {shape: [3], dataType: 'int64'},
+ 'constant': true
+ }
+ },
+ 'operators': [{
+ 'name': 'gatherND',
+ 'arguments':
+ [{'input': 'gatherNDInput'}, {'indices': 'gatherNDIndices'}],
+ 'outputs': 'gatherNDOutput'
+ }],
+ 'expectedOutputs': {
+ 'gatherNDOutput': {
+ 'data': [44.92119598388672, 56.828636169433594],
+ 'descriptor': {shape: [2], dataType: 'float32'}
+ }
+ }
+ }
+ },
+ {
'name': 'gatherND float32 2D input and 2D negative indices',
'graph': {
'inputs': {
@@ -169,6 +309,41 @@ const gatherNDTests = [
}
}
}
+ },
+ {
+ 'name': 'gatherND float32 2D input and 2D out-of-bounds indices',
+ 'graph': {
+ 'inputs': {
+ 'gatherNDInput': {
+ 'data': [
+ -66.05901336669922, -68.9197006225586, -77.02045440673828,
+ -26.158037185668945, 89.0337142944336, -45.89653396606445,
+ 43.84803771972656, 48.81806945800781, 51.79948425292969,
+ 41.94132614135742, -1.1303654909133911, -50.42131042480469,
+ 90.2870101928711, 55.620765686035156, 44.92119598388672,
+ 56.828636169433594
+ ],
+ 'descriptor': {shape: [16, 1], dataType: 'float32'}
+ },
+ 'gatherNDIndices': {
+ 'data': [16, 20],
+ 'descriptor': {shape: [2, 1], dataType: 'int32'},
+ 'constant': true
+ }
+ },
+ 'operators': [{
+ 'name': 'gatherND',
+ 'arguments':
+ [{'input': 'gatherNDInput'}, {'indices': 'gatherNDIndices'}],
+ 'outputs': 'gatherNDOutput'
+ }],
+ 'expectedOutputs': {
+ 'gatherNDOutput': {
+ 'data': [56.828636169433594, 56.828636169433594],
+ 'descriptor': {shape: [2, 1], dataType: 'float32'}
+ }
+ }
+ }
}
];
diff --git a/tests/wpt/tests/webnn/conformance_tests/inputs-are-not-modified.https.any.js b/tests/wpt/tests/webnn/conformance_tests/inputs-are-not-modified.https.any.js
index ffd2d93a557..730941fbd8b 100644
--- a/tests/wpt/tests/webnn/conformance_tests/inputs-are-not-modified.https.any.js
+++ b/tests/wpt/tests/webnn/conformance_tests/inputs-are-not-modified.https.any.js
@@ -31,10 +31,10 @@ promise_test(async () => {
mlContext.createTensor({
dataType: 'float32',
shape: [4],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ
+ readable: true,
+ writable: true,
}),
- mlContext.createTensor(
- {dataType: 'float32', shape: [4], usage: MLTensorUsage.READ}),
+ mlContext.createTensor({dataType: 'float32', shape: [4], readable: true}),
builder.build({'output': outputOperand})
]);
@@ -66,10 +66,10 @@ promise_test(async () => {
mlContext.createTensor({
dataType: 'float32',
shape: [4],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ
+ readable: true,
+ writable: true,
}),
- mlContext.createTensor(
- {dataType: 'float32', shape: [4], usage: MLTensorUsage.READ}),
+ mlContext.createTensor({dataType: 'float32', shape: [4], readable: true}),
builder.build({'output': outputOperand})
]);
diff --git a/tests/wpt/tests/webnn/conformance_tests/logical_and.https.any.js b/tests/wpt/tests/webnn/conformance_tests/logical_and.https.any.js
index be379de157c..3d46c0b2406 100644
--- a/tests/wpt/tests/webnn/conformance_tests/logical_and.https.any.js
+++ b/tests/wpt/tests/webnn/conformance_tests/logical_and.https.any.js
@@ -370,8 +370,8 @@ const logicalAndTests = [
'expectedOutputs': {
'output': {
'data': [
- 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
- 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1
],
'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'}
}
diff --git a/tests/wpt/tests/webnn/conformance_tests/logical_or.https.any.js b/tests/wpt/tests/webnn/conformance_tests/logical_or.https.any.js
index f5eb21de729..3be3b0090f2 100644
--- a/tests/wpt/tests/webnn/conformance_tests/logical_or.https.any.js
+++ b/tests/wpt/tests/webnn/conformance_tests/logical_or.https.any.js
@@ -370,8 +370,8 @@ const logicalOrTests = [
'expectedOutputs': {
'output': {
'data': [
- 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1,
- 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1
+ 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
+ 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1
],
'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'}
}
diff --git a/tests/wpt/tests/webnn/conformance_tests/logical_xor.https.any.js b/tests/wpt/tests/webnn/conformance_tests/logical_xor.https.any.js
index b678b04065b..cab96c27237 100644
--- a/tests/wpt/tests/webnn/conformance_tests/logical_xor.https.any.js
+++ b/tests/wpt/tests/webnn/conformance_tests/logical_xor.https.any.js
@@ -20,7 +20,7 @@ const logicalXorTests = [
'descriptor': {shape: [], dataType: 'uint8'}
},
'inputB': {
- 'data': [1],
+ 'data': [0],
'descriptor': {shape: [], dataType: 'uint8'}
}
},
@@ -370,8 +370,8 @@ const logicalXorTests = [
'expectedOutputs': {
'output': {
'data': [
- 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0,
- 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0
+ 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0
],
'descriptor': {shape: [2, 2, 2, 3], dataType: 'uint8'}
}
diff --git a/tests/wpt/tests/webnn/conformance_tests/parallel-dispatch.https.any.js b/tests/wpt/tests/webnn/conformance_tests/parallel-dispatch.https.any.js
index dfdf70a6aa4..4051645771f 100644
--- a/tests/wpt/tests/webnn/conformance_tests/parallel-dispatch.https.any.js
+++ b/tests/wpt/tests/webnn/conformance_tests/parallel-dispatch.https.any.js
@@ -33,7 +33,8 @@ promise_test(async () => {
const operandDescriptor = {
dataType: 'float32',
shape: [1],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
};
const [mlGraph, inputTensor1, inputTensor2, outputTensor] =
@@ -73,7 +74,8 @@ promise_test(async () => {
const operandDescriptor = {
dataType: 'float32',
shape: [1],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
};
const mlGraph = await buildMulGraph(mlContext, operandDescriptor, 3);
@@ -101,7 +103,8 @@ promise_test(async () => {
const operandDescriptor = {
dataType: 'float32',
shape: [1],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
};
const mlGraph = await buildMulGraph(mlContext, operandDescriptor, 10);
@@ -140,7 +143,8 @@ promise_test(async () => {
const operandDescriptor = {
dataType: 'float32',
shape: [1],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
};
const mlGraph = await buildMulGraph(mlContext, operandDescriptor, 9);
@@ -178,7 +182,8 @@ promise_test(async () => {
const operandDescriptor = {
dataType: 'float32',
shape: [1],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
};
const mlGraph = await buildMulGraph(mlContext, operandDescriptor, 2);
@@ -211,7 +216,8 @@ promise_test(async () => {
const operandDescriptor = {
dataType: 'float32',
shape: [1],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
};
// write/write...
@@ -250,7 +256,8 @@ promise_test(async () => {
const operandDescriptor = {
dataType: 'float32',
shape: [1],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
};
// write/write...
@@ -288,7 +295,8 @@ promise_test(async () => {
const operandDescriptor = {
dataType: 'float32',
shape: [1],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
};
const graphs = await Promise.all([3, 2].map(async (multiplier) => {
@@ -324,7 +332,8 @@ promise_test(async () => {
const operandDescriptor = {
dataType: 'float32',
shape: [1],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
};
const graphs = await Promise.all([2, 3].map(async (multiplier) => {
diff --git a/tests/wpt/tests/webnn/conformance_tests/quantizeLinear.https.any.js b/tests/wpt/tests/webnn/conformance_tests/quantizeLinear.https.any.js
index 0871c881b71..8aa9d7f3bcc 100644
--- a/tests/wpt/tests/webnn/conformance_tests/quantizeLinear.https.any.js
+++ b/tests/wpt/tests/webnn/conformance_tests/quantizeLinear.https.any.js
@@ -18,7 +18,7 @@
const getQuantizeLinearPrecisionTolerance = (graphResources) => {
- const toleranceValueDict = {int8: 1, uint8: 1};
+ const toleranceValueDict = {int8: 1, uint8: 1, int4: 1, uint4: 1};
const expectedDataType =
getExpectedDataTypeOfSingleOutput(graphResources.expectedOutputs);
return {metricType: 'ULP', value: toleranceValueDict[expectedDataType]};
@@ -143,6 +143,191 @@ const quantizeLinearTests = [
}
}
}
+ },
+ {
+ 'name':
+ 'quantizeLinear float32 tensor with int4 zeroPoint which has odd size',
+ 'graph': {
+ 'inputs': {
+ 'quantizeLinearInput': {
+ 'data': [4.794857501983643],
+ 'descriptor': {shape: [], dataType: 'float32'},
+ 'constant': true
+ },
+ 'quantizeLinearScale': {
+ 'data': [1.1202747821807861],
+ 'descriptor': {shape: [], dataType: 'float32'},
+ 'constant': true
+ },
+ 'quantizeLinearZeroPoint': {
+ 'data': [-4],
+ 'descriptor': {shape: [], dataType: 'int4'},
+ 'constant': true
+ }
+ },
+ 'operators': [{
+ 'name': 'quantizeLinear',
+ 'arguments': [
+ {'input': 'quantizeLinearInput'}, {'scale': 'quantizeLinearScale'},
+ {'zeroPoint': 'quantizeLinearZeroPoint'}
+ ],
+ 'outputs': 'quantizeLinearOutput'
+ }],
+ 'expectedOutputs': {
+ 'quantizeLinearOutput':
+ {'data': [-1], 'descriptor': {shape: [], dataType: 'int4'}}
+ }
+ }
+ },
+ {
+ 'name':
+ 'quantizeLinear float32 tensor with int4 zeroPoint which has even size',
+ 'graph': {
+ 'inputs': {
+ 'quantizeLinearInput': {
+ 'data': [4.794857501983643, 3.23434354545],
+ 'descriptor': {shape: [2], dataType: 'float32'},
+ 'constant': true
+ },
+ 'quantizeLinearScale': {
+ 'data': [1.1202747821807861],
+ 'descriptor': {shape: [], dataType: 'float32'},
+ 'constant': true
+ },
+ 'quantizeLinearZeroPoint': {
+ 'data': [-6, -5],
+ 'descriptor': {shape: [2], dataType: 'int4'},
+ 'constant': true
+ }
+ },
+ 'operators': [{
+ 'name': 'quantizeLinear',
+ 'arguments': [
+ {'input': 'quantizeLinearInput'}, {'scale': 'quantizeLinearScale'},
+ {'zeroPoint': 'quantizeLinearZeroPoint'}
+ ],
+ 'outputs': 'quantizeLinearOutput'
+ }],
+ 'expectedOutputs': {
+ 'quantizeLinearOutput':
+ {'data': [-2, -2], 'descriptor': {shape: [2], dataType: 'int4'}}
+ }
+ }
+ },
+ {
+ 'name':
+ 'quantizeLinear float32 2D tensor with int4 zeroPoint which has even size',
+ 'graph': {
+ 'inputs': {
+ 'quantizeLinearInput': {
+ 'data': [
+ 4.794857501983643, 3.23434354545, 2.794857501983643,
+ 5.794857501983643, 0, 7.23434354545
+ ],
+ 'descriptor': {shape: [3, 2], dataType: 'float32'},
+ 'constant': true
+ },
+ 'quantizeLinearScale': {
+ 'data': [1.1202747821807861, 2.1202747821807861],
+ 'descriptor': {shape: [2], dataType: 'float32'},
+ 'constant': true
+ },
+ 'quantizeLinearZeroPoint': {
+ 'data': [-6, -5],
+ 'descriptor': {shape: [2], dataType: 'int4'},
+ 'constant': true
+ }
+ },
+ 'operators': [{
+ 'name': 'quantizeLinear',
+ 'arguments': [
+ {'input': 'quantizeLinearInput'}, {'scale': 'quantizeLinearScale'},
+ {'zeroPoint': 'quantizeLinearZeroPoint'}
+ ],
+ 'outputs': 'quantizeLinearOutput'
+ }],
+ 'expectedOutputs': {
+ 'quantizeLinearOutput': {
+ 'data': [-2, -3, -4, -3, -5, -2],
+ 'descriptor': {shape: [3, 2], dataType: 'int4'}
+ }
+ }
+ }
+ },
+ {
+ 'name':
+ 'quantizeLinear float32 tensor with uint4 zeroPoint which has odd size',
+ 'graph': {
+ 'inputs': {
+ 'quantizeLinearInput': {
+ 'data': [
+ 4.794857501983643, 2.794857501983643, 1.794857501983643, 0,
+ 3.794857501983643
+ ],
+ 'descriptor': {shape: [5], dataType: 'float32'},
+ 'constant': true
+ },
+ 'quantizeLinearScale': {
+ 'data': [1.1202747821807861],
+ 'descriptor': {shape: [], dataType: 'float32'},
+ 'constant': true
+ },
+ 'quantizeLinearZeroPoint': {
+ 'data': [12],
+ 'descriptor': {shape: [], dataType: 'uint4'},
+ 'constant': true
+ }
+ },
+ 'operators': [{
+ 'name': 'quantizeLinear',
+ 'arguments': [
+ {'input': 'quantizeLinearInput'}, {'scale': 'quantizeLinearScale'},
+ {'zeroPoint': 'quantizeLinearZeroPoint'}
+ ],
+ 'outputs': 'quantizeLinearOutput'
+ }],
+ 'expectedOutputs': {
+ 'quantizeLinearOutput': {
+ 'data': [16, 14, 13, 12, 15],
+ 'descriptor': {shape: [5], dataType: 'uint4'}
+ }
+ }
+ }
+ },
+ {
+ 'name':
+ 'quantizeLinear float32 tensor with uint4 zeroPoint which has even size',
+ 'graph': {
+ 'inputs': {
+ 'quantizeLinearInput': {
+ 'data': [4.794857501983643, 3.23434354545],
+ 'descriptor': {shape: [2], dataType: 'float32'},
+ 'constant': true
+ },
+ 'quantizeLinearScale': {
+ 'data': [1.1202747821807861],
+ 'descriptor': {shape: [], dataType: 'float32'},
+ 'constant': true
+ },
+ 'quantizeLinearZeroPoint': {
+ 'data': [1, 5],
+ 'descriptor': {shape: [2], dataType: 'uint4'},
+ 'constant': true
+ }
+ },
+ 'operators': [{
+ 'name': 'quantizeLinear',
+ 'arguments': [
+ {'input': 'quantizeLinearInput'}, {'scale': 'quantizeLinearScale'},
+ {'zeroPoint': 'quantizeLinearZeroPoint'}
+ ],
+ 'outputs': 'quantizeLinearOutput'
+ }],
+ 'expectedOutputs': {
+ 'quantizeLinearOutput':
+ {'data': [5, 8], 'descriptor': {shape: [2], dataType: 'uint4'}}
+ }
+ }
}
];
diff --git a/tests/wpt/tests/webnn/conformance_tests/scatterElements.https.any.js b/tests/wpt/tests/webnn/conformance_tests/scatterElements.https.any.js
new file mode 100644
index 00000000000..561260d47ec
--- /dev/null
+++ b/tests/wpt/tests/webnn/conformance_tests/scatterElements.https.any.js
@@ -0,0 +1,91 @@
+// META: title=test WebNN API scatterElements operation
+// META: global=window,dedicatedworker
+// META: variant=?cpu
+// META: variant=?gpu
+// META: variant=?npu
+// META: script=../resources/utils.js
+// META: timeout=long
+
+'use strict';
+
+const getScatterElementsPrecisionTolerance = () => {
+ return {metricType: 'ULP', value: 0};
+};
+
+const scatterElementsTests = [
+ {
+ 'name': 'Scatter elements along axis 0',
+ 'graph': {
+ 'inputs': {
+ 'input': {
+ 'data': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
+ 'descriptor': {shape: [3, 3], dataType: 'float32'}
+ },
+ 'indices': {
+ 'data': [1, 0, 2, 0, 2, 1],
+ 'descriptor': {shape: [2, 3], dataType: 'int32'},
+ },
+ 'updates': {
+ 'data': [1.0, 1.1, 1.2, 2.0, 2.1, 2.2],
+ 'descriptor': {shape: [2, 3], dataType: 'float32'}
+ }
+ },
+ 'operators': [{
+ 'name': 'scatterElements',
+ 'arguments': [
+ {'input': 'input'}, {'indices': 'indices'}, {'updates': 'updates'},
+ {'options': {'axis': 0}}
+ ],
+ 'outputs': 'output'
+ }],
+ 'expectedOutputs': {
+ 'output': {
+ 'data': [2.0, 1.1, 0.0, 1.0, 0.0, 2.2, 0.0, 2.1, 1.2],
+ 'descriptor': {shape: [3, 3], dataType: 'float32'}
+ }
+ }
+ }
+ },
+ {
+ 'name': 'Scatter elements along axis 1',
+ 'graph': {
+ 'inputs': {
+ 'input': {
+ 'data': [1.0, 2.0, 3.0, 4.0, 5.0],
+ 'descriptor': {shape: [1, 5], dataType: 'float32'}
+ },
+ 'indices': {
+ 'data': [1, 3],
+ 'descriptor': {shape: [1, 2], dataType: 'int32'},
+ },
+ 'updates': {
+ 'data': [1.1, 2.1],
+ 'descriptor': {shape: [1, 2], dataType: 'float32'}
+ }
+ },
+ 'operators': [{
+ 'name': 'scatterElements',
+ 'arguments': [
+ {'input': 'input'}, {'indices': 'indices'}, {'updates': 'updates'},
+ {'options': {'axis': 1}}
+ ],
+ 'outputs': 'output'
+ }],
+ 'expectedOutputs': {
+ 'output': {
+ 'data': [1.0, 1.1, 3.0, 2.1, 5.0],
+ 'descriptor': {shape: [1, 5], dataType: 'float32'}
+ }
+ }
+ }
+ }
+];
+
+if (navigator.ml) {
+ scatterElementsTests.forEach((test) => {
+ webnn_conformance_test(
+ buildGraphAndCompute, getScatterElementsPrecisionTolerance, test);
+ });
+} else {
+ test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
+}
diff --git a/tests/wpt/tests/webnn/conformance_tests/tensor.https.any.js b/tests/wpt/tests/webnn/conformance_tests/tensor.https.any.js
index 51905bbaf3c..0bc51614608 100644
--- a/tests/wpt/tests/webnn/conformance_tests/tensor.https.any.js
+++ b/tests/wpt/tests/webnn/conformance_tests/tensor.https.any.js
@@ -33,7 +33,13 @@ const sizeOfDescriptor = (descriptor) => {
};
const getDescriptorFromTensor = (tensor) => {
- return {dataType: tensor.dataType, shape: tensor.shape, usage: tensor.usage};
+ return {
+ dataType: tensor.dataType,
+ shape: tensor.shape,
+ readable: tensor.readable,
+ writable: tensor.writable,
+ importableToWebGPU: tensor.importableToWebGPU,
+ };
};
@@ -162,7 +168,7 @@ const testWriteTensor = (testName) => {
const tensorDescriptor = {
dataType: 'int32',
shape: [1],
- usage: MLTensorUsage.WRITE,
+ writable: true,
};
let mlTensor = await mlContext.createTensor(tensorDescriptor);
@@ -211,7 +217,7 @@ const testWriteTensor = (testName) => {
const tensorDescriptor = {
dataType: 'int32',
shape: [2, 2],
- usage: MLTensorUsage.WRITE,
+ writable: true,
};
let mlTensor = await mlContext.createTensor(tensorDescriptor);
@@ -228,7 +234,7 @@ const testWriteTensor = (testName) => {
const tensorDescriptor = {
dataType: 'int32',
shape: [2, 3],
- usage: MLTensorUsage.WRITE,
+ writable: true,
};
let mlTensor = await mlContext.createTensor(tensorDescriptor);
@@ -247,7 +253,8 @@ const testWriteTensor = (testName) => {
let mlTensor = await mlContext.createTensor({
dataType: 'int32',
shape: [1],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
});
// Initialize the tensor.
@@ -270,7 +277,8 @@ const testWriteTensor = (testName) => {
const tensorDescriptor = {
dataType: 'int32',
shape: [2, 2],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
};
let mlTensor = await mlContext.createTensor(tensorDescriptor);
@@ -321,7 +329,7 @@ const testReadTensor = (testName) => {
let mlTensor = await mlContext.createTensor({
dataType: 'int32',
shape: [2, 2],
- usage: MLTensorUsage.READ,
+ readable: true,
});
// Reading a destroyed MLTensor should reject.
@@ -335,7 +343,7 @@ const testReadTensor = (testName) => {
let mlTensor = await mlContext.createTensor({
dataType: 'int32',
shape: [2, 3],
- usage: MLTensorUsage.READ,
+ readable: true,
});
let promise = mlContext.readTensor(mlTensor);
@@ -351,7 +359,7 @@ const testReadTensor = (testName) => {
let mlTensor = await mlContext.createTensor({
dataType: 'int32',
shape: [1024],
- usage: MLTensorUsage.READ,
+ readable: true,
});
await assert_tensor_data_equals(mlContext, mlTensor, new Uint32Array(1024));
@@ -361,7 +369,8 @@ const testReadTensor = (testName) => {
let mlTensor = await mlContext.createTensor({
dataType: 'int32',
shape: [1],
- usage: MLTensorUsage.READ | MLTensorUsage.WRITE,
+ readable: true,
+ writable: true,
});
// Initialize the tensor.
@@ -377,7 +386,8 @@ const testReadTensor = (testName) => {
let mlTensor = await mlContext.createTensor({
dataType: 'int32',
shape: [1],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
});
// Initialize the tensor.
@@ -395,7 +405,8 @@ const testReadTensor = (testName) => {
let mlTensor = await mlContext.createTensor({
dataType: 'int32',
shape: [1],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
});
// Initialize the tensor.
@@ -413,7 +424,8 @@ const testReadTensor = (testName) => {
let mlTensor = await mlContext.createTensor({
dataType: 'int32',
shape: [1],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
});
// Initialize the tensor.
@@ -431,7 +443,8 @@ const testReadTensor = (testName) => {
let mlTensor = await mlContext.createTensor({
dataType: 'int32',
shape: [1],
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
});
const inputData = [0xAA, 0xAA, 0xAA, 0xAA];
@@ -448,7 +461,7 @@ const testReadTensor = (testName) => {
const tensorDescriptor = {
dataType: 'int32',
shape: [2, 3],
- usage: MLTensorUsage.READ,
+ readable: true,
};
let mlTensor = await mlContext.createTensor(tensorDescriptor);
@@ -484,7 +497,8 @@ const testDispatchTensor = (testName) => {
const tensorDescriptor = {
dataType: 'float32',
shape: shape,
- usage: MLTensorUsage.WRITE | MLTensorUsage.READ,
+ readable: true,
+ writable: true,
};
const lhsOperand = builder.input('lhs', tensorDescriptor);
const rhsOperand = builder.input('rhs', tensorDescriptor);
diff --git a/tests/wpt/tests/webnn/resources/utils.js b/tests/wpt/tests/webnn/resources/utils.js
index 460fe461154..973c16baca7 100644
--- a/tests/wpt/tests/webnn/resources/utils.js
+++ b/tests/wpt/tests/webnn/resources/utils.js
@@ -85,9 +85,12 @@ const TypedArrayDict = {
uint32: Uint32Array,
int8: Int8Array,
uint8: Uint8Array,
+ int4: Uint8Array,
+ uint4: Uint8Array,
};
-const kIntTypes = ['uint8', 'int8', 'uint32', 'int32', 'uint64', 'int64'];
+const kIntTypes =
+ ['uint4', 'int4', 'uint8', 'int8', 'uint32', 'int32', 'uint64', 'int64'];
const kFloatTypes = ['float16', 'float32'];
const findCompatibleType = (dataType, supportedTypes) => {
@@ -204,6 +207,27 @@ const getTypedArrayData = (type, size, data) => {
for (let i = 0; i < data.length; i++) {
outData[i] = BigInt(data[i]);
}
+ } else if (type === 'uint4' || type === 'int4') {
+ // The first nybble is stored in the first bits 0-3, and later bits 4-7
+ // store the later nybble. The data is packed, without any padding between
+ // dimensions. For example: an array of uint4:
+ // size = [2,5]
+ // values = [1,2,3,4,5,6,7,8,9,10]
+ // Would yield 5 hex bytes:
+ // Uint8Array.of(0x21, 0x43, 0x65, 0x87, 0xA9);
+ const array = new TypedArrayDict[type](Math.ceil(size / 2));
+ let i = 0;
+ while (i < size - 1) {
+ const packedByte = ((data[i + 1] & 0xF) << 4) | (data[i] & 0xF);
+ array[Math.floor(i / 2)] = packedByte;
+ i = i + 2;
+ }
+ // Handle the odd size.
+ if (i === size - 1) {
+ const packedByte = data[i] & 0xF;
+ array[Math.floor(i / 2)] = packedByte;
+ }
+ return array;
} else {
if (typeof (data) === 'number' && size > 1) {
return new TypedArrayDict[type](size).fill(data);
@@ -282,7 +306,8 @@ const assert_array_approx_equals_ulp = (actual, expected, nulp, dataType, descri
expectedBitwise = BigUint64Array(expected[i]);
} else if (
dataType === 'int8' || dataType === 'uint8' || dataType === 'int32' ||
- dataType === 'uint32') {
+ dataType === 'uint32' || dataType === 'int4' ||
+ dataType === 'uint4') {
actualBitwise = actual[i];
expectedBitwise = expected[i];
}
@@ -365,6 +390,44 @@ const assertResultsEquals =
kMaximumIndexToValidate, sizeOfShape(expectedDescriptor.shape));
expectedData = new Array(size).fill(expectedData);
outputData = outputData.subarray(0, kMaximumIndexToValidate);
+ } else if (
+ expectedDescriptor.dataType === 'uint4' ||
+ expectedDescriptor.dataType === 'int4') {
+ // The int4/uint4 data were packed in Uint8Array.
+ // The first nybble and later nybble of one int8/uint8 value store two
+ // consecutive 4-bits values separately. After unpacking each 4-bits
+ // value, the unpacked int4 value is stored in an element of
+ // Int8Array, and the unpacked uint4 value is stored in an element of
+ // Uint8Array. For example: an array of uint4:
+ // size = [1, 5]
+ // Uint8Array.of(0x21, 0x43, 0x65, 0x87, 0xA9)
+ // Would yield 5 * 2 uint4 data:
+ // Uint8Array.of(1,2,3,4,5,6,7,8,9,10);
+ // Another example: an array of int4:
+ // size = [1, 5]
+ // Uint8Array.of(0xA9, 0xCB, 0xED, 0x0F, 0x21)
+ // Would yield 5 * 2 int4 data:
+ // Int8Array.of(-7, -6, -5, -4, -3, -2, -1, 0, 1, 2);
+ let newOutputData;
+ if (expectedDescriptor.dataType === 'uint4') {
+ newOutputData =
+ new Uint8Array(sizeOfShape(expectedDescriptor.shape));
+ } else {
+ newOutputData =
+ new Int8Array(sizeOfShape(expectedDescriptor.shape));
+ }
+ const signMask =
+ (expectedDescriptor.dataType === 'int4') ? 0x08 : 0x00;
+ for (let i = 0; i < sizeOfShape(expectedDescriptor.shape); i++) {
+ const byteIndex = Math.floor(i / 2);
+ let value = (outputData[byteIndex] >> ((i & 1) << 2)) & 0xF;
+ // Handle the negative numbers.
+ if (value & signMask) {
+ value |= 0xF0;
+ }
+ newOutputData[i] = value;
+ }
+ outputData = newOutputData;
}
doAssert(
operatorName, outputData, expectedData, metricType, toleranceValue,
@@ -422,8 +485,13 @@ const prepareOutputsForGraph = (outputs, resources) => {
const descriptor = resources[operandName].descriptor;
const dataType =
descriptor.castedType ? descriptor.castedType : descriptor.dataType;
- outputs[operandName] =
- new TypedArrayDict[dataType](sizeOfShape(descriptor.shape));
+ if (dataType === 'int4' || dataType === 'uint4') {
+ outputs[operandName] = new TypedArrayDict[dataType](
+ Math.ceil(sizeOfShape(descriptor.shape) / 2));
+ } else {
+ outputs[operandName] =
+ new TypedArrayDict[dataType](sizeOfShape(descriptor.shape));
+ }
}
};
diff --git a/tests/wpt/tests/webnn/validation_tests/constant.https.any.js b/tests/wpt/tests/webnn/validation_tests/constant.https.any.js
index b9b75e372b0..fc0243197db 100644
--- a/tests/wpt/tests/webnn/validation_tests/constant.https.any.js
+++ b/tests/wpt/tests/webnn/validation_tests/constant.https.any.js
@@ -11,13 +11,6 @@ const tests = [
// Tests for constant(descriptor, bufferView)
{
name:
- '[constant] Test building a 0-D scalar constant without presenting dimensions',
- descriptor: {dataType: 'float32'},
- bufferView: {type: Float32Array, byteLength: 1 * 4},
- output: {dataType: 'float32', shape: []}
- },
- {
- name:
'[constant] Test building a 0-D scalar constant with empty dimensions',
descriptor: {dataType: 'float32', shape: []},
bufferView: {type: Float32Array, byteLength: 1 * 4},
diff --git a/tests/wpt/tests/webnn/validation_tests/destroyContext.https.any.js b/tests/wpt/tests/webnn/validation_tests/destroyContext.https.any.js
index b4027e23dba..abed6b09bde 100644
--- a/tests/wpt/tests/webnn/validation_tests/destroyContext.https.any.js
+++ b/tests/wpt/tests/webnn/validation_tests/destroyContext.https.any.js
@@ -135,7 +135,7 @@ promise_test(async t => {
const tensor = await context.createTensor({
dataType: 'float32',
shape: [1],
- usage: MLTensorUsage.READ,
+ readable: true,
});
context.destroy();
promise_rejects_dom(t, 'InvalidStateError', context.readTensor(tensor));
@@ -146,7 +146,7 @@ promise_test(async t => {
const tensor = await context.createTensor({
dataType: 'float32',
shape: [1],
- usage: MLTensorUsage.READ,
+ readable: true,
});
let promise = context.readTensor(tensor);
context.destroy();
@@ -161,7 +161,7 @@ promise_test(async t => {
const tensor = await context.createTensor({
dataType: 'float32',
shape: [1],
- usage: MLTensorUsage.WRITE,
+ writable: true,
});
let arrayBuffer = new ArrayBuffer(4);
context.destroy();
diff --git a/tests/wpt/tests/webnn/validation_tests/destroyGraph.https.any.js b/tests/wpt/tests/webnn/validation_tests/destroyGraph.https.any.js
index f7eb01eafef..4d883e9f3c3 100644
--- a/tests/wpt/tests/webnn/validation_tests/destroyGraph.https.any.js
+++ b/tests/wpt/tests/webnn/validation_tests/destroyGraph.https.any.js
@@ -110,17 +110,17 @@ promise_test(async t => {
const lhsTensor = await context.createTensor({
dataType: 'float32',
shape: [1],
- usage: MLTensorUsage.WRITE,
+ writable: true,
});
const rhsTensor = await context.createTensor({
dataType: 'float32',
shape: [1],
- usage: MLTensorUsage.WRITE,
+ writable: true,
});
const outputTensor = await context.createTensor({
dataType: 'float32',
shape: [1],
- usage: MLTensorUsage.READ,
+ readable: true,
});
// Initialize inputs
const inputData = new Float32Array(1).fill(2.0);
diff --git a/tests/wpt/tests/webnn/validation_tests/input.https.any.js b/tests/wpt/tests/webnn/validation_tests/input.https.any.js
index 0649c67f086..b5b257d8bb0 100644
--- a/tests/wpt/tests/webnn/validation_tests/input.https.any.js
+++ b/tests/wpt/tests/webnn/validation_tests/input.https.any.js
@@ -10,14 +10,7 @@
// Tests for input(name, descriptor)
const tests = [
{
- testName:
- '[input] Test building a 0-D scalar input without presenting dimensions',
- name: 'input',
- descriptor: {dataType: 'float32'},
- output: {dataType: 'float32', shape: []},
- },
- {
- testName: '[input] Test building a 0-D scalar input with empty dimensions',
+ testName: '[input] Test building a 0-D scalar input with empty shape',
name: 'input',
descriptor: {dataType: 'float32', shape: []},
output: {dataType: 'float32', shape: []},
diff --git a/tests/wpt/tests/webnn/validation_tests/scatterElements.https.any.js b/tests/wpt/tests/webnn/validation_tests/scatterElements.https.any.js
new file mode 100644
index 00000000000..15551b2bbe5
--- /dev/null
+++ b/tests/wpt/tests/webnn/validation_tests/scatterElements.https.any.js
@@ -0,0 +1,150 @@
+// META: title=validation tests for WebNN API scatterElements operation
+// META: global=window,dedicatedworker
+// META: variant=?cpu
+// META: variant=?gpu
+// META: variant=?npu
+// META: script=../resources/utils_validation.js
+
+'use strict';
+
+const tests = [
+ {
+ name: '[scatterElements] Test scatterElements with default options',
+ input: {dataType: 'float32', shape: [3, 3]},
+ indices: {dataType: 'int32', shape: [2, 3]},
+ updates: {dataType: 'float32', shape: [2, 3]},
+ output: {dataType: 'float32', shape: [3, 3]}
+ },
+ {
+ name: '[scatterElements] Test scatterElements with axis = 0',
+ input: {dataType: 'float32', shape: [3, 3]},
+ indices: {dataType: 'int32', shape: [2, 3]},
+ updates: {dataType: 'float32', shape: [2, 3]},
+ axis: 0,
+ output: {dataType: 'float32', shape: [3, 3]}
+ },
+ {
+ name: '[scatterElements] Test scatterElements with axis = 1',
+ input: {dataType: 'float32', shape: [3, 3]},
+ indices: {dataType: 'int32', shape: [3, 2]},
+ updates: {dataType: 'float32', shape: [3, 2]},
+ axis: 1,
+ output: {dataType: 'float32', shape: [3, 3]}
+ },
+ {
+ name: '[scatterElements] Throw if axis is greater than input rank',
+ input: {dataType: 'float32', shape: [3, 3]},
+ indices: {dataType: 'int32', shape: [2, 3]},
+ updates: {dataType: 'float32', shape: [2, 3]},
+ axis: 2
+ },
+ {
+ name:
+ '[scatterElements] Throw if updates tensor data type is not the same as input data type',
+ input: {dataType: 'float32', shape: [3, 3]},
+ indices: {dataType: 'int32', shape: [2, 3]},
+ updates: {dataType: 'float16', shape: [2, 3]},
+ },
+ {
+ name: '[scatterElements] Throw if input, indices and updates are scalar',
+ input: {dataType: 'float32', shape: []},
+ indices: {dataType: 'int32', shape: []},
+ updates: {dataType: 'float32', shape: []},
+ },
+ {
+ name:
+ '[scatterElements] Throw if indices rank is not the same as input rank',
+ input: {dataType: 'float32', shape: [3, 3]},
+ indices: {dataType: 'int32', shape: [2, 3, 3]},
+ updates: {dataType: 'float32', shape: [2, 3, 3]},
+ },
+ {
+ name:
+ '[scatterElements] Throw if indices size is not the same as input size along axis 1',
+ input: {dataType: 'float32', shape: [3, 3]},
+ indices: {dataType: 'int32', shape: [2, 4]},
+ updates: {dataType: 'float32', shape: [2, 4]},
+ axis: 0
+ },
+ {
+ name:
+ '[scatterElements] Throw if indices size is not the same as input size along axis 0',
+ input: {dataType: 'float32', shape: [3, 3]},
+ indices: {dataType: 'int32', shape: [2, 2]},
+ updates: {dataType: 'float32', shape: [2, 2]},
+ axis: 1
+ },
+ {
+ name:
+ '[scatterElements] Throw if indices rank is not the same as updates rank',
+ input: {dataType: 'float32', shape: [3, 3]},
+ indices: {dataType: 'int32', shape: [2, 3]},
+ updates: {dataType: 'float32', shape: [2, 3, 3]},
+ },
+ {
+ name:
+ '[scatterElements] Throw if indices shape is not the same as updates shape',
+ input: {dataType: 'float32', shape: [3, 3]},
+ indices: {dataType: 'int32', shape: [2, 3]},
+ updates: {dataType: 'float32', shape: [2, 4]},
+ }
+];
+
+tests.forEach(
+ test => promise_test(async t => {
+ const builder = new MLGraphBuilder(context);
+ const input = builder.input('input', test.input);
+ const indices = builder.input('indices', test.indices);
+ const updates = builder.input('updates', test.updates);
+
+ const options = {};
+ if (test.axis) {
+ options.axis = test.axis;
+ }
+
+ if (test.output) {
+ const output =
+ builder.scatterElements(input, indices, updates, options);
+ assert_equals(output.dataType(), test.output.dataType);
+ assert_array_equals(output.shape(), test.output.shape);
+ } else {
+ const label = 'a_scatter_elements'
+ options.label = label;
+ const regexp = new RegExp('\\[' + label + '\\]');
+ assert_throws_with_label(
+ () => builder.scatterElements(input, indices, updates, options),
+ regexp);
+ }
+ }, test.name));
+
+multi_builder_test(async (t, builder, otherBuilder) => {
+ const input =
+ otherBuilder.input('input', {dataType: 'float32', shape: [3, 3]});
+ const indices = builder.input('indices', {dataType: 'int32', shape: [2, 3]});
+ const updates =
+ builder.input('updates', {dataType: 'float32', shape: [2, 3]});
+
+ assert_throws_js(
+ TypeError, () => builder.scatterElements(input, indices, updates));
+}, '[scatterElements] Throw if input is from another builder');
+
+multi_builder_test(async (t, builder, otherBuilder) => {
+ const input = builder.input('input', {dataType: 'float32', shape: [3, 3]});
+ const indices =
+ otherBuilder.input('indices', {dataType: 'int32', shape: [2, 3]});
+ const updates =
+ builder.input('updates', {dataType: 'float32', shape: [2, 3]});
+
+ assert_throws_js(
+ TypeError, () => builder.scatterElements(input, indices, updates));
+}, '[scatterElements] Throw if indices is from another builder');
+
+multi_builder_test(async (t, builder, otherBuilder) => {
+ const input = builder.input('input', {dataType: 'float32', shape: [3, 3]});
+ const indices = builder.input('indices', {dataType: 'int32', shape: [2, 3]});
+ const updates =
+ otherBuilder.input('updates', {dataType: 'float32', shape: [2, 3]});
+
+ assert_throws_js(
+ TypeError, () => builder.scatterElements(input, indices, updates));
+}, '[scatterElements] Throw if updates is from another builder');
diff --git a/tests/wpt/tests/webrtc/RTCPeerConnection-getStats-timestamp.https.html b/tests/wpt/tests/webrtc/RTCPeerConnection-getStats-timestamp.https.html
index 9345d5838d1..af975219018 100644
--- a/tests/wpt/tests/webrtc/RTCPeerConnection-getStats-timestamp.https.html
+++ b/tests/wpt/tests/webrtc/RTCPeerConnection-getStats-timestamp.https.html
@@ -11,6 +11,11 @@
// performance.now()` diverge inside of WPTs, so implementers beware that these
// tests may give FALSE positives if `timestamp` is implemented as Wall Clock.
+// TODO: crbug.com/372749742 - Timestamps from RTCStats differs slightly from
+// performance.timeOrigin + performance.now(). We add an epsilon to the
+// timestamp checks as a workaround to avoid making the tests flaky.
+const kTimeEpsilon = 0.2;
+
promise_test(async t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
@@ -25,8 +30,10 @@ promise_test(async t => {
const peerConnectionStats =
report.values().find(stats => stats.type == 'peer-connection');
- assert_less_than_equal(t0, peerConnectionStats.timestamp);
- assert_less_than_equal(peerConnectionStats.timestamp, t1);
+ assert_less_than_equal(t0, peerConnectionStats.timestamp + kTimeEpsilon,
+ 't0 < timestamp');
+ assert_less_than_equal(peerConnectionStats.timestamp, t1 + kTimeEpsilon,
+ 'timestamp < t1');
}, 'RTCStats.timestamp is expressed as Performance time');
promise_test(async t => {
@@ -63,7 +70,9 @@ promise_test(async t => {
}
const t1 = performance.timeOrigin + performance.now();
- assert_less_than_equal(t0, remoteInboundRtp.timestamp);
- assert_less_than_equal(remoteInboundRtp.timestamp, t1);
+ assert_less_than_equal(t0, remoteInboundRtp.timestamp + kTimeEpsilon,
+ 't0 < timestamp');
+ assert_less_than_equal(remoteInboundRtp.timestamp, t1 + kTimeEpsilon,
+ 'timestamp < t1');
}, 'RTCRemoteInboundRtpStats.timestamp is expressed as Performance time');
</script>
diff --git a/tests/wpt/tests/webrtc/RTCRtpEncodingParameters-codec-opus-stereo.https.html b/tests/wpt/tests/webrtc/RTCRtpEncodingParameters-codec-opus-stereo.https.html
new file mode 100644
index 00000000000..49335eada4f
--- /dev/null
+++ b/tests/wpt/tests/webrtc/RTCRtpEncodingParameters-codec-opus-stereo.https.html
@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>RTCRtpEncodingParameters codec opus stereo</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+const kNumChannelsMono = 1;
+const kNumChannelsStereo = 2;
+const kAudioProcessingEnabled = true;
+const kAudioProcessingDisabled = false;
+
+// In some implementations (e.g. Chrome), whether or not audio processing is
+// used may affect the number of channels we get.
+// To isolate this factor from the test, we constrain both channels and APM.
+function getAudioConstraints(numChannels, audioProcessing) {
+ return {
+ channelCount: {exact: numChannels},
+ autoGainControl: audioProcessing,
+ echoCancellation: audioProcessing,
+ noiseSuppression: audioProcessing
+ };
+}
+
+// Polls getSettings() until `channelCount` is known.
+// Remote tracks don't populate their `channelCount` until media is received.
+async function pollChannelCount(t, track) {
+ while (true) {
+ if (track.getSettings().channelCount != undefined) {
+ break;
+ }
+ await new Promise(r => t.step_timeout(r, 50));
+ }
+ return track.getSettings().channelCount;
+}
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate);
+ pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate);
+
+ // Open microphone as mono.
+ const stream = await navigator.mediaDevices.getUserMedia(
+ {audio: getAudioConstraints(kNumChannelsMono, kAudioProcessingEnabled)});
+ const [track] = stream.getTracks();
+ t.add_cleanup(() => track.stop());
+ // Prerequisite of the test.
+ assert_equals(track.getSettings().channelCount, 1,
+ 'Can open track in mono');
+
+ // Negotiate opus.
+ const transceiver = pc1.addTransceiver(track);
+ transceiver.setCodecPreferences(
+ RTCRtpSender.getCapabilities('audio').codecs.filter(
+ codec => codec.mimeType == 'audio/opus'));
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription();
+ await pc1.setRemoteDescription(pc2.localDescription);
+
+ const [receiver] = pc2.getReceivers();
+ const remoteTrack = receiver.track;
+ // Attaching the track to an audio element is needed for media to flow,
+ // otherwise the `channelCount` is never known.
+ const audio = document.createElement('audio');
+ audio.srcObject = new MediaStream();
+ audio.srcObject.addTrack(remoteTrack);
+ assert_equals(await pollChannelCount(t, remoteTrack), 1,
+ 'Remote track is also mono');
+}, 'Sending and receiving a mono track with opus');
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate);
+ pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate);
+
+ // Open microphone as stereo.
+ const stream = await navigator.mediaDevices.getUserMedia(
+ {audio: getAudioConstraints(kNumChannelsStereo, kAudioProcessingDisabled)});
+ const [track] = stream.getTracks();
+ t.add_cleanup(() => track.stop());
+ // Prerequisite of the test.
+ assert_equals(track.getSettings().channelCount, 2,
+ 'Can open track in stereo');
+
+ // Negotiate opus.
+ const transceiver = pc1.addTransceiver(track);
+ transceiver.setCodecPreferences(
+ RTCRtpSender.getCapabilities('audio').codecs.filter(
+ codec => codec.mimeType == 'audio/opus'));
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription();
+ await pc1.setRemoteDescription(pc2.localDescription);
+
+ const [receiver] = pc2.getReceivers();
+ const remoteTrack = receiver.track;
+ // Attaching the track to an audio element is needed for media to flow,
+ // otherwise the `channelCount` is never known.
+ const audio = document.createElement('audio');
+ audio.srcObject = new MediaStream();
+ audio.srcObject.addTrack(remoteTrack);
+ assert_equals(await pollChannelCount(t, remoteTrack), 2,
+ 'Remote track is also stereo');
+}, 'Sending and receiving a stereo track with opus');
+</script>
diff --git a/tests/wpt/tests/xhr/formdata/constructor-submitter-coordinate.html b/tests/wpt/tests/xhr/formdata/constructor-submitter-coordinate.html
index 992f64b7217..b7bf128bd12 100644
--- a/tests/wpt/tests/xhr/formdata/constructor-submitter-coordinate.html
+++ b/tests/wpt/tests/xhr/formdata/constructor-submitter-coordinate.html
@@ -1,18 +1,21 @@
<!DOCTYPE html>
<meta charset='utf-8'>
+<meta name=viewport content='width=device-width,initial-scale=1'>
<link rel='help' href='https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#constructing-the-form-data-set'>
<link ref='help' href='https://xhr.spec.whatwg.org/#dom-formdata'>
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<form>
- <input type=image src='/media/1x1-green.png'></button>
+ <input type=image src='/images/100px-green-rect.svg'>
</form>
<script>
"use strict";
-test(() => {
+promise_test(async () => {
+ await new Promise(r => window.addEventListener("load", r));
+
const form = document.querySelector("form");
const submitter = form.querySelector("input[type=image]");
@@ -23,14 +26,14 @@ test(() => {
});
const domRect = submitter.getBoundingClientRect();
+ const clientX = Math.round((domRect.left + domRect.right) / 7);
+ const clientY = Math.round((domRect.top + domRect.bottom) / 4);
+
submitter.dispatchEvent(
- new MouseEvent("click", {
- clientX: Math.round(domRect.x) + 1,
- clientY: Math.round(domRect.y) + 2
- })
+ new MouseEvent("click", {clientX, clientY})
);
- assert_equals(formData?.get("x"), "1");
- assert_equals(formData?.get("y"), "2");
+ assert_equals(formData?.get("x"), "23");
+ assert_equals(formData?.get("y"), "46");
}, "The constructed FormData object should contain correct entries for Image Button submitter's dispatched coordinate");
</script>
diff --git a/tests/wpt/tests/xhr/formdata/submitter-coordinate-value.html b/tests/wpt/tests/xhr/formdata/submitter-coordinate-value.html
new file mode 100644
index 00000000000..69bea0ac3f9
--- /dev/null
+++ b/tests/wpt/tests/xhr/formdata/submitter-coordinate-value.html
@@ -0,0 +1,55 @@
+<!doctype html>
+<meta charset="utf-8">
+<meta name=viewport content="width=device-width,initial-scale=1">
+<title>Test image button coordinates</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/input.html#image-button-state-(type=image)">
+<link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=282266">
+<link rel="author" title="Zach Hoffman" href="mailto:zach@zrhoffman.net">
+<form id="myForm" onsubmit="return false;">
+ <input id="myImage" name="myImage" type="image" src="/images/100px-green-rect.svg">
+</form>
+<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>
+promise_test(async t => {
+ await new Promise(r => window.addEventListener("load", r));
+
+ const xCoordinates = [];
+ const yCoordinates = [];
+
+ let formData;
+ myForm.addEventListener("submit", t.step_func(e => {
+ e.preventDefault();
+ formData = new FormData(myForm, myImage);
+ xCoordinates.push(formData.get("myImage.x"));
+ yCoordinates.push(formData.get("myImage.y"));
+ }));
+
+ await test_driver.click(myImage);
+
+ const [clientX, clientY] = getInViewCenterPoint(myImage.getBoundingClientRect());
+ const mouseEvent = new MouseEvent("click", {clientX, clientY});
+ myImage.dispatchEvent(mouseEvent);
+
+ assert_equals(xCoordinates.length, 2, "there should be 2 X coordinates");
+ assert_equals(yCoordinates.length, 2, "there should be 2 Y coordinates");
+ assert_equals(xCoordinates[1], xCoordinates[0], "dispatched event X coordinate should match user intention X coordinate");
+ assert_equals(yCoordinates[1], yCoordinates[0], "dispatched event Y coordinate should match user intention Y coordinate");
+}, "dispatched event coordinates should match user intention coordinates")
+
+// Private function from testdriver.js.
+function getInViewCenterPoint(rect) {
+ var left = Math.max(0, rect.left);
+ var right = Math.min(window.innerWidth, rect.right);
+ var top = Math.max(0, rect.top);
+ var bottom = Math.min(window.innerHeight, rect.bottom);
+
+ var x = 0.5 * (left + right);
+ var y = 0.5 * (top + bottom);
+
+ return [x, y];
+}
+</script>