From 43a97878ce14b72f0981164f87f2e35e14151312 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:22:09 +0200 Subject: Adding upstream version 110.0.1. Signed-off-by: Daniel Baumann --- .../accumulation-per-property-001.html | 24 + .../accumulation-per-property-002.html | 24 + .../animation-types/addition-per-property-001.html | 24 + .../animation-types/addition-per-property-002.html | 24 + .../animation-model/animation-types/discrete.html | 135 + .../interpolation-per-property-001.html | 24 + .../interpolation-per-property-002.html | 24 + .../animation-types/property-list.js | 1564 +++++++++++ .../animation-types/property-types.js | 2769 ++++++++++++++++++++ .../animation-types/property-utils.js | 38 + .../animation-types/visibility.html | 57 + .../applying-interpolated-transform.html | 87 + .../applying-the-composited-result.html | 29 + .../combining-effects/effect-composition.html | 154 ++ .../computed-keyframes-shorthands.html | 30 + .../effect-in-removed-iframe-crash.html | 22 + .../effect-on-marquee-parent-crash.html | 21 + .../effect-value-context-filling.html | 377 +++ .../keyframe-effects/effect-value-context.html | 105 + .../effect-value-interval-distance.html | 36 + ...effect-value-iteration-composite-operation.html | 824 ++++++ .../effect-value-overlapping-keyframes.html | 77 + .../effect-value-replaced-animations.html | 161 ++ .../effect-value-transformed-distance.html | 84 + .../transform-and-opacity-on-inline-001-ref.html | 14 + .../transform-and-opacity-on-inline-001.html | 27 + 26 files changed, 6755 insertions(+) create mode 100644 testing/web-platform/tests/web-animations/animation-model/animation-types/accumulation-per-property-001.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/animation-types/accumulation-per-property-002.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/animation-types/addition-per-property-001.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/animation-types/addition-per-property-002.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/animation-types/discrete.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/animation-types/interpolation-per-property-001.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/animation-types/interpolation-per-property-002.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/animation-types/property-list.js create mode 100644 testing/web-platform/tests/web-animations/animation-model/animation-types/property-types.js create mode 100644 testing/web-platform/tests/web-animations/animation-model/animation-types/property-utils.js create mode 100644 testing/web-platform/tests/web-animations/animation-model/animation-types/visibility.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/combining-effects/applying-interpolated-transform.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/combining-effects/applying-the-composited-result.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/combining-effects/effect-composition.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/keyframe-effects/computed-keyframes-shorthands.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-in-removed-iframe-crash.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-on-marquee-parent-crash.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-context-filling.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-context.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-interval-distance.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-iteration-composite-operation.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-overlapping-keyframes.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-replaced-animations.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/keyframe-effects/transform-and-opacity-on-inline-001-ref.html create mode 100644 testing/web-platform/tests/web-animations/animation-model/keyframe-effects/transform-and-opacity-on-inline-001.html (limited to 'testing/web-platform/tests/web-animations/animation-model') diff --git a/testing/web-platform/tests/web-animations/animation-model/animation-types/accumulation-per-property-001.html b/testing/web-platform/tests/web-animations/animation-model/animation-types/accumulation-per-property-001.html new file mode 100644 index 0000000000..a3fd115563 --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/animation-types/accumulation-per-property-001.html @@ -0,0 +1,24 @@ + + +Accumulation for each property + + + + + + + + + +
+ diff --git a/testing/web-platform/tests/web-animations/animation-model/animation-types/accumulation-per-property-002.html b/testing/web-platform/tests/web-animations/animation-model/animation-types/accumulation-per-property-002.html new file mode 100644 index 0000000000..5cf411edf6 --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/animation-types/accumulation-per-property-002.html @@ -0,0 +1,24 @@ + + +Accumulation for each property + + + + + + + + + +
+ diff --git a/testing/web-platform/tests/web-animations/animation-model/animation-types/addition-per-property-001.html b/testing/web-platform/tests/web-animations/animation-model/animation-types/addition-per-property-001.html new file mode 100644 index 0000000000..2fbec2c4cd --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/animation-types/addition-per-property-001.html @@ -0,0 +1,24 @@ + + +Addition for each property + + + + + + + + + +
+ diff --git a/testing/web-platform/tests/web-animations/animation-model/animation-types/addition-per-property-002.html b/testing/web-platform/tests/web-animations/animation-model/animation-types/addition-per-property-002.html new file mode 100644 index 0000000000..3b1c40e3c7 --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/animation-types/addition-per-property-002.html @@ -0,0 +1,24 @@ + + +Addition for each property + + + + + + + + + +
+ diff --git a/testing/web-platform/tests/web-animations/animation-model/animation-types/discrete.html b/testing/web-platform/tests/web-animations/animation-model/animation-types/discrete.html new file mode 100644 index 0000000000..76f42bc7a4 --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/animation-types/discrete.html @@ -0,0 +1,135 @@ + + +Discrete animation type + + + + + +
+ diff --git a/testing/web-platform/tests/web-animations/animation-model/animation-types/interpolation-per-property-001.html b/testing/web-platform/tests/web-animations/animation-model/animation-types/interpolation-per-property-001.html new file mode 100644 index 0000000000..97f2822473 --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/animation-types/interpolation-per-property-001.html @@ -0,0 +1,24 @@ + + +Interpolation for each property + + + + + + + + + +
+ diff --git a/testing/web-platform/tests/web-animations/animation-model/animation-types/interpolation-per-property-002.html b/testing/web-platform/tests/web-animations/animation-model/animation-types/interpolation-per-property-002.html new file mode 100644 index 0000000000..9ccc613cfc --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/animation-types/interpolation-per-property-002.html @@ -0,0 +1,24 @@ + + +Interpolation for each property + + + + + + + + + +
+ diff --git a/testing/web-platform/tests/web-animations/animation-model/animation-types/property-list.js b/testing/web-platform/tests/web-animations/animation-model/animation-types/property-list.js new file mode 100644 index 0000000000..59866a5897 --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/animation-types/property-list.js @@ -0,0 +1,1564 @@ +'use strict'; + +const gCSSProperties1 = { + 'align-content': { + // https://drafts.csswg.org/css-align/#propdef-align-content + types: [ + { type: 'discrete' , options: [ [ 'flex-start', 'flex-end' ] ] } + ] + }, + 'align-items': { + // https://drafts.csswg.org/css-align/#propdef-align-items + types: [ + { type: 'discrete', options: [ [ 'flex-start', 'flex-end' ] ] } + ] + }, + 'align-self': { + // https://drafts.csswg.org/css-align/#propdef-align-self + types: [ + { type: 'discrete', options: [ [ 'flex-start', 'flex-end' ] ] } + ] + }, + 'backface-visibility': { + // https://drafts.csswg.org/css-transforms/#propdef-backface-visibility + types: [ + { type: 'discrete', options: [ [ 'visible', 'hidden' ] ] } + ] + }, + 'background-attachment': { + // https://drafts.csswg.org/css-backgrounds-3/#background-attachment + types: [ + { type: 'discrete', options: [ [ 'fixed', 'local' ] ] } + ] + }, + 'background-color': { + // https://drafts.csswg.org/css-backgrounds-3/#background-color + types: [ 'color' ] + }, + 'background-blend-mode': { + // https://drafts.fxtf.org/compositing-1/#propdef-background-blend-mode + types: [ + { type: 'discrete', options: [ [ 'multiply', 'screen' ] ] } + ] + }, + 'background-clip': { + // https://drafts.csswg.org/css-backgrounds-3/#background-clip + types: [ + { type: 'discrete', options: [ [ 'padding-box', 'content-box' ] ] } + ] + }, + 'background-image': { + // https://drafts.csswg.org/css-backgrounds-3/#background-image + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'background-origin': { + // https://drafts.csswg.org/css-backgrounds-3/#background-origin + types: [ + { type: 'discrete', options: [ [ 'padding-box', 'content-box' ] ] } + ] + }, + 'background-position': { + // https://drafts.csswg.org/css-backgrounds-3/#background-position + types: [ + ] + }, + 'background-position-x': { + // https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-x + types: [ + ] + }, + 'background-position-y': { + // https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-y + types: [ + ] + }, + 'background-repeat': { + // https://drafts.csswg.org/css-backgrounds-3/#background-repeat + types: [ + { type: 'discrete', options: [ [ 'space', 'round' ] ] } + ] + }, + 'background-size': { + // https://drafts.csswg.org/css-backgrounds-3/#background-size + types: [ + ] + }, + 'block-size': { + // https://drafts.csswg.org/css-logical-props/#propdef-block-size + types: [ + ] + }, + 'border-block-end-color': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-block-end-color + types: [ + ] + }, + 'border-block-end-style': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-block-end-style + types: [ + ] + }, + 'border-block-end-width': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-block-end-width + types: [ + ] + }, + 'border-block-start-color': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-block-start-color + types: [ + ] + }, + 'border-block-start-style': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-block-start-style + types: [ + ] + }, + 'border-block-start-width': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-block-start-width + types: [ + ] + }, + 'border-bottom-color': { + // https://drafts.csswg.org/css-backgrounds-3/#border-bottom-color + types: [ 'color' ] + }, + 'border-bottom-left-radius': { + // https://drafts.csswg.org/css-backgrounds-3/#border-bottom-left-radius + types: [ + ] + }, + 'border-bottom-right-radius': { + // https://drafts.csswg.org/css-backgrounds-3/#border-bottom-right-radius + types: [ + ] + }, + 'border-bottom-style': { + // https://drafts.csswg.org/css-backgrounds-3/#border-bottom-style + types: [ + { type: 'discrete', options: [ [ 'dotted', 'solid' ] ] } + ] + }, + 'border-bottom-width': { + // https://drafts.csswg.org/css-backgrounds-3/#border-bottom-width + types: [ 'length' ], + setup: t => { + const element = createElement(t); + element.style.borderBottomStyle = 'solid'; + return element; + } + }, + 'border-collapse': { + // https://drafts.csswg.org/css-tables/#propdef-border-collapse + types: [ + { type: 'discrete', options: [ [ 'collapse', 'separate' ] ] } + ] + }, + 'border-inline-end-color': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-inline-end-color + types: [ + ] + }, + 'border-inline-end-style': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-inline-end-style + types: [ + ] + }, + 'border-inline-end-width': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-inline-end-width + types: [ + ] + }, + 'border-inline-start-color': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-inline-start-color + types: [ + ] + }, + 'border-inline-start-style': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-block-start-style + types: [ + ] + }, + 'border-inline-start-width': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-inline-start-width + types: [ + ] + }, + 'border-image-outset': { + // https://drafts.csswg.org/css-backgrounds-3/#border-image-outset + types: [ + ] + }, + 'border-image-repeat': { + // https://drafts.csswg.org/css-backgrounds-3/#border-image-repeat + types: [ + { type: 'discrete', options: [ [ 'stretch repeat', 'round space' ] ] } + ] + }, + 'border-image-slice': { + // https://drafts.csswg.org/css-backgrounds-3/#border-image-slice + types: [ + ] + }, + 'border-image-source': { + // https://drafts.csswg.org/css-backgrounds-3/#border-image-source + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'border-image-width': { + // https://drafts.csswg.org/css-backgrounds-3/#border-image-width + types: [ + ] + }, + 'border-left-color': { + // https://drafts.csswg.org/css-backgrounds-3/#border-left-color + types: [ 'color' ] + }, + 'border-left-style': { + // https://drafts.csswg.org/css-backgrounds-3/#border-left-style + types: [ + { type: 'discrete', options: [ [ 'dotted', 'solid' ] ] } + ] + }, + 'border-left-width': { + // https://drafts.csswg.org/css-backgrounds-3/#border-left-width + types: [ 'length' ], + setup: t => { + const element = createElement(t); + element.style.borderLeftStyle = 'solid'; + return element; + } + }, + 'border-right-color': { + // https://drafts.csswg.org/css-backgrounds-3/#border-right-color + types: [ 'color' ] + }, + 'border-right-style': { + // https://drafts.csswg.org/css-backgrounds-3/#border-right-style + types: [ + { type: 'discrete', options: [ [ 'dotted', 'solid' ] ] } + ] + }, + 'border-right-width': { + // https://drafts.csswg.org/css-backgrounds-3/#border-right-width + types: [ 'length' ], + setup: t => { + const element = createElement(t); + element.style.borderRightStyle = 'solid'; + return element; + } + }, + 'border-spacing': { + // https://drafts.csswg.org/css-tables/#propdef-border-spacing + types: [ 'lengthPair' ] + }, + 'border-top-color': { + // https://drafts.csswg.org/css-backgrounds-3/#border-top-color + types: [ 'color' ] + }, + 'border-top-left-radius': { + // https://drafts.csswg.org/css-backgrounds-3/#border-top-left-radius + types: [ + ] + }, + 'border-top-right-radius': { + // https://drafts.csswg.org/css-backgrounds-3/#border-top-right-radius + types: [ + ] + }, + 'border-top-style': { + // https://drafts.csswg.org/css-backgrounds-3/#border-top-style + types: [ + { type: 'discrete', options: [ [ 'dotted', 'solid' ] ] } + ] + }, + 'border-top-width': { + // https://drafts.csswg.org/css-backgrounds-3/#border-top-width + types: [ 'length' ], + setup: t => { + const element = createElement(t); + element.style.borderTopStyle = 'solid'; + return element; + } + }, + 'bottom': { + // https://drafts.csswg.org/css-position/#propdef-bottom + types: [ + ] + }, + 'box-decoration-break': { + // https://drafts.csswg.org/css-break/#propdef-box-decoration-break + types: [ + { type: 'discrete', options: [ [ 'slice', 'clone' ] ] } + ] + }, + 'box-shadow': { + // https://drafts.csswg.org/css-backgrounds/#box-shadow + types: [ 'boxShadowList' ], + }, + 'box-sizing': { + // https://drafts.csswg.org/css-ui-4/#box-sizing + types: [ + { type: 'discrete', options: [ [ 'content-box', 'border-box' ] ] } + ] + }, + 'caption-side': { + // https://drafts.csswg.org/css-tables/#propdef-caption-side + types: [ + { type: 'discrete', options: [ [ 'top', 'bottom' ] ] } + ] + }, + 'caret-color': { + // https://drafts.csswg.org/css-ui/#propdef-caret-color + types: [ 'color' ] + }, + 'clear': { + // https://drafts.csswg.org/css-page-floats/#propdef-clear + types: [ + { type: 'discrete', options: [ [ 'left', 'right' ] ] } + ] + }, + 'clip': { + // https://drafts.fxtf.org/css-masking-1/#propdef-clip + types: [ + 'rect', + { type: 'discrete', options: [ [ 'rect(10px, 10px, 10px, 10px)', + 'auto' ], + [ 'rect(10px, 10px, 10px, 10px)', + 'rect(10px, 10px, 10px, auto)'] ] } + ] + }, + 'clip-path': { + // https://drafts.fxtf.org/css-masking-1/#propdef-clip-path + types: [ + ] + }, + 'clip-rule': { + // https://drafts.fxtf.org/css-masking-1/#propdef-clip-rule + types: [ + { type: 'discrete', options: [ [ 'evenodd', 'nonzero' ] ] } + ] + }, + 'color': { + // https://drafts.csswg.org/css-color/#propdef-color + types: [ 'color' ] + }, + 'color-adjust': { + // https://drafts.csswg.org/css-color-4/#color-adjust + types: [ + { type: 'discrete', options: [ [ 'economy', 'exact' ] ] } + ] + }, + 'color-interpolation': { + // https://svgwg.org/svg2-draft/painting.html#ColorInterpolationProperty + types: [ + { type: 'discrete', options: [ [ 'linearrgb', 'auto' ] ] } + ] + }, + 'color-interpolation-filters': { + // https://drafts.fxtf.org/filters-1/#propdef-color-interpolation-filters + types: [ + { type: 'discrete', options: [ [ 'srgb', 'linearrgb' ] ] } + ] + }, + 'column-count': { + // https://drafts.csswg.org/css-multicol/#propdef-column-count + types: [ 'positiveInteger', + { type: 'discrete', options: [ [ 'auto', '10' ] ] } + ] + }, + 'column-gap': { + // https://drafts.csswg.org/css-multicol/#propdef-column-gap + types: [ 'length', + { type: 'discrete', options: [ [ 'normal', '200px' ] ] } + ] + }, + 'column-rule-color': { + // https://drafts.csswg.org/css-multicol/#propdef-column-rule-color + types: [ 'color' ] + }, + 'column-fill': { + // https://drafts.csswg.org/css-multicol/#propdef-column-fill + types: [ + { type: 'discrete', options: [ [ 'auto', 'balance' ] ] } + ] + }, + 'column-rule-style': { + // https://drafts.csswg.org/css-multicol/#propdef-column-rule-style + types: [ + { type: 'discrete', options: [ [ 'none', 'dotted' ] ] } + ] + }, + 'column-rule-width': { + // https://drafts.csswg.org/css-multicol/#propdef-column-rule-width + types: [ 'length' ], + setup: t => { + const element = createElement(t); + element.style.columnRuleStyle = 'solid'; + return element; + } + }, + 'column-width': { + // https://drafts.csswg.org/css-multicol/#propdef-column-width + types: [ 'length', + { type: 'discrete', options: [ [ 'auto', '1px' ] ] } + ] + }, + 'counter-increment': { + // https://drafts.csswg.org/css-lists-3/#propdef-counter-increment + types: [ + { type: 'discrete', options: [ [ 'ident-1 1', 'ident-2 2' ] ] } + ] + }, + 'counter-reset': { + // https://drafts.csswg.org/css-lists-3/#propdef-counter-reset + types: [ + { type: 'discrete', options: [ [ 'ident-1 1', 'ident-2 2' ] ] } + ] + }, + 'cursor': { + // https://drafts.csswg.org/css2/ui.html#propdef-cursor + types: [ + { type: 'discrete', options: [ [ 'pointer', 'wait' ] ] } + ] + }, + 'dominant-baseline': { + // https://drafts.csswg.org/css-inline/#propdef-dominant-baseline + types: [ + { type: 'discrete', options: [ [ 'ideographic', 'alphabetic' ] ] } + ] + }, + 'empty-cells': { + // https://drafts.csswg.org/css-tables/#propdef-empty-cells + types: [ + { type: 'discrete', options: [ [ 'show', 'hide' ] ] } + ] + }, + 'fill': { + // https://svgwg.org/svg2-draft/painting.html#FillProperty + types: [ + ] + }, + 'fill-opacity': { + // https://svgwg.org/svg2-draft/painting.html#FillOpacityProperty + types: [ 'opacity' ] + }, + 'fill-rule': { + // https://svgwg.org/svg2-draft/painting.html#FillRuleProperty + types: [ + { type: 'discrete', options: [ [ 'evenodd', 'nonzero' ] ] } + ] + }, + 'filter': { + // https://drafts.fxtf.org/filters/#propdef-filter + types: [ 'filterList' ] + }, + 'flex-basis': { + // https://drafts.csswg.org/css-flexbox/#propdef-flex-basis + types: [ + 'lengthPercentageOrCalc', + { type: 'discrete', options: [ [ 'auto', '10px' ] ] } + ] + }, + 'flex-direction': { + // https://drafts.csswg.org/css-flexbox/#propdef-flex-direction + types: [ + { type: 'discrete', options: [ [ 'row', 'row-reverse' ] ] } + ] + }, + 'flex-grow': { + // https://drafts.csswg.org/css-flexbox/#flex-grow-property + types: [ 'positiveNumber' ] + }, + 'flex-shrink': { + // https://drafts.csswg.org/css-flexbox/#propdef-flex-shrink + types: [ 'positiveNumber' ] + }, + 'flex-wrap': { + // https://drafts.csswg.org/css-flexbox/#propdef-flex-wrap + types: [ + { type: 'discrete', options: [ [ 'nowrap', 'wrap' ] ] } + ] + }, + 'flood-color': { + // https://drafts.fxtf.org/filters/#FloodColorProperty + types: [ 'color' ] + }, + 'flood-opacity': { + // https://drafts.fxtf.org/filters/#propdef-flood-opacity + types: [ 'opacity' ] + }, + 'font-size': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-size + types: [ + ] + }, + 'font-size-adjust': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-size-adjust + types: [ + ] + }, + 'font-stretch': { + // https://drafts.csswg.org/css-fonts-4/#propdef-font-stretch + types: [ 'percentage' ] + }, + 'font-style': { + // https://drafts.csswg.org/css-fonts/#propdef-font-style + types: [ + { type: 'discrete', options: [ [ 'italic', 'oblique' ] ] } + ] + }, + 'float': { + // https://drafts.csswg.org/css-page-floats/#propdef-float + types: [ + { type: 'discrete', options: [ [ 'left', 'right' ] ] } + ] + }, + 'font-family': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-family + types: [ + { type: 'discrete', options: [ [ 'helvetica', 'verdana' ] ] } + ] + }, + 'font-feature-settings': { + // https://drafts.csswg.org/css-fonts/#descdef-font-feature-settings + types: [ + { type: 'discrete', options: [ [ '"liga" 5', 'normal' ] ] } + ] + }, + 'font-kerning': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-kerning + types: [ + { type: 'discrete', options: [ [ 'auto', 'normal' ] ] } + ] + }, + 'font-language-override': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-language-override + types: [ + { type: 'discrete', options: [ [ '"eng"', 'normal' ] ] } + ] + }, + 'font-style': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-style + types: [ + { type: 'discrete', options: [ [ 'italic', 'oblique' ] ] } + ] + }, + 'font-synthesis': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-synthesis + types: [ + { type: 'discrete', options: [ [ 'none', 'weight style' ] ] } + ] + }, + 'font-variant-alternates': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-variant-alternates + types: [ + { type: 'discrete', + options: [ [ 'swash(unknown)', 'stylistic(unknown)' ] ] } + ] + }, + 'font-variant-caps': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-variant-caps + types: [ + { type: 'discrete', options: [ [ 'small-caps', 'unicase' ] ] } + ] + }, + 'font-variant-east-asian': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-variant-east-asian + types: [ + { type: 'discrete', options: [ [ 'full-width', 'proportional-width' ] ] } + ] + }, + 'font-variant-ligatures': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-variant-ligatures + types: [ + { type: 'discrete', + options: [ [ 'common-ligatures', 'no-common-ligatures' ] ] } + ] + }, + 'font-variant-numeric': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-variant-numeric + types: [ + { type: 'discrete', options: [ [ 'lining-nums', 'oldstyle-nums' ] ] } + ] + }, + 'font-variant-position': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-variant-position + types: [ + { type: 'discrete', options: [ [ 'sub', 'super' ] ] } + ] + }, + 'font-variation-settings': { + // https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-variation-settings + types: [ + 'fontVariationSettings', + { type: 'discrete', + options: [ ['"wdth" 1, "wght" 1.1', '"wdth" 5'], + ['"wdth" 5', 'normal'] + ] }, + ] + }, + 'font-weight': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-weight + types: [ + ] + }, + 'grid-auto-columns': { + // https://drafts.csswg.org/css-grid/#propdef-grid-auto-columns + types: [ + { type: 'discrete', options: [ [ '1px', '5px' ] ] } + ] + }, + 'grid-auto-flow': { + // https://drafts.csswg.org/css-grid/#propdef-grid-auto-flow + types: [ + { type: 'discrete', options: [ [ 'row', 'column' ] ] } + ] + }, + 'grid-auto-rows': { + // https://drafts.csswg.org/css-grid/#propdef-grid-auto-rows + types: [ + { type: 'discrete', options: [ [ '1px', '5px' ] ] } + ] + }, + 'grid-column-end': { + // https://drafts.csswg.org/css-grid/#propdef-grid-column-end + types: [ + { type: 'discrete', options: [ [ '1', '5' ] ] } + ] + }, + 'grid-column-gap': { + // https://drafts.csswg.org/css-grid/#propdef-grid-column-gap + types: [ + ] + }, + 'grid-column-start': { + // https://drafts.csswg.org/css-grid/#propdef-grid-column-start + types: [ + { type: 'discrete', options: [ [ '1', '5' ] ] } + ] + }, + 'grid-row-end': { + // https://drafts.csswg.org/css-grid/#propdef-grid-row-end + types: [ + { type: 'discrete', options: [ [ '1', '5' ] ] } + ] + }, + 'grid-row-gap': { + // https://drafts.csswg.org/css-grid/#propdef-grid-row-gap + types: [ + ] + }, + 'grid-row-start': { + // https://drafts.csswg.org/css-grid/#propdef-grid-row-start + types: [ + { type: 'discrete', options: [ [ '1', '5' ] ] } + ] + }, + 'grid-template-areas': { + // https://drafts.csswg.org/css-template/#grid-template-areas + types: [ + { type: 'discrete', options: [ [ '". . a b" ". .a b"', 'none' ] ] } + ] + }, + 'height': { + // https://drafts.csswg.org/css21/visudet.html#propdef-height + types: [ + ] + }, + 'hyphens': { + // https://drafts.csswg.org/css-text-3/#propdef-hyphens + types: [ + { type: 'discrete', options: [ [ 'manual', 'none' ] ] } + ] + }, + 'image-orientation': { + // https://drafts.csswg.org/css-images-3/#propdef-image-orientation + types: [ + { type: 'discrete', options: [ [ 'none', 'from-image' ] ] } + ] + }, + 'image-rendering': { + // https://drafts.csswg.org/css-images-3/#propdef-image-rendering + types: [ + ] + }, + 'ime-mode': { + // https://drafts.csswg.org/css-ui/#input-method-editor + types: [ + { type: 'discrete', options: [ [ 'disabled', 'auto' ] ] } + ] + }, + 'initial-letter': { + // https://drafts.csswg.org/css-inline/#propdef-initial-letter + types: [ + { type: 'discrete', options: [ [ '1 2', '3 4' ] ] } + ] + }, +}; + +const gCSSProperties2 = { + 'inline-size': { + // https://drafts.csswg.org/css-logical-props/#propdef-inline-size + types: [ + ] + }, + 'isolation': { + // https://drafts.fxtf.org/compositing-1/#propdef-isolation + types: [ + { type: 'discrete', options: [ [ 'auto', 'isolate' ] ] } + ] + }, + 'justify-content': { + // https://drafts.csswg.org/css-align/#propdef-justify-content + types: [ + { type: 'discrete', options: [ [ 'start', 'end' ] ] } + ] + }, + 'justify-items': { + // https://drafts.csswg.org/css-align/#propdef-justify-items + types: [ + { type: 'discrete', options: [ [ 'start', 'end' ] ] } + ] + }, + 'justify-self': { + // https://drafts.csswg.org/css-align/#propdef-justify-self + types: [ + { type: 'discrete', options: [ [ 'start', 'end' ] ] } + ] + }, + 'left': { + // https://drafts.csswg.org/css-position/#propdef-left + types: [ + ] + }, + 'letter-spacing': { + // https://drafts.csswg.org/css-text-3/#propdef-letter-spacing + types: [ 'length' ] + }, + 'lighting-color': { + // https://drafts.fxtf.org/filters/#LightingColorProperty + types: [ 'color' ] + }, + 'line-height': { + // https://drafts.csswg.org/css21/visudet.html#propdef-line-height + types: [ + ] + }, + 'list-style-image': { + // https://drafts.csswg.org/css-lists-3/#propdef-list-style-image + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'list-style-position': { + // https://drafts.csswg.org/css-lists-3/#propdef-list-style-position + types: [ + { type: 'discrete', options: [ [ 'inside', 'outside' ] ] } + ] + }, + 'list-style-type': { + // https://drafts.csswg.org/css-lists-3/#propdef-list-style-type + types: [ + { type: 'discrete', options: [ [ 'circle', 'square' ] ] } + ] + }, + 'margin-block-end': { + // https://drafts.csswg.org/css-logical-props/#propdef-margin-block-end + types: [ + ] + }, + 'margin-block-start': { + // https://drafts.csswg.org/css-logical-props/#propdef-margin-block-start + types: [ + ] + }, + 'margin-bottom': { + // https://drafts.csswg.org/css-box/#propdef-margin-bottom + types: [ + ] + }, + 'margin-inline-end': { + // https://drafts.csswg.org/css-logical-props/#propdef-margin-inline-end + types: [ + ] + }, + 'margin-inline-start': { + // https://drafts.csswg.org/css-logical-props/#propdef-margin-inline-start + types: [ + ] + }, + 'margin-left': { + // https://drafts.csswg.org/css-box/#propdef-margin-left + types: [ + ] + }, + 'margin-right': { + // https://drafts.csswg.org/css-box/#propdef-margin-right + types: [ + ] + }, + 'margin-top': { + // https://drafts.csswg.org/css-box/#propdef-margin-top + types: [ + ] + }, + 'marker-end': { + // https://svgwg.org/specs/markers/#MarkerEndProperty + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'marker-mid': { + // https://svgwg.org/specs/markers/#MarkerMidProperty + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'marker-start': { + // https://svgwg.org/specs/markers/#MarkerStartProperty + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'mask': { + // https://drafts.fxtf.org/css-masking-1/#the-mask + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'mask-clip': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-clip + types: [ + { type: 'discrete', options: [ [ 'content-box', 'border-box' ] ] } + ] + }, + 'mask-composite': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-composite + types: [ + { type: 'discrete', options: [ [ 'add', 'subtract' ] ] } + ] + }, + 'mask-image': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-image + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'mask-mode': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-mode + types: [ + { type: 'discrete', options: [ [ 'alpha', 'luminance' ] ] } + ] + }, + 'mask-origin': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-origin + types: [ + { type: 'discrete', options: [ [ 'content-box', 'border-box' ] ] } + ] + }, + 'mask-position': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-position + types: [ + ] + }, + 'mask-position-x': { + // https://lists.w3.org/Archives/Public/www-style/2014Jun/0166.html + types: [ + ] + }, + 'mask-position-y': { + // https://lists.w3.org/Archives/Public/www-style/2014Jun/0166.html + types: [ + ] + }, + 'mask-repeat': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-repeat + types: [ + { type: 'discrete', options: [ [ 'space', 'round' ] ] } + ] + }, + 'mask-size': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-size + types: [ + ] + }, + 'mask-type': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-type + types: [ + { type: 'discrete', options: [ [ 'alpha', 'luminance' ] ] } + ] + }, + 'max-block-size': { + // https://drafts.csswg.org/css-logical-props/#propdef-max-block-size + types: [ + ] + }, + 'max-height': { + // https://drafts.csswg.org/css21/visudet.html#propdef-max-height + types: [ + ] + }, + 'max-inline-size': { + // https://drafts.csswg.org/css-logical-props/#propdef-max-inline-size + types: [ + ] + }, + 'max-width': { + // https://drafts.csswg.org/css21/visudet.html#propdef-max-width + types: [ + ] + }, + 'min-block-size': { + // https://drafts.csswg.org/css-logical-props/#propdef-min-block-size + types: [ + ] + }, + 'min-height': { + // https://drafts.csswg.org/css21/visudet.html#propdef-min-height + types: [ + ] + }, + 'min-inline-size': { + // https://drafts.csswg.org/css-logical-props/#propdef-min-inline-size + types: [ + ] + }, + 'min-width': { + // https://drafts.csswg.org/css21/visudet.html#propdef-min-width + types: [ + ] + }, + 'mix-blend-mode': { + // https://drafts.fxtf.org/compositing-1/#propdef-mix-blend-mode + types: [ + { type: 'discrete', options: [ [ 'multiply', 'screen' ] ] } + ] + }, + 'object-fit': { + // https://drafts.csswg.org/css-images-3/#propdef-object-fit + types: [ + { type: 'discrete', options: [ [ 'fill', 'contain' ] ] } + ] + }, + 'object-position': { + // https://drafts.csswg.org/css-images-3/#propdef-object-position + types: [ + ] + }, + 'inset-block-end': { + // https://drafts.csswg.org/css-logical-props/#propdef-inset-block-end + types: [ + ] + }, + 'inset-block-start': { + // https://drafts.csswg.org/css-logical-props/#propdef-inset-block-start + types: [ + ] + }, + 'inset-inline-end': { + // https://drafts.csswg.org/css-logical-props/#propdef-inset-inline-end + types: [ + ] + }, + 'inset-inline-start': { + // https://drafts.csswg.org/css-logical-props/#propdef-inset-inline-start + types: [ + ] + }, + 'offset-distance': { + // https://drafts.fxtf.org/motion-1/#offset-distance-property + types: [ 'lengthPercentageOrCalc' ] + }, + 'offset-path': { + // https://drafts.fxtf.org/motion-1/#offset-path-property + types: [ + ] + }, + 'opacity': { + // https://drafts.csswg.org/css-color/#propdef-opacity + types: [ + ] + }, + 'order': { + // https://drafts.csswg.org/css-flexbox/#propdef-order + types: [ 'integer' ] + }, + 'outline-color': { + // https://drafts.csswg.org/css-ui-3/#propdef-outline-color + types: [ 'color' ] + }, + 'outline-offset': { + // https://drafts.csswg.org/css-ui-3/#propdef-outline-offset + types: [ 'length' ] + }, + 'outline-style': { + // https://drafts.csswg.org/css-ui/#propdef-outline-style + types: [ + { type: 'discrete', options: [ [ 'none', 'dotted' ] ] } + ] + }, + 'outline-width': { + // https://drafts.csswg.org/css-ui-3/#propdef-outline-width + types: [ 'length' ], + setup: t => { + const element = createElement(t); + element.style.outlineStyle = 'solid'; + return element; + } + }, + 'overflow': { + // https://drafts.csswg.org/css-overflow/#propdef-overflow + types: [ + ] + }, + 'overflow-wrap': { + // https://drafts.csswg.org/css-text-3/#propdef-overflow-wrap + types: [ + { type: 'discrete', options: [ [ 'normal', 'break-word' ] ] } + ] + }, + 'overflow-x': { + // https://drafts.csswg.org/css-overflow-3/#propdef-overflow-x + types: [ + { type: 'discrete', options: [ [ 'visible', 'hidden' ] ] } + ] + }, + 'overflow-y': { + // https://drafts.csswg.org/css-overflow-3/#propdef-overflow-y + types: [ + { type: 'discrete', options: [ [ 'visible', 'hidden' ] ] } + ] + }, + 'padding-block-end': { + // https://drafts.csswg.org/css-logical-props/#propdef-padding-block-end + types: [ + ] + }, + 'padding-block-start': { + // https://drafts.csswg.org/css-logical-props/#propdef-padding-block-start + types: [ + ] + }, + 'padding-bottom': { + // https://drafts.csswg.org/css-box/#propdef-padding-bottom + types: [ + ] + }, + 'padding-inline-end': { + // https://drafts.csswg.org/css-logical-props/#propdef-padding-inline-end + types: [ + ] + }, + 'padding-inline-start': { + // https://drafts.csswg.org/css-logical-props/#propdef-padding-inline-start + types: [ + ] + }, + 'padding-left': { + // https://drafts.csswg.org/css-box/#propdef-padding-left + types: [ + ] + }, + 'padding-right': { + // https://drafts.csswg.org/css-box/#propdef-padding-right + types: [ + ] + }, + 'padding-top': { + // https://drafts.csswg.org/css-box/#propdef-padding-top + types: [ + ] + }, + 'page-break-after': { + // https://drafts.csswg.org/css-break-3/#propdef-break-after + types: [ + { type: 'discrete', options: [ [ 'always', 'auto' ] ] } + ] + }, + 'page-break-before': { + // https://drafts.csswg.org/css-break-3/#propdef-break-before + types: [ + { type: 'discrete', options: [ [ 'always', 'auto' ] ] } + ] + }, + 'page-break-inside': { + // https://drafts.csswg.org/css-break-3/#propdef-break-inside + types: [ + { type: 'discrete', options: [ [ 'auto', 'avoid' ] ] } + ] + }, + 'paint-order': { + // https://svgwg.org/svg2-draft/painting.html#PaintOrderProperty + types: [ + { type: 'discrete', options: [ [ 'fill', 'stroke' ] ] } + ] + }, + 'perspective': { + // https://drafts.csswg.org/css-transforms-1/#propdef-perspective + types: [ 'length' ] + }, + 'perspective-origin': { + // https://drafts.csswg.org/css-transforms-1/#propdef-perspective-origin + types: [ 'position' ] + }, + 'pointer-events': { + // https://svgwg.org/svg2-draft/interact.html#PointerEventsProperty + types: [ + { type: 'discrete', options: [ [ 'fill', 'none' ] ] } + ] + }, + 'position': { + // https://drafts.csswg.org/css-position/#propdef-position + types: [ + { type: 'discrete', options: [ [ 'absolute', 'fixed' ] ] } + ] + }, + 'quotes': { + // https://drafts.csswg.org/css-content-3/#propdef-quotes + types: [ + { type: 'discrete', options: [ [ '"“" "”" "‘" "’"', '"‘" "’" "“" "”"' ] ] } + ] + }, + 'resize': { + // https://drafts.csswg.org/css-ui/#propdef-resize + types: [ + { type: 'discrete', options: [ [ 'both', 'horizontal' ] ] } + ] + }, + 'right': { + // https://drafts.csswg.org/css-position/#propdef-right + types: [ + ] + }, + 'ruby-align': { + // https://drafts.csswg.org/css-ruby-1/#propdef-ruby-align + types: [ + { type: 'discrete', options: [ [ 'start', 'center' ] ] } + ] + }, + 'ruby-position': { + // https://drafts.csswg.org/css-ruby-1/#propdef-ruby-position + types: [ + { type: 'discrete', options: [ [ 'under', 'over' ] ] } + ], + setup: t => { + return createElement(t, 'ruby'); + } + }, + 'scroll-behavior': { + // https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior + types: [ + { type: 'discrete', options: [ [ 'auto', 'smooth' ] ] } + ] + }, + 'shape-outside': { + // http://dev.w3.org/csswg/css-shapes/#propdef-shape-outside + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'shape-rendering': { + // https://svgwg.org/svg2-draft/painting.html#ShapeRenderingProperty + types: [ + { type: 'discrete', options: [ [ 'optimizeSpeed', 'crispEdges' ] ] } + ] + }, + 'stop-color': { + // https://svgwg.org/svg2-draft/pservers.html#StopColorProperty + types: [ 'color' ] + }, + 'stop-opacity': { + // https://svgwg.org/svg2-draft/pservers.html#StopOpacityProperty + types: [ 'opacity' ] + }, + 'stroke': { + // https://svgwg.org/svg2-draft/painting.html#StrokeProperty + types: [ + ] + }, + 'stroke-dasharray': { + // https://svgwg.org/svg2-draft/painting.html#StrokeDasharrayProperty + types: [ + 'dasharray', + { type: 'discrete', options: [ [ 'none', '10px, 20px' ] ] } + ] + }, + 'stroke-dashoffset': { + // https://svgwg.org/svg2-draft/painting.html#StrokeDashoffsetProperty + types: [ + ] + }, + 'stroke-linecap': { + // https://svgwg.org/svg2-draft/painting.html#StrokeLinecapProperty + types: [ + { type: 'discrete', options: [ [ 'round', 'square' ] ] } + ] + }, + 'stroke-linejoin': { + // https://svgwg.org/svg2-draft/painting.html#StrokeLinejoinProperty + types: [ + { type: 'discrete', options: [ [ 'round', 'miter' ] ] } + ], + setup: t => { + return createElement(t, 'rect'); + } + }, + 'stroke-miterlimit': { + // https://svgwg.org/svg2-draft/painting.html#StrokeMiterlimitProperty + types: [ 'positiveNumber' ] + }, + 'stroke-opacity': { + // https://svgwg.org/svg2-draft/painting.html#StrokeOpacityProperty + types: [ 'opacity' ] + }, + 'stroke-width': { + // https://svgwg.org/svg2-draft/painting.html#StrokeWidthProperty + types: [ + ] + }, + 'table-layout': { + // https://drafts.csswg.org/css-tables/#propdef-table-layout + types: [ + { type: 'discrete', options: [ [ 'auto', 'fixed' ] ] } + ] + }, + 'text-align': { + // https://drafts.csswg.org/css-text-3/#propdef-text-align + types: [ + { type: 'discrete', options: [ [ 'start', 'end' ] ] } + ] + }, + 'text-align-last': { + // https://drafts.csswg.org/css-text-3/#propdef-text-align-last + types: [ + { type: 'discrete', options: [ [ 'start', 'end' ] ] } + ] + }, + 'text-anchor': { + // https://svgwg.org/svg2-draft/text.html#TextAnchorProperty + types: [ + { type: 'discrete', options: [ [ 'middle', 'end' ] ] } + ] + }, + 'text-decoration-color': { + // https://drafts.csswg.org/css-text-decor-3/#propdef-text-decoration-color + types: [ 'color' ] + }, + 'text-decoration-line': { + // https://drafts.csswg.org/css-text-decor-3/#propdef-text-decoration-line + types: [ + { type: 'discrete', options: [ [ 'underline', 'overline' ] ] } + ] + }, + 'text-decoration-style': { + // http://dev.w3.org/csswg/css-text-decor-3/#propdef-text-decoration-style + types: [ + { type: 'discrete', options: [ [ 'solid', 'dotted' ] ] } + ] + }, + 'text-emphasis-color': { + // https://drafts.csswg.org/css-text-decor-3/#propdef-text-emphasis-color + types: [ 'color' ] + }, + 'text-emphasis-position': { + // http://dev.w3.org/csswg/css-text-decor-3/#propdef-text-emphasis-position + types: [ + { type: 'discrete', options: [ [ 'over', 'under left' ] ] } + ] + }, + 'text-emphasis-style': { + // http://dev.w3.org/csswg/css-text-decor-3/#propdef-text-emphasis-style + types: [ + { type: 'discrete', options: [ [ 'circle', 'open dot' ] ] } + ] + }, + 'text-group-align': { + // https://drafts.csswg.org/css-text-4/#propdef-text-group-align + types: [ + { type: 'discrete', options: [ [ 'none', 'center' ] ] } + ] + }, + 'text-indent': { + // https://drafts.csswg.org/css-text-3/#propdef-text-indent + types: [ + ] + }, + 'text-overflow': { + // https://drafts.csswg.org/css-ui/#propdef-text-overflow + types: [ + { type: 'discrete', options: [ [ 'clip', 'ellipsis' ] ] } + ] + }, + 'text-rendering': { + // https://svgwg.org/svg2-draft/painting.html#TextRenderingProperty + types: [ + { type: 'discrete', options: [ [ 'optimizeSpeed', 'optimizeLegibility' ] ] } + ] + }, + 'text-shadow': { + // https://drafts.csswg.org/css-text-decor-3/#propdef-text-shadow + types: [ 'textShadowList' ], + setup: t => { + const element = createElement(t); + element.style.color = 'green'; + return element; + } + }, + 'text-transform': { + // https://drafts.csswg.org/css-text-3/#propdef-text-transform + types: [ + { type: 'discrete', options: [ [ 'capitalize', 'uppercase' ] ] } + ] + }, + 'text-wrap': { + // https://drafts.csswg.org/css-text-4/#propdef-text-wrap + types: [ + { type: 'discrete', options: [ [ 'wrap', 'nowrap' ] ] } + ] + }, + 'touch-action': { + // https://w3c.github.io/pointerevents/#the-touch-action-css-property + types: [ + { type: 'discrete', options: [ [ 'auto', 'none' ] ] } + ] + }, + 'top': { + // https://drafts.csswg.org/css-position/#propdef-top + types: [ + ] + }, + 'transform': { + // https://drafts.csswg.org/css-transforms/#propdef-transform + types: [ 'transformList' ] + }, + 'transform-box': { + // https://drafts.csswg.org/css-transforms/#propdef-transform-box + types: [ + { type: 'discrete', options: [ [ 'fill-box', 'border-box' ] ] } + ] + }, + 'transform-origin': { + // https://drafts.csswg.org/css-transforms/#propdef-transform-origin + types: [ + ] + }, + 'transform-style': { + // https://drafts.csswg.org/css-transforms/#propdef-transform-style + types: [ + { type: 'discrete', options: [ [ 'flat', 'preserve-3d' ] ] } + ] + }, + 'rotate': { + // https://drafts.csswg.org/css-transforms-2/#individual-transforms + types: [ 'rotateList' ] + }, + 'translate': { + // https://drafts.csswg.org/css-transforms-2/#individual-transforms + types: [ 'translateList' ], + setup: t => { + // We need to set a width/height for resolving percentages against. + const element = createElement(t); + element.style.width = '100px'; + element.style.height = '100px'; + return element; + } + }, + 'scale': { + // https://drafts.csswg.org/css-transforms-2/#individual-transforms + types: [ 'scaleList' ] + }, + 'vector-effect': { + // https://svgwg.org/svg2-draft/coords.html#VectorEffectProperty + types: [ + { type: 'discrete', options: [ [ 'none', 'non-scaling-stroke' ] ] }, + ] + }, + 'vertical-align': { + // https://drafts.csswg.org/css21/visudet.html#propdef-vertical-align + types: [ + ] + }, + 'visibility': { + // https://drafts.csswg.org/css2/visufx.html#propdef-visibility + types: [ 'visibility' ] + }, + 'white-space': { + // https://drafts.csswg.org/css-text-4/#propdef-white-space + types: [ + { type: 'discrete', options: [ [ 'pre', 'nowrap' ] ] } + ] + }, + 'width': { + // https://drafts.csswg.org/css21/visudet.html#propdef-width + types: [ + ] + }, + 'word-break': { + // https://drafts.csswg.org/css-text-3/#propdef-word-break + types: [ + { type: 'discrete', options: [ [ 'keep-all', 'break-all' ] ] } + ] + }, + 'word-spacing': { + // https://drafts.csswg.org/css-text-3/#propdef-word-spacing + types: [ 'lengthPercentageOrCalc' ] + }, + 'z-index': { + // https://drafts.csswg.org/css-position/#propdef-z-index + types: [ + ] + }, +}; + +function testAnimationSamples(animation, idlName, testSamples) { + const pseudoType = animation.effect.pseudoElement; + const target = animation.effect.target; + for (const testSample of testSamples) { + animation.currentTime = testSample.time; + assert_equals(getComputedStyle(target, pseudoType)[idlName].toLowerCase(), + testSample.expected, + `The value should be ${testSample.expected}` + + ` at ${testSample.time}ms`); + } +} + +function toOrderedArray(string) { + return string.split(/\s*,\s/).sort(); +} + +// This test is for some list-based CSS properties such as font-variant-settings +// don't specify an order for serializing computed values. +// This test is for such the property. +function testAnimationSamplesWithAnyOrder(animation, idlName, testSamples) { + const type = animation.effect.pseudoElement; + const target = animation.effect.target; + for (const testSample of testSamples) { + animation.currentTime = testSample.time; + + // Convert to array and sort the expected and actual value lists first + // before comparing them. + const computedValues = + toOrderedArray(getComputedStyle(target, type)[idlName]); + const expectedValues = toOrderedArray(testSample.expected); + + assert_array_equals(computedValues, expectedValues, + `The computed values should be ${expectedValues}` + + ` at ${testSample.time}ms`); + } +} + +function RoundMatrix(style) { + var matrixMatch = style.match(/^(matrix(3d)?)\(.+\)$/); + if (!!matrixMatch) { + var matrixType = matrixMatch[1]; + var matrixArgs = style.substr(matrixType.length); + var extractmatrix = function(matrixStr) { + var list = []; + var regex = /[+\-]?[0-9]+[.]?[0-9]*(e[+/-][0-9]+)?/g; + var match = undefined; + do { + match = regex.exec(matrixStr); + if (match) { + list.push(parseFloat(parseFloat(match[0]).toFixed(6))); + } + } while (match); + return list; + } + return matrixType + '(' + extractmatrix(matrixArgs).join(', ') + ')'; + } + return style; +} + +function testAnimationSampleMatrices(animation, idlName, testSamples) { + const target = animation.effect.target; + for (const testSample of testSamples) { + animation.currentTime = testSample.time; + const actual = RoundMatrix(getComputedStyle(target)[idlName]); + const expected = RoundMatrix(createMatrixFromArray(testSample.expected)); + assert_matrix_equals(actual, expected, + `The value should be ${expected} at` + + ` ${testSample.time}ms but got ${actual}`); + } +} + +function testAnimationSampleRotate3d(animation, idlName, testSamples) { + const target = animation.effect.target; + for (const testSample of testSamples) { + animation.currentTime = testSample.time; + const actual = getComputedStyle(target)[idlName]; + const expected = testSample.expected; + assert_rotate3d_equals(actual, expected, + `The value should be ${expected} at` + + ` ${testSample.time}ms but got ${actual}`); + } +} + +function createTestElement(t, setup) { + return setup ? setup(t) : createElement(t); +} + +function isSupported(property) { + const testKeyframe = new TestKeyframe(propertyToIDL(property)); + assert_not_equals(window.KeyframeEffect, undefined, 'window.KeyframeEffect'); + try { + // Since TestKeyframe returns 'undefined' for |property|, + // the KeyframeEffect constructor will throw + // if the string 'undefined' is not a valid value for the property. + new KeyframeEffect(null, testKeyframe); + } catch(e) {} + return testKeyframe.propAccessCount !== 0; +} + +function TestKeyframe(testProp) { + let _propAccessCount = 0; + + Object.defineProperty(this, testProp, { + get: function() { _propAccessCount++; }, + enumerable: true + }); + + Object.defineProperty(this, 'propAccessCount', { + get: function() { return _propAccessCount; } + }); +} + +function propertyToIDL(property) { + // https://drafts.csswg.org/web-animations/#animation-property-name-to-idl-attribute-name + if (property === 'float') { + return 'cssFloat'; + } + return property.replace(/-[a-z]/gi, + function (str) { + return str.substr(1).toUpperCase(); }); +} +function calcFromPercentage(idlName, percentageValue) { + const examElem = document.createElement('div'); + document.body.appendChild(examElem); + examElem.style[idlName] = percentageValue; + + const calcValue = getComputedStyle(examElem)[idlName]; + document.body.removeChild(examElem); + + return calcValue; +} diff --git a/testing/web-platform/tests/web-animations/animation-model/animation-types/property-types.js b/testing/web-platform/tests/web-animations/animation-model/animation-types/property-types.js new file mode 100644 index 0000000000..6f39020b5c --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/animation-types/property-types.js @@ -0,0 +1,2769 @@ +'use strict'; + +const discreteType = { + testInterpolation: (property, setup, options) => { + for (const keyframes of options) { + const [ from, to ] = keyframes; + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: [from, to] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: from.toLowerCase() }, + { time: 499, expected: from.toLowerCase() }, + { time: 500, expected: to.toLowerCase() }, + { time: 1000, expected: to.toLowerCase() }]); + }, `${property} uses discrete animation when animating between` + + ` "${from}" and "${to}" with linear easing`); + + test(t => { + // Easing: http://cubic-bezier.com/#.68,0,1,.01 + // With this curve, we don't reach the 50% point until about 95% of + // the time has expired. + const idlName = propertyToIDL(property); + const keyframes = {}; + const target = createTestElement(t, setup); + const animation = target.animate( + { [idlName]: [from, to] }, + { + duration: 1000, + fill: 'both', + easing: 'cubic-bezier(0.68,0,1,0.01)', + } + ); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: from.toLowerCase() }, + { time: 940, expected: from.toLowerCase() }, + { time: 960, expected: to.toLowerCase() }]); + }, `${property} uses discrete animation when animating between` + + ` "${from}" and "${to}" with effect easing`); + + test(t => { + // Easing: http://cubic-bezier.com/#.68,0,1,.01 + // With this curve, we don't reach the 50% point until about 95% of + // the time has expired. + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { + [idlName]: [from, to], + easing: 'cubic-bezier(0.68,0,1,0.01)', + }, + { duration: 1000, fill: 'both' } + ); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: from.toLowerCase() }, + { time: 940, expected: from.toLowerCase() }, + { time: 960, expected: to.toLowerCase() }]); + }, `${property} uses discrete animation when animating between` + + ` "${from}" and "${to}" with keyframe easing`); + } + }, + + testAdditionOrAccumulation: (property, setup, options, composite) => { + for (const keyframes of options) { + const [ from, to ] = keyframes; + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.animate({ [idlName]: [from, from] }, 1000); + const animation = target.animate( + { [idlName]: [to, to] }, + { duration: 1000, composite } + ); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: to.toLowerCase() }]); + }, `${property}: "${to}" onto "${from}"`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.animate({ [idlName]: [to, to] }, 1000); + const animation = target.animate( + { [idlName]: [from, from] }, + { duration: 1000, composite } + ); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: from.toLowerCase() }]); + }, `${property}: "${from}" onto "${to}"`); + } + }, + + testAddition: function(property, setup, options) { + this.testAdditionOrAccumulation(property, setup, options, 'add'); + }, + + testAccumulation: function(property, setup, options) { + this.testAdditionOrAccumulation(property, setup, options, 'accumulate'); + }, +}; + +const lengthType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['10px', '50px'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '30px' }]); + }, `${property} supports animating as a length`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['1rem', '5rem'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '30px' }]); + }, `${property} supports animating as a length of rem`); + }, + + testAdditionOrAccumulation: (property, setup, composite) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '10px'; + const animation = target.animate( + { [idlName]: ['10px', '50px'] }, + { duration: 1000, composite } + ); + testAnimationSamples(animation, idlName, [{ time: 0, expected: '20px' }]); + }, `${property}: length`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '1rem'; + const animation = target.animate( + { [idlName]: ['1rem', '5rem'] }, + { duration: 1000, composite } + ); + testAnimationSamples(animation, idlName, [{ time: 0, expected: '20px' }]); + }, `${property}: length of rem`); + }, + + testAddition: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'add'); + }, + + testAccumulation: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'accumulate'); + }, +}; + +const lengthPairType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { [idlName]: ['10px 10px', '50px 50px'] }, + { duration: 1000, fill: 'both' } + ); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '30px 30px' }]); + }, `${property} supports animating as a length pair`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { [idlName]: ['1rem 1rem', '5rem 5rem'] }, + { duration: 1000, fill: 'both' } + ); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '30px 30px' }]); + }, `${property} supports animating as a length pair of rem`); + }, + + testAdditionOrAccumulation: (property, setup, composite) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '10px 10px'; + const animation = target.animate( + { [idlName]: ['10px 10px', '50px 50px'] }, + { duration: 1000, composite } + ); + testAnimationSamples( + animation, + idlName, + [{ time: 0, expected: '20px 20px' }] + ); + }, `${property}: length pair`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '1rem 1rem'; + const animation = target.animate( + { [idlName]: ['1rem 1rem', '5rem 5rem'] }, + { duration: 1000, composite } + ); + testAnimationSamples( + animation, + idlName, + [{ time: 0, expected: '20px 20px' }] + ); + }, `${property}: length pair of rem`); + }, + + testAddition: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'add'); + }, + + testAccumulation: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'accumulate'); + }, +}; + +const percentageType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['10%', '50%'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '30%' }]); + }, `${property} supports animating as a percentage`); + }, + + testAdditionOrAccumulation: (property, setup, composite) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '60%'; + const animation = target.animate( + { [idlName]: ['70%', '100%'] }, + { duration: 1000, composite } + ); + testAnimationSamples(animation, idlName, [{ time: 0, expected: '130%' }]); + }, `${property}: percentage`); + }, + + testAddition: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'add'); + }, + + testAccumulation: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'accumulate'); + }, +}; + +const integerType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: [-2, 2] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '0' }]); + }, `${property} supports animating as an integer`); + }, + + testAdditionOrAccumulation: (property, setup, composite) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = -1; + const animation = target.animate( + { [idlName]: [-2, 2] }, + { duration: 1000, composite } + ); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '-3' }]); + }, `${property}: integer`); + }, + + testAddition: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'add'); + }, + + testAccumulation: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'accumulate'); + }, +}; + +const positiveIntegerType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: [1, 3] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [ { time: 500, expected: '2' } ]); + }, `${property} supports animating as a positive integer`); + }, + + testAdditionOrAccumulation: (property, setup, composite) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 1; + const animation = target.animate( + { [idlName]: [2, 5] }, + { duration: 1000, composite } + ); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '3' }]); + }, `${property}: positive integer`); + }, + + testAddition: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'add'); + }, + + testAccumulation: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'accumulate'); + }, +}; + +const lengthPercentageOrCalcType = { + testInterpolation: (property, setup) => { + lengthType.testInterpolation(property, setup); + percentageType.testInterpolation(property, setup); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['10px', '20%'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'calc(10% + 5px)' }]); + }, `${property} supports animating as combination units "px" and "%"`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['10%', '2em'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'calc(5% + 10px)' }]); + }, `${property} supports animating as combination units "%" and "em"`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['1em', '2rem'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '15px' }]); + }, `${property} supports animating as combination units "em" and "rem"`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { [idlName]: ['10px', 'calc(1em + 20%)'] }, + { duration: 1000, fill: 'both' } + ); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'calc(10% + 10px)' }]); + }, `${property} supports animating as combination units "px" and "calc"`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { [idlName]: ['calc(10px + 10%)', 'calc(1em + 1rem + 20%)'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, + expected: 'calc(15% + 15px)' }]); + }, `${property} supports animating as a calc`); + }, + + testAdditionOrAccumulation: (property, setup, composite) => { + lengthType.testAddition(property, setup); + percentageType.testAddition(property, setup); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '10px'; + const animation = target.animate({ [idlName]: ['10%', '50%'] }, + { duration: 1000, composite }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'calc(10% + 10px)' }]); + }, `${property}: units "%" onto "px"`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '10%'; + const animation = target.animate({ [idlName]: ['10px', '50px'] }, + { duration: 1000, composite }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'calc(10% + 10px)' }]); + }, `${property}: units "px" onto "%"`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '10%'; + const animation = target.animate({ [idlName]: ['2rem', '5rem'] }, + { duration: 1000, composite }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'calc(10% + 20px)' }]); + }, `${property}: units "rem" onto "%"`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '2rem'; + const animation = target.animate({ [idlName]: ['10%', '50%'] }, + { duration: 1000, composite }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'calc(10% + 20px)' }]); + }, `${property}: units "%" onto "rem"`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '2em'; + const animation = target.animate({ [idlName]: ['2rem', '5rem'] }, + { duration: 1000, composite }); + testAnimationSamples(animation, idlName, [{ time: 0, expected: '40px' }]); + }, `${property}: units "rem" onto "em"`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '2rem'; + const animation = target.animate({ [idlName]: ['2em', '5em'] }, + { duration: 1000, composite }); + testAnimationSamples(animation, idlName, [{ time: 0, expected: '40px' }]); + }, `${property}: units "em" onto "rem"`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '10px'; + const animation = target.animate({ [idlName]: ['calc(2em + 20%)', + 'calc(5rem + 50%)'] }, + { duration: 1000, composite }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'calc(20% + 30px)' }]); + }, `${property}: units "calc" onto "px"`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'calc(10px + 10%)'; + const animation = target.animate({ [idlName]: ['calc(20px + 20%)', + 'calc(2em + 3rem + 40%)'] }, + { duration: 1000, composite }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'calc(30% + 30px)' }]); + }, `${property}: calc`); + }, + + testAddition: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'add'); + }, + + testAccumulation: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'accumulate'); + }, +}; + +const positiveNumberType = { + testInterpolation: (property, setup, expectedUnit='') => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: [1.1, 1.5] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '1.3' + expectedUnit }]); + }, `${property} supports animating as a positive number`); + }, + + testAdditionOrAccumulation: (property, setup, composite) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 1.1; + const animation = target.animate({ [idlName]: [1.1, 1.5] }, + { duration: 1000, composite }); + testAnimationSamples(animation, idlName, [{ time: 0, expected: '2.2' }]); + }, `${property}: positive number`); + }, + + testAddition: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'add'); + }, + + testAccumulation: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'accumulate'); + }, +}; + +// Test using float values in the range [0, 1] +const opacityType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: [0.3, 0.8] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '0.55' }]); + }, `${property} supports animating as a [0, 1] number`); + }, + + testAdditionOrAccumulation: (property, setup, composite) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 0.3; + const animation = target.animate({ [idlName]: [0.3, 0.8] }, + { duration: 1000, composite }); + testAnimationSamples(animation, idlName, [{ time: 0, expected: '0.6' }]); + }, `${property}: [0, 1] number`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 0.8; + const animation = target.animate({ [idlName]: [0.3, 0.8] }, + { duration: 1000, composite }); + testAnimationSamples(animation, idlName, [{ time: 0, expected: '1' }]); + }, `${property}: [0, 1] number (clamped)`); + }, + + testAddition: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'add'); + }, + + testAccumulation: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'accumulate'); + }, +}; + +const visibilityType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['visible', 'hidden'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'visible' }, + { time: 999, expected: 'visible' }, + { time: 1000, expected: 'hidden' }]); + }, `${property} uses visibility animation when animating` + + ' from "visible" to "hidden"'); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['hidden', 'visible'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'hidden' }, + { time: 1, expected: 'visible' }, + { time: 1000, expected: 'visible' }]); + }, `${property} uses visibility animation when animating` + + ' from "hidden" to "visible"'); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['hidden', 'collapse'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'hidden' }, + { time: 499, expected: 'hidden' }, + { time: 500, expected: 'collapse' }, + { time: 1000, expected: 'collapse' }]); + }, `${property} uses visibility animation when animating` + + ' from "hidden" to "collapse"'); + + test(t => { + // Easing: http://cubic-bezier.com/#.68,-.55,.26,1.55 + // With this curve, the value is less than 0 till about 34% + // also more than 1 since about 63% + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: ['visible', 'hidden'] }, + { duration: 1000, fill: 'both', + easing: 'cubic-bezier(0.68, -0.55, 0.26, 1.55)' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'visible' }, + { time: 1, expected: 'visible' }, + { time: 330, expected: 'visible' }, + { time: 340, expected: 'visible' }, + { time: 620, expected: 'visible' }, + { time: 630, expected: 'hidden' }, + { time: 1000, expected: 'hidden' }]); + }, `${property} uses visibility animation when animating` + + ' from "visible" to "hidden" with easeInOutBack easing'); + }, + + testAdditionOrAccumulation: (property, setup, composite) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'visible'; + const animation = target.animate({ [idlName]: ['visible', 'hidden'] }, + { duration: 1000, fill: 'both', + composite }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'visible' }, + { time: 1000, expected: 'hidden' }]); + }, `${property}: onto "visible"`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'hidden'; + const animation = target.animate({ [idlName]: ['hidden', 'visible'] }, + { duration: 1000, fill: 'both', + composite }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'hidden' }, + { time: 1000, expected: 'visible' }]); + }, `${property}: onto "hidden"`); + }, + + testAddition: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'add'); + }, + + testAccumulation: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'accumulate'); + }, +}; + +const colorType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['rgb(255, 0, 0)', + 'rgb(0, 0, 255)'] }, + 1000); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgb(128, 0, 128)' }]); + }, `${property} supports animating as color of rgb()`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['#ff0000', '#0000ff'] }, + 1000); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgb(128, 0, 128)' }]); + }, `${property} supports animating as color of #RGB`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['hsl(0, 100%, 50%)', + 'hsl(240, 100%, 50%)'] }, + 1000); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgb(128, 0, 128)' }]); + }, `${property} supports animating as color of hsl()`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { [idlName]: ['#ff000066', '#0000ffcc'] }, + 1000 + ); + // R: 255 * (0.4 * 0.5) / 0.6 = 85 + // B: 255 * (0.8 * 0.5) / 0.6 = 170 + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgba(85, 0, 170, 0.6)' }]); + }, `${property} supports animating as color of #RGBa`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { + [idlName]: ['rgba(255, 0, 0, 0.4)', 'rgba(0, 0, 255, 0.8)'], + }, + 1000 + ); + testAnimationSamples(animation, idlName, // Same as above. + [{ time: 500, expected: 'rgba(85, 0, 170, 0.6)' }]); + }, `${property} supports animating as color of rgba()`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { + [idlName]: ['hsla(0, 100%, 50%, 0.4)', 'hsla(240, 100%, 50%, 0.8)'], + }, + 1000 + ); + testAnimationSamples(animation, idlName, // Same as above. + [{ time: 500, expected: 'rgba(85, 0, 170, 0.6)' }]); + }, `${property} supports animating as color of hsla()`); + }, + + testAdditionOrAccumulation: (property, setup, composite) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rgb(128, 128, 128)'; + const animation = target.animate( + { + [idlName]: ['rgb(255, 0, 0)', 'rgb(0, 0, 255)'], + }, + { duration: 1000, composite } + ); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'rgb(255, 128, 128)' }, + // The value at 50% is interpolated + // from 'rgb(128+255, 128, 128)' + // to 'rgb(128, 128, 128+255)'. + { time: 500, expected: 'rgb(255, 128, 255)' }]); + }, `${property} supports animating as color of rgb() with overflowed ` + + ' from and to values'); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rgb(128, 128, 128)'; + const animation = target.animate({ [idlName]: ['#ff0000', '#0000ff'] }, + { duration: 1000, composite }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'rgb(255, 128, 128)' }]); + }, `${property} supports animating as color of #RGB`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rgb(128, 128, 128)'; + const animation = target.animate({ [idlName]: ['hsl(0, 100%, 50%)', + 'hsl(240, 100%, 50%)'] }, + { duration: 1000, composite }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'rgb(255, 128, 128)' }]); + }, `${property} supports animating as color of hsl()`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rgb(128, 128, 128)'; + const animation = target.animate( + { [idlName]: ['#ff000066', '#0000ffcc'] }, + { duration: 1000, composite } + ); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'rgb(230, 128, 128)' }]); + }, `${property} supports animating as color of #RGBa`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rgb(128, 128, 128)'; + const animation = target.animate({ [idlName]: ['rgba(255, 0, 0, 0.4)', + 'rgba(0, 0, 255, 0.8)'] }, + { duration: 1000, composite }); + testAnimationSamples(animation, idlName, // Same as above. + [{ time: 0, expected: 'rgb(230, 128, 128)' }]); + }, `${property} supports animating as color of rgba()`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rgb(128, 128, 128)'; + const animation = target.animate( + { + [idlName]: ['hsla(0, 100%, 50%, 0.4)', 'hsla(240, 100%, 50%, 0.8)'], + }, + { duration: 1000, composite } + ); + testAnimationSamples(animation, idlName, // Same as above. + [{ time: 0, expected: 'rgb(230, 128, 128)' }]); + }, `${property} supports animating as color of hsla()`); + }, + + testAddition: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'add'); + }, + + testAccumulation: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'accumulate'); + }, +}; + +const transformListType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { + [idlName]: ['translate(200px, -200px)', 'translate(400px, 400px)'], + }, + 1000 + ); + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ 1, 0, 0, 1, 300, 100 ] }]); + }, `${property}: translate`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { + [idlName]: ['rotate(45deg)', 'rotate(135deg)'], + }, + 1000 + ); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ Math.cos(Math.PI / 2), + Math.sin(Math.PI / 2), + -Math.sin(Math.PI / 2), + Math.cos(Math.PI / 2), + 0, 0] }]); + }, `${property}: rotate`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['scale(3)', 'scale(5)'] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ 4, 0, 0, 4, 0, 0 ] }]); + }, `${property}: scale`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['skew(30deg, 60deg)', + 'skew(60deg, 30deg)'] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ 1, Math.tan(Math.PI / 4), + Math.tan(Math.PI / 4), 1, + 0, 0] }]); + }, `${property}: skew`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: ['translateX(100px) rotate(45deg)', + 'translateX(200px) rotate(135deg)'] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ Math.cos(Math.PI / 2), + Math.sin(Math.PI / 2), + -Math.sin(Math.PI / 2), + Math.cos(Math.PI / 2), + 150, 0 ] }]); + }, `${property}: rotate and translate`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: ['rotate(45deg) translateX(100px)', + 'rotate(135deg) translateX(200px)'] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ Math.cos(Math.PI / 2), + Math.sin(Math.PI / 2), + -Math.sin(Math.PI / 2), + Math.cos(Math.PI / 2), + 150 * Math.cos(Math.PI / 2), + 150 * Math.sin(Math.PI / 2) ] }]); + }, `${property}: translate and rotate`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: ['rotate(0deg)', + 'rotate(1080deg) translateX(100px)'] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ -1, 0, 0, -1, -50, 0 ] }]); + }, `${property}: extend shorter list (from)`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: ['rotate(0deg) translateX(100px)', + 'rotate(1080deg)'] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ -1, 0, 0, -1, -50, 0 ] }]); + }, `${property}: extend shorter list (to)`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = // matrix(0, 1, -1, 0, 0, 100) + target.animate({ [idlName]: ['rotate(90deg) translateX(100px)', + // matrix(-1, 0, 0, -1, 200, 0) + 'translateX(200px) rotate(180deg)'] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ Math.cos(Math.PI * 3 / 4), + Math.sin(Math.PI * 3 / 4), + -Math.sin(Math.PI * 3 / 4), + Math.cos(Math.PI * 3 / 4), + 100, 50 ] }]); + }, `${property}: mismatch order of translate and rotate`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = // Same matrices as above. + target.animate({ [idlName]: [ 'matrix(0, 1, -1, 0, 0, 100)', + 'matrix(-1, 0, 0, -1, 200, 0)' ] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ Math.cos(Math.PI * 3 / 4), + Math.sin(Math.PI * 3 / 4), + -Math.sin(Math.PI * 3 / 4), + Math.cos(Math.PI * 3 / 4), + 100, 50 ] }]); + }, `${property}: matrix`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ 'rotate3d(1, 1, 0, 0deg)', + 'rotate3d(1, 1, 0, 90deg)'] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: rotate3dToMatrix(1, 1, 0, Math.PI / 4) }]); + }, `${property}: rotate3d`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + // To calculate expected matrices easily, generate input matrices from + // rotate3d. + const from = rotate3dToMatrix3d(1, 1, 0, Math.PI / 4); + const to = rotate3dToMatrix3d(1, 1, 0, Math.PI * 3 / 4); + const animation = target.animate({ [idlName]: [ from, to ] }, 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: rotate3dToMatrix(1, 1, 0, Math.PI * 2 / 4) }]); + }, `${property}: matrix3d`); + + // This test aims for forcing the two mismatched transforms to be + // decomposed into matrix3d before interpolation. Therefore, we not only + // test the interpolation, but also test the 3D matrix decomposition. + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { + [idlName]: [ + 'scale(0.3)', + // scale(0.5) translateZ(1px) + 'matrix3d(0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1)', + ], + }, + 1000 + ); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ 0.4, 0, 0, 0, + 0, 0.4, 0, 0, + 0, 0, 1, 0, + 0, 0, 0.5, 1] }]); + }, `${property}: mismatched 3D transforms`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: ['rotateY(60deg)', 'none' ] }, 1000); + + testAnimationSampleMatrices(animation, idlName, + // rotateY(30deg) == rotate3D(0, 1, 0, 30deg) + [{ time: 500, expected: rotate3dToMatrix(0, 1, 0, Math.PI / 6) }]); + }, `${property}: rotateY`); + + // Following tests aim for test the fallback discrete interpolation behavior + // for non-invertible matrices. The non-invertible matrix that we use is the + // singular matrix, matrix(1, 1, 0, 0, 0, 100). + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: ['matrix(-1, 0, 0, -1, 200, 0)', + 'matrix( 1, 1, 0, 0, 0, 100)'] }, + { duration: 1000, fill: 'both' }); + + testAnimationSampleMatrices(animation, idlName, + [ { time: 0, expected: [ -1, 0, 0, -1, 200, 0 ] }, + { time: 499, expected: [ -1, 0, 0, -1, 200, 0 ] }, + { time: 500, expected: [ 1, 1, 0, 0, 0, 100 ] }, + { time: 1000, expected: [ 1, 1, 0, 0, 0, 100 ] }]); + }, `${property}: non-invertible matrices`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { + [idlName]: [ + // matrix(0, -1, 1, 0, 250, 0) + 'translate(50px) matrix(-1, 0, 0, -1, 200, 0) rotate(90deg)', + // matrix(-1, -1, 0, 0, 100, 100) + 'translate(100px) matrix( 1, 1, 0, 0, 0, 100) rotate(180deg)', + ], + }, + { duration: 1000, fill: 'both' } + ); + + testAnimationSampleMatrices(animation, idlName, + [ { time: 0, expected: [ 0, -1, 1, 0, 250, 0 ] }, + { time: 499, expected: [ 0, -1, 1, 0, 250, 0 ] }, + { time: 500, expected: [ -1, -1, 0, 0, 100, 100 ] }, + { time: 1000, expected: [ -1, -1, 0, 0, 100, 100 ] }]); + }, `${property}: non-invertible matrices in matched transform lists`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { + [idlName]: [ + // matrix(-2, 0, 0, -2, 250, 0) + 'translate(50px) matrix(-1, 0, 0, -1, 200, 0) scale(2)', + // matrix(1, 1, 1, 1, 100, 100) + 'translate(100px) matrix( 1, 1, 0, 0, 0, 100) skew(45deg)', + ], + }, + { duration: 1000, fill: 'both' } + ); + + testAnimationSampleMatrices(animation, idlName, + [ { time: 0, expected: [ -2, 0, 0, -2, 250, 0 ] }, + { time: 499, expected: [ -2, 0, 0, -2, 250, 0 ] }, + { time: 500, expected: [ 1, 1, 1, 1, 100, 100 ] }, + { time: 1000, expected: [ 1, 1, 1, 1, 100, 100 ] }]); + }, `${property}: non-invertible matrices in mismatched transform lists`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { + // perspective(0) is treated as perspective(1px) + [idlName]: ['perspective(0)', 'perspective(10px)'], + }, + 1000 + ); + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, -0.55, + 0, 0, 0, 1 ] }]); + }, `${property}: perspective`); + + }, + + testAddition: function(property, setup) { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'translateX(100px)'; + const animation = target.animate({ [idlName]: ['translateX(-200px)', + 'translateX(500px)'] }, + { duration: 1000, fill: 'both', + composite: 'add' }); + testAnimationSampleMatrices(animation, idlName, + [ { time: 0, expected: [ 1, 0, 0, 1, -100, 0 ] }, + { time: 1000, expected: [ 1, 0, 0, 1, 600, 0 ] }]); + }, `${property}: translate`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rotate(45deg)'; + const animation = target.animate({ [idlName]: ['rotate(-90deg)', + 'rotate(90deg)'] }, + { duration: 1000, fill: 'both', + composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ Math.cos(-Math.PI / 4), + Math.sin(-Math.PI / 4), + -Math.sin(-Math.PI / 4), + Math.cos(-Math.PI / 4), + 0, 0] }, + { time: 1000, expected: [ Math.cos(Math.PI * 3 / 4), + Math.sin(Math.PI * 3 / 4), + -Math.sin(Math.PI * 3 / 4), + Math.cos(Math.PI * 3 / 4), + 0, 0] }]); + }, `${property}: rotate`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'scale(2)'; + const animation = target.animate({ [idlName]: ['scale(-3)', 'scale(5)'] }, + { duration: 1000, fill: 'both', + composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ -6, 0, 0, -6, 0, 0 ] }, // scale(-3) scale(2) + { time: 1000, expected: [ 10, 0, 0, 10, 0, 0 ] }]); // scale(5) scale(2) + }, `${property}: scale`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + // matrix(1, tan(10deg), tan(10deg), 1) + target.style[idlName] = 'skew(10deg, 10deg)'; + const animation = // matrix(1, tan(20deg), tan(-30deg), 1) + target.animate({ [idlName]: ['skew(-30deg, 20deg)', + // matrix(1, tan(-30deg), tan(20deg), 1) + 'skew(20deg, -30deg)'] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + // matrix at 0%. + // [ 1 tan(10deg) ] [ 1 tan(-30deg) ] + // [ tan(10deg) 1 ] [ tan(20deg) 1 ] = + // + // [ 1 + tan(10deg) * tan(20deg) tan(-30deg) + tan(10deg) ] + // [ tan(10deg) + tan(20deg) tan(10deg) * tan(-30deg) + 1 ] + + // matrix at 100%. + // [ 1 tan(10deg) ] [ 1 tan(20deg) ] + // [ tan(10deg) 1 ] [ tan(-30deg) 1 ] = + // + // [ 1 + tan(10deg) * tan(-30deg) tan(20deg) + tan(10deg) ] + // [ tan(10deg) + tan(-30deg) tan(10deg) * tan(20deg) + 1 ] + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ 1 + Math.tan(Math.PI/18) * Math.tan(Math.PI/9), + Math.tan(Math.PI/18) + Math.tan(Math.PI/9), + Math.tan(-Math.PI/6) + Math.tan(Math.PI/18), + 1 + Math.tan(Math.PI/18) * Math.tan(-Math.PI/6), + 0, 0] }, + { time: 1000, expected: [ 1 + Math.tan(Math.PI/18) * Math.tan(-Math.PI/6), + Math.tan(Math.PI/18) + Math.tan(-Math.PI/6), + Math.tan(Math.PI/9) + Math.tan(Math.PI/18), + 1 + Math.tan(Math.PI/18) * Math.tan(Math.PI/9), + 0, 0] }]); + }, `${property}: skew`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + // matrix(1, 0, 0, 1, 100, 0) + target.style[idlName] = 'translateX(100px)'; + const animation = // matrix(0, 1, -1, 0, 0, 0) + target.animate({ [idlName]: ['rotate(90deg)', + // matrix(-1, 0, 0, -1, 0, 0) + 'rotate(180deg)'] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ 0, 1, -1, 0, 100, 0 ] }, + { time: 1000, expected: [ -1, 0, 0, -1, 100, 0 ] }]); + }, `${property}: rotate on translate`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + // matrix(0, 1, -1, 0, 0, 0) + target.style[idlName] = 'rotate(90deg)'; + const animation = // matrix(1, 0, 0, 1, 100, 0) + target.animate({ [idlName]: ['translateX(100px)', + // matrix(1, 0, 0, 1, 200, 0) + 'translateX(200px)'] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ 0, 1, -1, 0, 0, 100 ] }, + { time: 1000, expected: [ 0, 1, -1, 0, 0, 200 ] }]); + }, `${property}: translate on rotate`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rotate(45deg) translateX(100px)'; + const animation = target.animate({ [idlName]: ['rotate(-90deg)', + 'rotate(90deg)'] }, + { duration: 1000, fill: 'both', + composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ Math.cos(-Math.PI / 4), + Math.sin(-Math.PI / 4), + -Math.sin(-Math.PI / 4), + Math.cos(-Math.PI / 4), + 100 * Math.cos(Math.PI / 4), + 100 * Math.sin(Math.PI / 4) ] }, + { time: 1000, expected: [ Math.cos(Math.PI * 3 / 4), + Math.sin(Math.PI * 3 / 4), + -Math.sin(Math.PI * 3 / 4), + Math.cos(Math.PI * 3 / 4), + 100 * Math.cos(Math.PI / 4), + 100 * Math.sin(Math.PI / 4) ] }]); + }, `${property}: rotate on rotate and translate`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'matrix(0, 1, -1, 0, 0, 0)'; + const animation = // Same matrices as above. + target.animate({ [idlName]: [ 'matrix(1, 0, 0, 1, 100, 0)', + 'matrix(1, 0, 0, 1, 200, 0)' ] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ 0, 1, -1, 0, 0, 100 ] }, + { time: 1000, expected: [ 0, 1, -1, 0, 0, 200 ] }]); + }, `${property}: matrix`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rotate3d(1, 1, 0, 45deg)'; + const animation = + target.animate({ [idlName]: [ 'rotate3d(1, 1, 0, -90deg)', + 'rotate3d(1, 1, 0, 90deg)'] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: rotate3dToMatrix(1, 1, 0, -Math.PI / 4) }, + { time: 1000, expected: rotate3dToMatrix(1, 1, 0, 3 * Math.PI / 4) }]); + }, `${property}: rotate3d`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + // To calculate expected matrices easily, generate input matrices from + // rotate3d. + target.style[idlName] = rotate3dToMatrix3d(1, 1, 0, Math.PI / 4); + const from = rotate3dToMatrix3d(1, 1, 0, -Math.PI / 2); + const to = rotate3dToMatrix3d(1, 1, 0, Math.PI / 2); + const animation = + target.animate({ [idlName]: [ from, to ] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: rotate3dToMatrix(1, 1, 0, -Math.PI / 4) }, + { time: 1000, expected: rotate3dToMatrix(1, 1, 0, 3 * Math.PI / 4) }]); + }, `${property}: matrix3d`); + + // Following tests aim for test the addition behavior for non-invertible + // matrices. Note that the addition for non-invertible matrices should be + // the same, just like addition for invertible matrices. With these tests, + // we can assure that addition never behaves as discrete. The non-invertible + // matrix that we use is the singular matrix, matrix(1, 1, 0, 0, 0, 100). + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'translateX(50px)'; + const animation = + target.animate({ [idlName]: ['matrix(-1, 0, 0, -1, 200, 0)', + 'matrix( 1, 1, 0, 0, 0, 100)'] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [ { time: 0, expected: [ -1, 0, 0, -1, 250, 0 ] }, + { time: 1000, expected: [ 1, 1, 0, 0, 50, 100 ] }]); + }, `${property}: non-invertible matrices`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'translateX(50px)'; + const animation = // matrix(0, -1, 1, 0, 200, 0) + target.animate({ [idlName]: ['matrix(-1, 0, 0, -1, 200, 0) rotate(90deg)', + // matrix(-1, -1, 0, 0, 0, 100) + 'matrix( 1, 1, 0, 0, 0, 100) rotate(180deg)'] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [ { time: 0, expected: [ 0, -1, 1, 0, 250, 0 ] }, + { time: 1000, expected: [ -1, -1, 0, 0, 50, 100 ] }]); + }, `${property}: non-invertible matrices in matched transform lists`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'translateX(50px)'; + const animation = // matrix(-2, 0, 0, -2, 200, 0) + target.animate({ [idlName]: ['matrix(-1, 0, 0, -1, 200, 0) scale(2)', + // matrix(1, 1, 1, 1, 0, 100) + 'matrix( 1, 1, 0, 0, 0, 100) skew(45deg)'] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [ { time: 0, expected: [ -2, 0, 0, -2, 250, 0 ] }, + { time: 1000, expected: [ 1, 1, 1, 1, 50, 100 ] }]); + }, `${property}: non-invertible matrices in mismatched transform lists`); + }, + + testAccumulation: function(property, setup) { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'translateX(100px)'; + const animation = target.animate({ [idlName]: ['translateX(-200px)', + 'translateX(500px)'] }, + { duration: 1000, fill: 'both', + composite: 'accumulate' }); + testAnimationSampleMatrices(animation, idlName, + [ { time: 0, expected: [ 1, 0, 0, 1, -100, 0 ] }, + { time: 1000, expected: [ 1, 0, 0, 1, 600, 0 ] }]); + }, `${property}: translate`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rotate(45deg)'; + const animation = target.animate({ [idlName]: ['rotate(-90deg)', + 'rotate(90deg)'] }, + { duration: 1000, fill: 'both', + composite: 'accumulate' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ Math.cos(-Math.PI / 4), + Math.sin(-Math.PI / 4), + -Math.sin(-Math.PI / 4), + Math.cos(-Math.PI / 4), + 0, 0] }, + { time: 1000, expected: [ Math.cos(Math.PI * 3 / 4), + Math.sin(Math.PI * 3 / 4), + -Math.sin(Math.PI * 3 / 4), + Math.cos(Math.PI * 3 / 4), + 0, 0] }]); + }, `${property}: rotate`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'scale(2)'; + const animation = target.animate({ [idlName]: ['scale(-3)', 'scale(5)'] }, + { duration: 1000, fill: 'both', + composite: 'accumulate' }); + + testAnimationSampleMatrices(animation, idlName, + // scale((2 - 1) + (-3 - 1) + 1) + [{ time: 0, expected: [ -2, 0, 0, -2, 0, 0 ] }, + // scale((2 - 1) + (5 - 1) + 1) + { time: 1000, expected: [ 6, 0, 0, 6, 0, 0 ] }]); + }, `${property}: scale`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + // matrix(1, tan(10deg), tan(10deg), 1) + target.style[idlName] = 'skew(10deg, 10deg)'; + const animation = // matrix(1, tan(20deg), tan(-30deg), 1) + target.animate({ [idlName]: ['skew(-30deg, 20deg)', + // matrix(1, tan(-30deg), tan(20deg), 1) + 'skew(20deg, -30deg)'] }, + { duration: 1000, fill: 'both', composite: 'accumulate' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ 1, Math.tan(Math.PI/6), + Math.tan(-Math.PI/9), 1, + 0, 0] }, + { time: 1000, expected: [ 1, Math.tan(-Math.PI/9), + Math.tan(Math.PI/6), 1, + 0, 0] }]); + }, `${property}: skew`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + // matrix(1, 0, 0, 1, 100, 0) + target.style[idlName] = 'translateX(100px)'; + const animation = // matrix(0, 1, -1, 0, 0, 0) + target.animate({ [idlName]: ['rotate(90deg)', + // matrix(-1, 0, 0, -1, 0, 0) + 'rotate(180deg)'] }, + { duration: 1000, fill: 'both', composite: 'accumulate' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ 0, 1, -1, 0, 100, 0 ] }, + { time: 1000, expected: [ -1, 0, 0, -1, 100, 0 ] }]); + }, `${property}: rotate on translate`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + // matrix(0, 1, -1, 0, 0, 0) + target.style[idlName] = 'rotate(90deg)'; + const animation = // matrix(1, 0, 0, 1, 100, 0) + target.animate({ [idlName]: ['translateX(100px)', + // matrix(1, 0, 0, 1, 200, 0) + 'translateX(200px)'] }, + { duration: 1000, fill: 'both', composite: 'accumulate' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ 0, 1, -1, 0, 100, 0 ] }, + { time: 1000, expected: [ 0, 1, -1, 0, 200, 0 ] }]); + }, `${property}: translate on rotate`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rotate(45deg)'; + const animation = + target.animate({ [idlName]: ['rotate(45deg) translateX(0px)', + 'rotate(45deg) translateX(100px)'] }, + { duration: 1000, fill: 'both', composite: 'accumulate' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ Math.cos(Math.PI / 2), + Math.sin(Math.PI / 2), + -Math.sin(Math.PI / 2), + Math.cos(Math.PI / 2), + 0 * Math.cos(Math.PI / 2), + 0 * Math.sin(Math.PI / 2) ] }, + { time: 1000, expected: [ Math.cos(Math.PI / 2), + Math.sin(Math.PI / 2), + -Math.sin(Math.PI / 2), + Math.cos(Math.PI / 2), + 100 * Math.cos(Math.PI / 2), + 100 * Math.sin(Math.PI / 2) ] }]); + }, `${property}: rotate and translate on rotate`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rotate(45deg) translateX(100px)'; + const animation = + target.animate({ [idlName]: ['rotate(45deg)', 'rotate(45deg)'] }, + { duration: 1000, fill: 'both', composite: 'accumulate' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ Math.cos(Math.PI / 2), + Math.sin(Math.PI / 2), + -Math.sin(Math.PI / 2), + Math.cos(Math.PI / 2), + 100 * Math.cos(Math.PI / 2), + 100 * Math.sin(Math.PI / 2) ] }, + { time: 1000, expected: [ Math.cos(Math.PI / 2), + Math.sin(Math.PI / 2), + -Math.sin(Math.PI / 2), + Math.cos(Math.PI / 2), + 100 * Math.cos(Math.PI / 2), + 100 * Math.sin(Math.PI / 2) ] }]); + }, `${property}: rotate on rotate and translate`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'matrix(0, 1, -1, 0, 0, 0)'; + const animation = // Same matrices as above. + target.animate({ [idlName]: [ 'matrix(1, 0, 0, 1, 100, 0)', + 'matrix(1, 0, 0, 1, 200, 0)' ] }, + { duration: 1000, fill: 'both', composite: 'accumulate' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ 0, 1, -1, 0, 100, 0 ] }, + { time: 1000, expected: [ 0, 1, -1, 0, 200, 0 ] }]); + }, `${property}: matrix`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rotate3d(1, 1, 0, 45deg)'; + const animation = + target.animate({ [idlName]: [ 'rotate3d(1, 1, 0, -90deg)', + 'rotate3d(1, 1, 0, 90deg)'] }, + { duration: 1000, fill: 'both', composite: 'accumulate' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: rotate3dToMatrix(1, 1, 0, -Math.PI / 4) }, + { time: 1000, expected: rotate3dToMatrix(1, 1, 0, 3 * Math.PI / 4) }]); + }, `${property}: rotate3d`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + // To calculate expected matrices easily, generate input matrices from + // rotate3d. + target.style[idlName] = rotate3dToMatrix3d(1, 1, 0, Math.PI / 4); + const from = rotate3dToMatrix3d(1, 1, 0, -Math.PI / 2); + const to = rotate3dToMatrix3d(1, 1, 0, Math.PI / 2); + const animation = + target.animate({ [idlName]: [ from, to ] }, + { duration: 1000, fill: 'both', composite: 'accumulate' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: rotate3dToMatrix(1, 1, 0, -Math.PI / 4) }, + { time: 1000, expected: rotate3dToMatrix(1, 1, 0, 3 * Math.PI / 4) }]); + }, `${property}: matrix3d`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const matrixArray = [ 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 1, 1 ]; + + target.style[idlName] = createMatrixFromArray(matrixArray); + const animation = + target.animate({ [idlName]: [ 'none', 'none' ] }, + { duration: 1000, fill: 'both', composite: 'accumulate' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: matrixArray }, + { time: 1000, expected: matrixArray }]); + }, `${property}: none`); + + // Following tests aim for test the fallback discrete accumulation behavior + // for non-invertible matrices. The non-invertible matrix that we use is the + // singular matrix, matrix(1, 1, 0, 0, 0, 100). + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.animate({ [idlName]: ['matrix(-1, 0, 0, -1, 200, 0)', + 'matrix(-1, 0, 0, -1, 200, 0)'] }, 1000); + const animation = target.animate( + { + [idlName]: [ + 'matrix( 1, 1, 0, 0, 0, 100)', + 'matrix( 1, 1, 0, 0, 0, 100)', + ], + }, + { duration: 1000, composite: 'accumulate' } + ); + testAnimationSampleMatrices(animation, idlName, [ + { time: 0, expected: [1, 1, 0, 0, 0, 100] }, + ]); + }, `${property}: non-invertible matrices (non-invertible onto invertible)`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.animate({ [idlName]: ['matrix( 1, 1, 0, 0, 0, 100)', + 'matrix( 1, 1, 0, 0, 0, 100)'] }, 1000); + const animation = target.animate( + { + [idlName]: [ + 'matrix(-1, 0, 0, -1, 200, 0)', + 'matrix(-1, 0, 0, -1, 200, 0)', + ], + }, + { duration: 1000, composite: 'accumulate' } + ); + testAnimationSampleMatrices(animation, idlName, [ + { time: 0, expected: [-1, 0, 0, -1, 200, 0] }, + ]); + }, `${property}: non-invertible matrices (invertible onto non-invertible)`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + // matrix(0, -1, 1, 0, 250, 0) + target.animate( + { + [idlName]: [ + 'translate(50px) matrix(-1, 0, 0, -1, 200, 0) rotate(90deg)', + 'translate(50px) matrix(-1, 0, 0, -1, 200, 0) rotate(90deg)', + ], + }, + 1000 + ); + // matrix(-1, -1, 0, 0, 100, 100) + const animation = target.animate( + { + [idlName]: [ + 'translate(100px) matrix( 1, 1, 0, 0, 0, 100) rotate(180deg)', + 'translate(100px) matrix( 1, 1, 0, 0, 0, 100) rotate(180deg)', + ], + }, + { duration: 1000, composite: 'accumulate' } + ); + testAnimationSampleMatrices(animation, idlName, [ + { time: 0, expected: [-1, -1, 0, 0, 100, 100] }, + ]); + }, `${property}: non-invertible matrices in matched transform lists (non-invertible onto invertible)`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + // matrix(-1, -1, 0, 0, 100, 100) + target.animate( + { + [idlName]: [ + 'translate(100px) matrix(1, 1, 0, 0, 0, 100) rotate(180deg)', + 'translate(100px) matrix(1, 1, 0, 0, 0, 100) rotate(180deg)', + ], + }, + 1000 + ); + // matrix(0, -1, 1, 0, 250, 0) + const animation = target.animate( + { + [idlName]: [ + 'translate(50px) matrix(-1, 0, 0, -1, 200, 0) rotate(90deg)', + 'translate(50px) matrix(-1, 0, 0, -1, 200, 0) rotate(90deg)', + ], + }, + { duration: 1000, composite: 'accumulate' } + ); + testAnimationSampleMatrices(animation, idlName, [ + { time: 0, expected: [0, -1, 1, 0, 250, 0] }, + ]); + }, `${property}: non-invertible matrices in matched transform lists (invertible onto non-invertible)`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + // matrix(-2, 0, 0, -2, 250, 0) + target.animate( + { + [idlName]: [ + 'translate(50px) matrix(-1, 0, 0, -1, 200, 0) scale(2)', + 'translate(50px) matrix(-1, 0, 0, -1, 200, 0) scale(2)', + ], + }, + 1000 + ); + // matrix(1, 1, 1, 1, 100, 100) + const animation = target.animate( + { + [idlName]: [ + 'translate(100px) matrix(1, 1, 0, 0, 0, 100) skew(45deg)', + 'translate(100px) matrix(1, 1, 0, 0, 0, 100) skew(45deg)', + ], + }, + { duration: 1000, composite: 'accumulate' } + ); + testAnimationSampleMatrices(animation, idlName, [ + { time: 0, expected: [1, 1, 1, 1, 100, 100] }, + ]); + }, `${property}: non-invertible matrices in mismatched transform lists` + + ' (non-invertible onto invertible)'); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + // matrix(1, 1, 1, 1, 100, 100) + target.animate( + { + [idlName]: [ + 'translate(100px) matrix(1, 1, 0, 0, 0, 100) skew(45deg)', + 'translate(100px) matrix(1, 1, 0, 0, 0, 100) skew(45deg)', + ], + }, + 1000 + ); + // matrix(-2, 0, 0, -2, 250, 0) + const animation = target.animate( + { + [idlName]: [ + 'translate(50px) matrix(-1, 0, 0, -1, 200, 0) scale(2)', + 'translate(50px) matrix(-1, 0, 0, -1, 200, 0) scale(2)', + ], + }, + { duration: 1000, composite: 'accumulate' } + ); + testAnimationSampleMatrices(animation, idlName, [ + { time: 0, expected: [-2, 0, 0, -2, 250, 0] }, + ]); + }, `${property}: non-invertible matrices in mismatched transform lists` + + ' (invertible onto non-invertible)'); + }, +}; + +const rotateListType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { + [idlName]: ['45deg', '135deg'], + }, + 1000 + ); + + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '90deg' }]); + }, `${property} without rotation axes`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ '0 1 0 0deg', + '0 1 0 90deg'] }, + 1000); + + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'y 45deg' }]); + }, `${property} with rotation axes`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + + const animation = + target.animate({ [idlName]: [ '0 1 0 0deg', + '0 1 0 720deg'] }, + 1000); + + testAnimationSamples(animation, idlName, + [{ time: 250, expected: 'y 180deg' }]); + }, `${property} with rotation axes and range over 360 degrees`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ '0 1 0 0deg', + '0 1 1 90deg'] }, + 1000); + + testAnimationSampleRotate3d(animation, idlName, + [{ time: 500, expected: '0 0.707107 0.707107 45deg' }]); + }, `${property} with different rotation axes`); + }, + testAddition: function(property, setup) { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '45deg'; + const animation = target.animate({ [idlName]: ['-90deg', '90deg'] }, + { duration: 1000, fill: 'both', + composite: 'add' }); + + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '-45deg' }, + { time: 1000, expected: '135deg' }]); + }, `${property} without rotation axes`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + // Rotation specified in transform property should not affect the computed + // value of |property|. + target.style.transform = 'rotate(20deg)'; + target.style[idlName] = 'y -45deg'; + const animation = + target.animate({ [idlName]: ['0 1 0 90deg', + '0 1 0 180deg'] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'y 45deg' }, + { time: 1000, expected: 'y 135deg' }]); + }, `${property} with underlying transform`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ '0 1 0 0deg', + '1 1 1 270deg'] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + testAnimationSampleRotate3d(animation, idlName, + [{ time: 500, expected: '0.57735 0.57735 0.57735 135deg' }]); + }, `${property} with different rotation axes`); + }, + testAccumulation: function(property, setup) { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '45deg'; + const animation = target.animate({ [idlName]: ['-90deg', '90deg'] }, + { duration: 1000, fill: 'both', + composite: 'accumulate' }); + + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '-45deg' }, + { time: 1000, expected: '135deg' }]); + }, `${property} without rotation axes`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style.transform = 'translateX(100px)'; + target.style[idlName] = '1 0 0 -45deg'; + const animation = + target.animate({ [idlName]: ['1 0 0 90deg', + '1 0 0 180deg'] }, + { duration: 1000, fill: 'both', composite: 'accumulate' }); + + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'x 45deg' }, + { time: 1000, expected: 'x 135deg' }]); + }, `${property} with underlying transform`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ '0 1 0 0deg', + '1 0 1 180deg'] }, + { duration: 1000, fill: 'both', composite: 'accumulate' }); + + testAnimationSampleRotate3d(animation, idlName, + [{ time: 500, expected: '0.707107 0 0.707107 90deg' }]); + }, `${property} with different rotation axes`); + }, +}; + +const translateListType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { + [idlName]: ['200px', '400px'], + }, + 1000 + ); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '300px' }]); + }, `${property} with two unspecified values`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { + [idlName]: ['200px -200px', '400px 400px'], + }, + 1000 + ); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '300px 100px' }]); + }, `${property} with one unspecified value`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { + [idlName]: ['200px -200px 600px', '400px 400px -200px'], + }, + 1000 + ); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '300px 100px 200px' }]); + }, `${property} with all three values specified`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { + [idlName]: ['0% -101px 600px', '400px 50% -200px'], + }, + 1000 + ); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'calc(0% + 200px) calc(25% - 50.5px) 200px' }]); + }, `${property} with combination of percentages and lengths`); + }, + testAddition: function(property, setup) { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '100px'; + const animation = target.animate({ [idlName]: ['-200px', '500px'] }, + { duration: 1000, fill: 'both', + composite: 'add' }); + testAnimationSamples(animation, idlName, + [ { time: 0, expected: '-100px' }, + { time: 1000, expected: '600px' }]); + + }, `${property}`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.transform = 'translateY(100px)'; + target.style[idlName] = '100px'; + const animation = target.animate({ [idlName]: ['-200px', '500px'] }, + { duration: 1000, fill: 'both', + composite: 'add' }); + testAnimationSamples(animation, idlName, + [ { time: 0, expected: '-100px' }, + { time: 1000, expected: '600px' }]); + + }, `${property} with underlying transform`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '50%'; + const animation = target.animate({ [idlName]: ['-200px', '500px'] }, + { duration: 1000, fill: 'both', + composite: 'add' }); + testAnimationSamples(animation, idlName, + [ { time: 0, expected: 'calc(50% - 200px)' }, + { time: 1000, expected: 'calc(50% + 500px)' }]); + + }, `${property} with underlying percentage value`); + }, + testAccumulation: function(property, setup) { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '100px'; + const animation = target.animate({ [idlName]: ['-200px', '500px'] }, + { duration: 1000, fill: 'both', + composite: 'accumulate' }); + testAnimationSamples(animation, idlName, + [ { time: 0, expected: '-100px' }, + { time: 1000, expected: '600px' }]); + }, `${property}`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.transform = 'translateY(100px)'; + target.style[idlName] = '100px'; + const animation = target.animate({ [idlName]: ['-200px', '500px'] }, + { duration: 1000, fill: 'both', + composite: 'accumulate' }); + testAnimationSamples(animation, idlName, + [ { time: 0, expected: '-100px' }, + { time: 1000, expected: '600px' }]); + }, `${property} with transform`); + }, +}; + +const scaleListType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['3', '5'] }, + 1000); + + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '4' }]); + }, `${property} with two unspecified values`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['3 3', '5 5'] }, + 1000); + + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '4' }]); + }, `${property} with one unspecified value`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['3 3 3', '5 5 5'] }, + 1000); + + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '4 4 4' }]); + }, `${property}`); + }, + testAddition: function(property, setup) { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '2'; + const animation = target.animate({ [idlName]: ['-3', '5'] }, + { duration: 1000, fill: 'both', + composite: 'add' }); + + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '-6' }, + { time: 1000, expected: '10' }]); + }, `${property} with two unspecified values`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '2 2'; + const animation = target.animate({ [idlName]: ['-3 -3', '5 5'] }, + { duration: 1000, fill: 'both', + composite: 'add' }); + + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '-6' }, + { time: 1000, expected: '10' }]); + }, `${property} with one unspecified value`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '2 2 2'; + const animation = target.animate({ [idlName]: ['-1 -2 -3', '4 5 6'] }, + { duration: 1000, fill: 'both', + composite: 'add' }); + + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '-2 -4 -6' }, + { time: 1000, expected: '8 10 12' }]); + }, `${property}`); + }, + testAccumulation: function(property, setup) { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '2'; + const animation = target.animate({ [idlName]: ['-3', '5'] }, + { duration: 1000, fill: 'both', + composite: 'accumulate' }); + + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '-2' }, + { time: 1000, expected: '6' }]); + }, `${property} with two unspecified values`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '2 2'; + const animation = target.animate({ [idlName]: ['-3 -3', '5 5'] }, + { duration: 1000, fill: 'both', + composite: 'accumulate' }); + + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '-2' }, + { time: 1000, expected: '6' }]); + }, `${property} with one unspecified value`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '2 2 2'; + const animation = target.animate({ [idlName]: ['-1 -2 -3', '4 5 6'] }, + { duration: 1000, fill: 'both', + composite: 'accumulate' }); + + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '0 -1 -2' }, + { time: 1000, expected: '5 6 7' }]); + }, `${property}`); + }, +}; + +const filterListType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: + ['blur(10px)', 'blur(50px)'] }, + 1000); + + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'blur(30px)' }]); + }, `${property}: blur function`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['hue-rotate(0deg)', + 'hue-rotate(100deg)'] }, + 1000); + + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'hue-rotate(50deg)' }]); + }, `${property}: hue-rotate function with same unit(deg)`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['hue-rotate(10deg)', + 'hue-rotate(100rad)'] }, + 1000); + + // 10deg = 0.1745rad. + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'hue-rotate(2869.79deg)' }]); + }, `${property}: hue-rotate function with different unit(deg -> rad)`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { [idlName]: + ['drop-shadow(10px 10px 10px rgba(255, 0, 0, 0.4))', + 'drop-shadow(50px 50px 50px rgba(0, 0, 255, 0.8))'] }, + 1000); + + testAnimationSamples( + animation, idlName, + [{ time: 500, + expected: 'drop-shadow(rgba(85, 0, 170, 0.6) 30px 30px 30px)' }]); + }, `${property}: drop-shadow function`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { [idlName]: + ['brightness(0.1) contrast(0.1) grayscale(0.1) invert(0.1) ' + + 'opacity(0.1) saturate(0.1) sepia(0.1)', + 'brightness(0.5) contrast(0.5) grayscale(0.5) invert(0.5) ' + + 'opacity(0.5) saturate(0.5) sepia(0.5)'] }, + 1000); + + testAnimationSamples(animation, idlName, + [{ time: 500, + expected: 'brightness(0.3) contrast(0.3) grayscale(0.3) ' + + 'invert(0.3) opacity(0.3) saturate(0.3) sepia(0.3)' }]); + }, `${property}: percentage or numeric-specifiable functions` + + ' (number value)'); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { [idlName]: + ['brightness(10%) contrast(10%) grayscale(10%) invert(10%) ' + + 'opacity(10%) saturate(10%) sepia(10%)', + 'brightness(50%) contrast(50%) grayscale(50%) invert(50%) ' + + 'opacity(50%) saturate(50%) sepia(50%)'] }, + 1000); + + testAnimationSamples(animation, idlName, + [{ time: 500, + expected: 'brightness(0.3) contrast(0.3) grayscale(0.3) ' + + 'invert(0.3) opacity(0.3) saturate(0.3) sepia(0.3)' }]); + }, `${property}: percentage or numeric-specifiable functions` + + ' (percentage value)'); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { [idlName]: + // To make missing filter-function-lists, specified the grayscale. + ['grayscale(0)', + 'grayscale(1) brightness(0) contrast(0) opacity(0) saturate(0)' ]}, + 1000); + + testAnimationSamples(animation, idlName, + [{ time: 500, + expected: 'grayscale(0.5) brightness(0.5) contrast(0.5) ' + + 'opacity(0.5) saturate(0.5)' }]); + }, `${property}: interpolate different length of filter-function-list` + + ' with function which lacuna value is 1'); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { [idlName]: + // To make missing filter-function-lists, specified the opacity. + ['opacity(1)', + 'opacity(0) grayscale(1) invert(1) sepia(1) blur(10px)'] }, + 1000); + + testAnimationSamples(animation, idlName, + [{ time: 500, + expected: + 'opacity(0.5) grayscale(0.5) invert(0.5) sepia(0.5) blur(5px)' }]); + }, `${property}: interpolate different length of filter-function-list` + + ' with function which lacuna value is 0'); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { [idlName]: + ['blur(0px)', + 'blur(10px) drop-shadow(10px 10px 10px rgba(0, 0, 255, 0.8))'] }, + 1000); + + testAnimationSamples(animation, idlName, + [{ time: 500, + // Per the spec: The initial value for interpolation is all length values + // set to 0 and the used color set to transparent. + expected: 'blur(5px) drop-shadow(rgba(0, 0, 255, 0.4) 5px 5px 5px)' }]); + }, `${property}: interpolate different length of filter-function-list` + + ' with drop-shadow function'); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['none', 'blur(10px)'] }, + 1000); + + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'blur(5px)' }]); + }, `${property}: interpolate from none`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate( + { [idlName]: + ['blur(0px) url(\"#f1\")', + 'blur(10px) url(\"#f2\")']}, + 1000); + testAnimationSamples(animation, idlName, + [{ time: 499, expected: 'blur(0px) url(\"#f1\")' }, + { time: 500, expected: 'blur(10px) url(\"#f2\")' }]); + }, `${property}: url function (interpoalte as discrete)`); + }, + + testAddition: function(property, setup) { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'blur(10px)'; + const animation = target.animate({ [idlName]: ['blur(20px)', + 'blur(50px)'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [ { time: 0, expected: 'blur(10px) blur(20px)' }]); + }, `${property}: blur on blur`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'blur(10px)'; + const animation = target.animate({ [idlName]: ['brightness(80%)', + 'brightness(40%)'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [ { time: 0, expected: 'blur(10px) brightness(0.8)' }]); + }, `${property}: different filter functions`); + }, + + testAccumulation: function(property, setup) { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'blur(10px) brightness(0.3)'; + const animation = target.animate( + { + [idlName]: [ + 'blur(20px) brightness(0.1)', + 'blur(20px) brightness(0.1)', + ], + }, + { duration: 1000, composite: 'accumulate' } + ); + // brightness(0.1) onto brightness(0.3) means + // brightness((0.1 - 1.0) + (0.3 - 1.0) + 1.0). The result of this formula + // is brightness(-0.6) that means brightness(0.0). + testAnimationSamples(animation, idlName, + [ { time: 0, expected: 'blur(30px) brightness(0)' }]); + }, `${property}: same ordered filter functions`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'blur(10px) brightness(1.3)'; + const animation = target.animate( + { + [idlName]: [ + 'brightness(1.2) blur(20px)', + 'brightness(1.2) blur(20px)', + ], + }, + { duration: 1000, composite: 'accumulate' } + ); + // Mismatched ordered functions can't be accumulated. + testAnimationSamples(animation, idlName, + [ { time: 0, expected: 'brightness(1.2) blur(20px)' }]); + }, `${property}: mismatched ordered filter functions`); + }, +}; + +const textShadowListType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ 'none', + 'rgb(100, 100, 100) 10px 10px 10px'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + // Premultiplied + [{ time: 500, expected: 'rgba(100, 100, 100, 0.5) 5px 5px 5px' }]); + }, `${property}: from none to other`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ 'rgb(100, 100, 100) 10px 10px 10px', + 'none' ] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + // Premultiplied + [{ time: 500, expected: 'rgba(100, 100, 100, 0.5) 5px 5px 5px' }]); + }, `${property}: from other to none`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ 'rgb(0, 0, 0) 0px 0px 0px', + 'rgb(100, 100, 100) 10px 10px 10px'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgb(50, 50, 50) 5px 5px 5px' }]); + }, `${property}: single shadow`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ 'rgb(0, 0, 0) 0px 0px 0px, ' + + 'rgb(200, 200, 200) 20px 20px 20px', + 'rgb(100, 100, 100) 10px 10px 10px, ' + + 'rgb(100, 100, 100) 10px 10px 10px'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgb(50, 50, 50) 5px 5px 5px, ' + + 'rgb(150, 150, 150) 15px 15px 15px' }]); + }, `${property}: shadow list`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ 'rgb(200, 200, 200) 20px 20px 20px', + 'rgb(100, 100, 100) 10px 10px 10px, ' + + 'rgb(100, 100, 100) 10px 10px 10px'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgb(150, 150, 150) 15px 15px 15px, ' + + 'rgba(100, 100, 100, 0.5) 5px 5px 5px' }]); + }, `${property}: mismatched list length (from longer to shorter)`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ 'rgb(100, 100, 100) 10px 10px 10px, ' + + 'rgb(100, 100, 100) 10px 10px 10px', + 'rgb(200, 200, 200) 20px 20px 20px'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgb(150, 150, 150) 15px 15px 15px, ' + + 'rgba(100, 100, 100, 0.5) 5px 5px 5px' }]); + }, `${property}: mismatched list length (from shorter to longer)`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style.color = 'rgb(0, 255, 0)'; + const animation = + target.animate({ [idlName]: [ 'currentcolor 0px 0px 0px', + 'currentcolor 10px 10px 10px'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgb(0, 255, 0) 5px 5px 5px' }]); + }, `${property}: with currentcolor`); + }, + + testAddition: function(property, setup) { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rgb(0, 0, 0) 0px 0px 0px'; + const animation = + target.animate({ [idlName]: [ 'rgb(120, 120, 120) 10px 10px 10px', + 'rgb(120, 120, 120) 10px 10px 10px'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [ { time: 0, expected: 'rgb(0, 0, 0) 0px 0px 0px, ' + + 'rgb(120, 120, 120) 10px 10px 10px' }]); + }, `${property}: shadow`); + }, + + testAccumulation: function(property, setup) { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rgb(120, 120, 120) 10px 10px 10px'; + const animation = + target.animate({ [idlName]: [ 'rgb(120, 120, 120) 10px 10px 10px', + 'rgb(120, 120, 120) 10px 10px 10px'] }, + { duration: 1000, composite: 'accumulate' }); + testAnimationSamples(animation, idlName, + [ { time: 0, expected: 'rgb(240, 240, 240) 20px 20px 20px' }]); + }, `${property}: shadow`); + }, +}; + + +const boxShadowListType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ 'none', + 'rgb(100, 100, 100) 10px 10px 10px 0px'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + // Premultiplied + [{ time: 500, expected: 'rgba(100, 100, 100, 0.5) 5px 5px 5px 0px' }]); + }, `${property}: from none to other`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ 'rgb(100, 100, 100) 10px 10px 10px 0px', + 'none' ] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + // Premultiplied + [{ time: 500, expected: 'rgba(100, 100, 100, 0.5) 5px 5px 5px 0px' }]); + }, `${property}: from other to none`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ 'rgb(0, 0, 0) 0px 0px 0px 0px', + 'rgb(100, 100, 100) 10px 10px 10px 0px'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgb(50, 50, 50) 5px 5px 5px 0px' }]); + }, `${property}: single shadow`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ 'rgb(0, 0, 0) 0px 0px 0px 0px, ' + + 'rgb(200, 200, 200) 20px 20px 20px 20px', + 'rgb(100, 100, 100) 10px 10px 10px 0px, ' + + 'rgb(100, 100, 100) 10px 10px 10px 0px'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgb(50, 50, 50) 5px 5px 5px 0px, ' + + 'rgb(150, 150, 150) 15px 15px 15px 10px' }]); + }, `${property}: shadow list`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ 'rgb(200, 200, 200) 20px 20px 20px 20px', + 'rgb(100, 100, 100) 10px 10px 10px 0px, ' + + 'rgb(100, 100, 100) 10px 10px 10px 0px'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgb(150, 150, 150) 15px 15px 15px 10px, ' + + 'rgba(100, 100, 100, 0.5) 5px 5px 5px 0px' }]); + }, `${property}: mismatched list length (from shorter to longer)`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: [ 'rgb(100, 100, 100) 10px 10px 10px 0px, ' + + 'rgb(100, 100, 100) 10px 10px 10px 0px', + 'rgb(200, 200, 200) 20px 20px 20px 20px']}, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgb(150, 150, 150) 15px 15px 15px 10px, ' + + 'rgba(100, 100, 100, 0.5) 5px 5px 5px 0px' }]); + }, `${property}: mismatched list length (from longer to shorter)`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style.color = 'rgb(0, 255, 0)'; + const animation = + target.animate({ [idlName]: [ 'currentcolor 0px 0px 0px 0px', + 'currentcolor 10px 10px 10px 10px'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgb(0, 255, 0) 5px 5px 5px 5px' }]); + }, `${property}: with currentcolor`); + }, + + testAddition: function(property, setup) { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rgb(0, 0, 0) 0px 0px 0px 0px'; + const animation = + target.animate({ [idlName]: [ 'rgb(120, 120, 120) 10px 10px 10px 0px', + 'rgb(120, 120, 120) 10px 10px 10px 0px'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [ { time: 0, expected: 'rgb(0, 0, 0) 0px 0px 0px 0px, ' + + 'rgb(120, 120, 120) 10px 10px 10px 0px' }]); + }, `${property}: shadow`); + }, + + testAccumulation: function(property, setup) { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rgb(120, 120, 120) 10px 10px 10px 10px'; + const animation = + target.animate({ [idlName]: [ 'rgb(120, 120, 120) 10px 10px 10px 10px', + 'rgb(120, 120, 120) 10px 10px 10px 10px'] }, + { duration: 1000, composite: 'accumulate' }); + testAnimationSamples(animation, idlName, + [ { time: 0, expected: 'rgb(240, 240, 240) 20px 20px 20px 20px' }]); + }, `${property}: shadow`); + }, +}; + +const positionType = { + testInterpolation: (property, setup) => { + lengthPairType.testInterpolation(property, setup); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: ['10% 10%', '50% 50%'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples( + animation, idlName, + [{ time: 500, expected: calcFromPercentage(idlName, '30% 30%') }]); + }, `${property} supports animating as a position of percent`); + }, + + testAdditionOrAccumulation: (property, setup, composite) => { + lengthPairType.testAddition(property, setup); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '60% 60%'; + const animation = target.animate({ [idlName]: ['70% 70%', '100% 100%'] }, + { duration: 1000, composite }); + testAnimationSamples( + animation, idlName, + [{ time: 0, expected: calcFromPercentage(idlName, '130% 130%') }]); + }, `${property}: position of percentage`); + }, + + testAddition: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'add'); + }, + + testAccumulation: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'accumulate'); + }, +}; + +const rectType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: + ['rect(10px, 10px, 10px, 10px)', + 'rect(50px, 50px, 50px, 50px)'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples( + animation, idlName, + [{ time: 500, expected: 'rect(30px, 30px, 30px, 30px)' }]); + }, `${property} supports animating as a rect`); + }, + + testAdditionOrAccumulation: (property, setup, composite) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = 'rect(100px, 100px, 100px, 100px)'; + const animation = target.animate({ [idlName]: + ['rect(10px, 10px, 10px, 10px)', + 'rect(10px, 10px, 10px, 10px)'] }, + { duration: 1000, composite }); + testAnimationSamples( + animation, idlName, + [{ time: 0, expected: 'rect(110px, 110px, 110px, 110px)' }]); + }, `${property}: rect`); + }, + + testAddition: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'add'); + }, + + testAccumulation: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'accumulate'); + }, +} + +// stroke-dasharray: none | [ | | ]* +const dasharrayType = { + testInterpolation: (property, setup) => { + percentageType.testInterpolation(property, setup); + positiveNumberType.testInterpolation(property, setup, 'px'); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: + ['8, 16, 4', + '4, 8, 12, 16'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples( + animation, idlName, + [{ time: 500, expected: '6px, 12px, 8px, 12px, 10px, 6px, 10px, 16px, 4px, 8px, 14px, 10px' }]); + }, `${property} supports animating as a dasharray (mismatched length)`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = target.animate({ [idlName]: + ['2, 50%, 6, 10', + '6, 30%, 2, 2'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples( + animation, idlName, + [{ time: 500, expected: '4px, 40%, 4px, 6px' }]); + }, `${property} supports animating as a dasharray (mixed lengths and percentages)`); + + }, + + // Note that stroke-dasharray is neither additive nor cumulative, so we should + // write this additive test case that animating value replaces underlying + // values. + // See https://www.w3.org/TR/SVG2/painting.html#StrokeDashing. + testAdditionOrAccumulation: (property, setup, composite) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '6, 30%, 2px'; + const animation = target.animate({ [idlName]: + ['1, 2, 3, 4, 5', + '6, 7, 8, 9, 10'] }, + { duration: 1000, composite }); + testAnimationSamples( + animation, idlName, + [{ time: 0, expected: '1px, 2px, 3px, 4px, 5px' }]); + }, `${property}: dasharray`); + }, + + testAddition: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'add'); + }, + + testAccumulation: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'accumulate'); + }, +} + +const fontVariationSettingsType = { + testInterpolation: (property, setup) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: ['"wght" 1.1', '"wght" 1.5'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '"wght" 1.1' }, + { time: 250, expected: '"wght" 1.2' }, + { time: 750, expected: '"wght" 1.4' } ]); + }, `${property} supports animation as float`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: ['"wdth" 1, "wght" 1.1', + '"wght" 1.5, "wdth" 5'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamplesWithAnyOrder( + animation, idlName, + [{ time: 0, expected: '"wdth" 1, "wght" 1.1' }, + { time: 250, expected: '"wdth" 2, "wght" 1.2' }, + { time: 750, expected: '"wdth" 4, "wght" 1.4' } ]); + }, `${property} supports animation as float with multiple tags`); + + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + const animation = + target.animate({ [idlName]: ['"wdth" 1, "wght" 1.1', + '"wght" 10, "wdth" 5, "wght" 1.5'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamplesWithAnyOrder( + animation, idlName, + [{ time: 250, expected: '"wdth" 2, "wght" 1.2' }, + { time: 750, expected: '"wdth" 4, "wght" 1.4' } ]); + }, `${property} supports animation as float with multiple duplicate tags`); + }, + + testAdditionOrAccumulation: (property, setup, composite) => { + test(t => { + const idlName = propertyToIDL(property); + const target = createTestElement(t, setup); + target.style[idlName] = '"wght" 1'; + const animation = + target.animate({ [idlName]: ['"wght" 1.1', '"wght" 1.5'] }, + { duration: 1000, composite }); + testAnimationSamples(animation, idlName, + [{ time: 250, expected: '"wght" 2.2' }, + { time: 750, expected: '"wght" 2.4' } ]); + }, `${property} with composite type ${composite}`); + }, + + testAddition: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'add'); + }, + + testAccumulation: function(property, setup) { + this.testAdditionOrAccumulation(property, setup, 'accumulate'); + }, +} + +const types = { + color: colorType, + discrete: discreteType, + filterList: filterListType, + integer: integerType, + positiveInteger: positiveIntegerType, + length: lengthType, + percentage: percentageType, + lengthPercentageOrCalc: lengthPercentageOrCalcType, + lengthPair: lengthPairType, + positiveNumber: positiveNumberType, + opacity: opacityType, + transformList: transformListType, + rotateList: rotateListType, + translateList: translateListType, + scaleList: scaleListType, + visibility: visibilityType, + boxShadowList: boxShadowListType, + textShadowList: textShadowListType, + rect: rectType, + position: positionType, + dasharray: dasharrayType, + fontVariationSettings: fontVariationSettingsType, +}; diff --git a/testing/web-platform/tests/web-animations/animation-model/animation-types/property-utils.js b/testing/web-platform/tests/web-animations/animation-model/animation-types/property-utils.js new file mode 100644 index 0000000000..d3a7b12a61 --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/animation-types/property-utils.js @@ -0,0 +1,38 @@ +'use strict'; + +function runAnimationTypeTest(gCSSProperties, testType) { + for (const property in gCSSProperties) { + if (!isSupported(property)) { + continue; + } + + const setupFunction = gCSSProperties[property].setup; + for (const animationType of gCSSProperties[property].types) { + let typeObject; + let animationTypeString; + if (typeof animationType === 'string') { + typeObject = types[animationType]; + animationTypeString = animationType; + } else if (typeof animationType === 'object' && + animationType.type && typeof animationType.type === 'string') { + typeObject = types[animationType.type]; + animationTypeString = animationType.type; + } + + // First, test that the animation type object has 'testAccumulation', or + // 'testAddition', or 'testInterpolation'. + // We use test() function here so that we can continue the remainder tests + // even if this test fails. + test(t => { + assert_own_property(typeObject, testType, animationTypeString + + ` should have ${testType} property`); + assert_equals(typeof typeObject[testType], 'function', + `${testType} method should be a function`); + }, `${property} (type: ${animationTypeString}) has ${testType} function`); + + if (typeObject[testType] && typeof typeObject[testType] === 'function') { + typeObject[testType](property, setupFunction, animationType.options); + } + } + } +} diff --git a/testing/web-platform/tests/web-animations/animation-model/animation-types/visibility.html b/testing/web-platform/tests/web-animations/animation-model/animation-types/visibility.html new file mode 100644 index 0000000000..f5a60b4e2c --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/animation-types/visibility.html @@ -0,0 +1,57 @@ + + +Animation type for the 'visibility' property + + + + + + +
+
+ + diff --git a/testing/web-platform/tests/web-animations/animation-model/combining-effects/applying-interpolated-transform.html b/testing/web-platform/tests/web-animations/animation-model/combining-effects/applying-interpolated-transform.html new file mode 100644 index 0000000000..c101b5f0cf --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/combining-effects/applying-interpolated-transform.html @@ -0,0 +1,87 @@ + + + apply interpolated transform on multiple keyframes + + + + + +
+
+ + diff --git a/testing/web-platform/tests/web-animations/animation-model/combining-effects/applying-the-composited-result.html b/testing/web-platform/tests/web-animations/animation-model/combining-effects/applying-the-composited-result.html new file mode 100644 index 0000000000..336115e577 --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/combining-effects/applying-the-composited-result.html @@ -0,0 +1,29 @@ + + +Applying the composited result + + + + +
+ diff --git a/testing/web-platform/tests/web-animations/animation-model/combining-effects/effect-composition.html b/testing/web-platform/tests/web-animations/animation-model/combining-effects/effect-composition.html new file mode 100644 index 0000000000..70a8cdd92c --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/combining-effects/effect-composition.html @@ -0,0 +1,154 @@ + + +Effect composition + + + + +
+ diff --git a/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/computed-keyframes-shorthands.html b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/computed-keyframes-shorthands.html new file mode 100644 index 0000000000..ff62a23bce --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/computed-keyframes-shorthands.html @@ -0,0 +1,30 @@ + + +Calculating computed keyframes: Shorthand properties + + + + + +
+
+ + diff --git a/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-in-removed-iframe-crash.html b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-in-removed-iframe-crash.html new file mode 100644 index 0000000000..209ede786f --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-in-removed-iframe-crash.html @@ -0,0 +1,22 @@ + + + + + + Querying keyframes for an effect in a removed iframe should not crash + + + + +
+ + + + diff --git a/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-on-marquee-parent-crash.html b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-on-marquee-parent-crash.html new file mode 100644 index 0000000000..2948d6b66e --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-on-marquee-parent-crash.html @@ -0,0 +1,21 @@ + +Animating marquee's parent inside display:none + + +
+ diff --git a/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-context-filling.html b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-context-filling.html new file mode 100644 index 0000000000..fcb7f13126 --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-context-filling.html @@ -0,0 +1,377 @@ + + +The effect value of a keyframe effect: Forwards-filling animations whose + values depend on their context (target element) + + + + + +
+ + diff --git a/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-context.html b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-context.html new file mode 100644 index 0000000000..3730a02098 --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-context.html @@ -0,0 +1,105 @@ + + +The effect value of a keyframe effect: Property values that depend on + their context (target element) + + + + + +
+ + diff --git a/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-interval-distance.html b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-interval-distance.html new file mode 100644 index 0000000000..6bf5d8cd46 --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-interval-distance.html @@ -0,0 +1,36 @@ + + +The effect value of a keyframe effect: Calculating the interval + distance between keyframes + + + + + +
+ + diff --git a/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-iteration-composite-operation.html b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-iteration-composite-operation.html new file mode 100644 index 0000000000..abfda86f4d --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-iteration-composite-operation.html @@ -0,0 +1,824 @@ + + +The effect value of a keyframe effect: Applying the iteration composite + operation + + + + + +
+ diff --git a/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-overlapping-keyframes.html b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-overlapping-keyframes.html new file mode 100644 index 0000000000..a2a0683921 --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-overlapping-keyframes.html @@ -0,0 +1,77 @@ + + +The effect value of a keyframe effect: Overlapping keyframes + + + + + +
+
+ + diff --git a/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-replaced-animations.html b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-replaced-animations.html new file mode 100644 index 0000000000..d40a01fdd2 --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-replaced-animations.html @@ -0,0 +1,161 @@ + + +The effect value of a keyframe effect: Overlapping keyframes + + + + + +
+ + diff --git a/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance.html b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance.html new file mode 100644 index 0000000000..a33d6d4f24 --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance.html @@ -0,0 +1,84 @@ + + +The effect value of a keyframe effect: Calculating the transformed + distance between keyframes + + + + + + +
+ + diff --git a/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/transform-and-opacity-on-inline-001-ref.html b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/transform-and-opacity-on-inline-001-ref.html new file mode 100644 index 0000000000..1e7f250c48 --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/transform-and-opacity-on-inline-001-ref.html @@ -0,0 +1,14 @@ + + +CSS Test (Animations): Element.animate() animating both transform and opacity on an inline + + + + + +x diff --git a/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/transform-and-opacity-on-inline-001.html b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/transform-and-opacity-on-inline-001.html new file mode 100644 index 0000000000..f76b53cd4c --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation-model/keyframe-effects/transform-and-opacity-on-inline-001.html @@ -0,0 +1,27 @@ + + +CSS Test (Animations): Element.animate() animating both transform and opacity on an inline + + + + + + + +x -- cgit v1.2.3