summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-view-transitions
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/css/css-view-transitions')
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/3d-transform-incoming-ref.html28
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/3d-transform-incoming.html63
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/3d-transform-outgoing-ref.html20
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/3d-transform-outgoing.html64
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/WEB_FEATURES.yml3
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/animating-new-content-ref.html28
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/animating-new-content-subset-ref.html28
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/animating-new-content-subset.html80
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/animating-new-content.html75
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/backdrop-filter-animated-ref.html22
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/backdrop-filter-animated.html54
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/backdrop-filter-captured-ref.html22
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/backdrop-filter-captured.html39
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/block-with-overflowing-text-ref.html21
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/block-with-overflowing-text.html60
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/break-inside-avoid-child-ref.html26
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/break-inside-avoid-child.html63
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/capture-with-offscreen-child-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/capture-with-offscreen-child-translated-ref.html29
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/capture-with-offscreen-child-translated.html51
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/capture-with-offscreen-child.html47
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/capture-with-opacity-zero-child.html45
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/capture-with-visibility-hidden-child-ref.html26
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/capture-with-visibility-hidden-child.html44
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/capture-with-visibility-mixed-descendants-ref.html37
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/capture-with-visibility-mixed-descendants.html56
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/class-specificity-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/class-specificity.html54
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-object-fit-fill-ref.html32
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-object-fit-none-ref.html22
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-smaller-than-box-size-ref.html23
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-smaller-than-box-size.html55
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-visibility-auto-shared-element-ref.html34
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-visibility-auto-shared-element.html81
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-with-child-with-transparent-background-ref.html64
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-with-child-with-transparent-background.html77
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-with-clip-ref.html31
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-with-clip-root-ref.html36
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-with-clip-root.html79
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-with-clip.html76
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-with-inline-child-ref.html32
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-with-inline-child.html71
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-with-object-view-box-ref.html16
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-with-overflow-ref.html28
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-with-overflow-zoomed-ref.html33
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-with-transform-new-image.html59
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-with-transform-old-image.html60
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-with-transform-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-with-transparent-background-ref.html44
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/content-with-transparent-background.html66
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/css-tags-paint-order-ref.html33
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/css-tags-paint-order-with-entry-ref.html40
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/css-tags-paint-order-with-entry.html111
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/css-tags-paint-order.html92
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/css-tags-shared-element-ref.html28
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/css-tags-shared-element.html79
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/dialog-in-rtl-iframe-ref.html19
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/dialog-in-rtl-iframe.html36
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/dialog-in-top-layer-during-transition-new.html70
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/dialog-in-top-layer-during-transition-old.html71
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/dialog-in-top-layer-during-transition-ref.html28
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/document-element-detached-crash.html25
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/duplicate-tag-rejects-capture.html48
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/duplicate-tag-rejects-start.html50
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/element-is-grouping-during-animation-ref.html23
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/element-is-grouping-during-animation.html74
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/element-stops-grouping-after-animation-ref.html32
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/element-stops-grouping-after-animation.html74
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/element-with-overflow-ref.html41
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/element-with-overflow.html70
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/event-pseudo-name.html70
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/exit-transition-with-anonymous-layout-object-ref.html20
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/exit-transition-with-anonymous-layout-object.html64
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/far-away-capture-ref.html31
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/far-away-capture.html84
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fractional-box-new.html35
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fractional-box-old.html35
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fractional-box-ref.html19
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fractional-box-with-overflow-children-new.html52
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fractional-box-with-overflow-children-old.html52
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fractional-box-with-overflow-children-ref.html33
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fractional-box-with-shadow-new.html36
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fractional-box-with-shadow-old.html36
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fractional-box-with-shadow-ref.html20
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fractional-translation-from-position-ref.html28
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fractional-translation-from-position.html55
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fractional-translation-from-transform-ref.html29
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fractional-translation-from-transform.html57
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fragmented-at-start-ignored-ref.html34
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fragmented-at-start-ignored.html58
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fragmented-during-transition-skips-ref.html32
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/fragmented-during-transition-skips.html64
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/get-computed-style-crash.html16
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/group-animation-for-root-transition.html47
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/hit-test-unpainted-element-from-point.html79
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/hit-test-unpainted-element-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/hit-test-unpainted-element.html69
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/hit-test-unrelated-element-ref.html27
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/hit-test-unrelated-element.html80
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/iframe-new-has-scrollbar-ref.html19
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/iframe-new-has-scrollbar.html39
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/iframe-old-has-scrollbar-ref.html19
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/iframe-old-has-scrollbar.html38
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/iframe-transition-destroyed-document-crash.html27
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/iframe-transition-ref.html22
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/iframe-transition.sub.html21
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/inline-child-with-filter-ref.html29
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/inline-child-with-filter.html54
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/inline-element-size-ref.html19
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/inline-element-size.html35
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/inline-with-offset-from-containing-block-ref.html27
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/inline-with-offset-from-containing-block.html49
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/input-targets-root-while-render-blocked.html105
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/intrinsic-aspect-ratio-ref.html31
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/japanese-tag-ref.html25
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/japanese-tag.html95
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/list-style-position-style-change-crash.html20
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-below-and-on-top-of-viewport-partially-onscreen-new.html76
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-below-and-on-top-of-viewport-partially-onscreen-old.html76
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-below-and-on-top-of-viewport-partially-onscreen-ref.html38
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-offscreen-new.html91
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-offscreen-old.html91
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-offscreen-ref.html46
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-partially-onscreen-new.html74
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-partially-onscreen-old.html74
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-partially-onscreen-ref.html46
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-offscreen-new.html96
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-offscreen-old.html96
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-offscreen-ref.html47
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-partially-onscreen-new.html80
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-partially-onscreen-old.html80
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-partially-onscreen-ref.html53
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-offscreen-new.html92
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-offscreen-old.html92
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-offscreen-ref.html43
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-partially-onscreen-new.html76
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-partially-onscreen-old.html76
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-partially-onscreen-ref.html49
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-right-and-left-of-viewport-partially-onscreen-new.html80
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-right-and-left-of-viewport-partially-onscreen-old.html80
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-right-and-left-of-viewport-partially-onscreen-ref.html42
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-offscreen-new.html95
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-offscreen-old.html95
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-offscreen-ref.html50
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-partially-onscreen-new.html78
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-partially-onscreen-old.html78
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-partially-onscreen-ref.html50
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/mix-blend-mode-only-on-transition.html67
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/modify-style-via-cssom-ref.html16
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/modify-style-via-cssom.html53
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/multiline-span-with-overflowing-text-and-box-decorations-ref.html28
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/multiline-span-with-overflowing-text-and-box-decorations.html67
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/named-element-with-fix-pos-child-new.html45
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/named-element-with-fix-pos-child-old.html45
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/named-element-with-fix-pos-child-ref.html25
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-and-old-sizes-match-ref.html48
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-and-old-sizes-match.html50
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-captures-clip-path-ref.html23
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-captures-clip-path.html48
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-captures-different-size-ref.html36
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-captures-different-size.html64
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-captures-opacity-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-captures-opacity.html47
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-captures-positioned-spans-ref.html15
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-captures-positioned-spans.html37
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-captures-root-ref.html20
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-captures-root.html53
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-captures-spans-ref.html13
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-captures-spans.html34
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-changes-overflow-ref.html27
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-changes-overflow.html53
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-container-writing-modes-ref.html23
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-container-writing-modes.html89
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-element-writing-modes-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-element-writing-modes.html91
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-from-root-display-none-ref.html22
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-from-root-display-none.html49
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-has-scrollbars-ref.html27
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-has-scrollbars.html62
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-intrinsic-aspect-ratio.html67
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-is-empty-div-ref.html19
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-is-empty-div.html61
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-is-inline-ref.html79
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-is-inline.html148
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-object-fit-fill.html76
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-object-fit-none.html69
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-clip-path-ref.html46
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-clip-path-reference-ref.html57
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-clip-path-reference.html93
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-clip-path.html82
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-overflow-clipped-ref.html38
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-overflow-clipped.html67
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-overflow-ref.html38
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-overflow.html67
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-scaling-ref.html21
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-scaling.html63
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-with-object-view-box.html42
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-with-overflow-zoomed.html56
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-content-with-overflow.html51
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-element-on-start-ref.html19
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-element-on-start.html64
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-root-vertical-writing-mode-ref.html22
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/new-root-vertical-writing-mode.html73
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/no-crash-set-exception.html41
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/no-crash-view-transition-in-massive-iframe.html22
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/no-css-animation-while-render-blocked.html59
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/no-raf-while-render-blocked.html48
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/no-root-capture-ref.html28
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/no-root-capture.html54
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/nothing-captured-ref.html28
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/nothing-captured.html47
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/object-view-box-new-image.html70
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/object-view-box-old-image.html72
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/object-view-box-ref.html25
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/offscreen-element-modified-before-coming-onscreen-ref.html20
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/offscreen-element-modified-before-coming-onscreen.html73
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-captures-clip-path-ref.html22
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-captures-clip-path.html47
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-captures-different-size-ref.html35
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-captures-different-size.html64
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-captures-opacity-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-captures-opacity.html48
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-captures-root-ref.html19
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-captures-root.html51
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-container-writing-modes-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-container-writing-modes.html94
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-element-writing-modes-ref.html25
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-element-writing-modes.html95
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-has-scrollbars-ref.html30
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-has-scrollbars.html60
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-intrinsic-aspect-ratio.html67
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-is-empty-div-ref.html19
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-is-empty-div.html60
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-is-inline-ref.html77
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-is-inline.html148
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-object-fit-fill.html76
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-object-fit-none.html69
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-clip-path-ref.html46
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-clip-path-reference-ref.html57
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-clip-path-reference.html94
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-clip-path.html83
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-overflow-ref.html38
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-overflow.html66
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-with-object-view-box.html42
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-with-overflow-zoomed.html56
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-content-with-overflow.html51
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-root-vertical-writing-mode-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/old-root-vertical-writing-mode.html76
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/only-child-group.html117
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/only-child-image-pair.html50
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/only-child-new.html171
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/only-child-no-transition.html39
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/only-child-old.html171
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/only-child-on-root-element-with-view-transition.html47
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/only-child-view-transition.html34
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/parsing/pseudo-elements-invalid-with-classes.html32
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/parsing/pseudo-elements-invalid.html69
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/parsing/pseudo-elements-valid-with-classes.html33
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/parsing/pseudo-elements-valid.html32
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-class-computed.html29
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-class-invalid.html24
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-class-valid.html23
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-name-computed.html27
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-name-invalid.html29
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-name-valid.html21
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/paused-animation-at-end.html44
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-computed-style-stays-in-sync-with-new-element.html42
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-get-computed-style.html112
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-rendering-invalidation-ref.html31
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-rendering-invalidation.html126
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-entry.html54
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-exit.html54
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-match-ident.html41
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-match-multiple-wildcard.html41
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-match-multiple.html41
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-match-wildard.html41
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-mismatch-ident.html46
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-mismatch-partial.html45
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-mismatch-wildcard.html46
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-multiple-vt-classes.html41
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-new-with-class-old-without.html46
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-old-with-class-new-without.html51
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-ref.html15
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-view-transition-group.html37
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-view-transition-image-pair.html37
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/ready_resolves_after_dom_before_raf.html51
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/root-captured-as-different-tag-ref.html19
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/root-captured-as-different-tag.html56
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/root-element-cv-hidden-crash.html11
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/root-element-display-none-crash.html23
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/root-element-display-none-during-transition-crash.html30
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/root-scrollbar-with-fixed-background-ref.html33
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/root-scrollbar-with-fixed-background.html67
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/root-style-change-during-animation-ref.html20
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/root-style-change-during-animation.html65
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-end-ref.html26
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-end.html53
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-incoming-ref.html13
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-incoming.html44
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-start-ref.html21
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-start.html44
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/rotated-cat-off-top-edge-ref.html16
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/rotated-cat-off-top-edge.html32
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/rtl-with-scrollbar-ref.html40
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/rtl-with-scrollbar.html72
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/scroller-child-abspos-ref.html39
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/scroller-child-abspos.html62
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/scroller-child-ref.html37
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/scroller-child.html60
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/scroller-ref.html30
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/scroller.html53
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/set-current-time-ref.html14
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/set-current-time-transform-ref.html39
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/set-current-time-transform.html62
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/set-current-time.html49
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/set-universal-specificity-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/set-universal-specificity.html45
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/shared-transition-author-style.manual.html94
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/shared-transition-half.manual.html60
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/shared-transition-shapes.manual.html80
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-absolute-ref.html51
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-absolute.html72
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-includes-scrollbar-gutter-ref.html34
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-includes-scrollbar-gutter.html48
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-static-ref.html37
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-static.html66
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-and-box-decorations-ref.html20
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-and-box-decorations.html59
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-hidden-ref.html23
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-hidden.html61
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text.html57
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/style-inheritance.html56
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/support/cat.pngbin0 -> 1883 bytes
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/support/dialog-in-rtl-iframe-child.html49
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/support/frame-helper.html25
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/support/iframe-scrollbar-child.html44
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/support/transition-in-empty-iframe-child.html45
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/synchronous-callback-skipped-before-run.html37
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/transform-origin-view-transition-group-ref.html20
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/transform-origin-view-transition-group.html58
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/transition-in-empty-iframe-ref.html28
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/transition-in-empty-iframe.html47
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/transition-skipped-after-animation-started.html37
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/transition-skipped-from-invalid-callback.html46
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/unset-and-initial-view-transition-name.html50
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/view-transition-name-is-backdrop-filter-root-ref.html37
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/view-transition-name-is-backdrop-filter-root.html37
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/view-transition-name-is-grouping-ref.html22
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/view-transition-name-is-grouping.html35
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/view-transition-name-on-document-root-ref.html51
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/view-transition-name-on-document-root.html44
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/view-transition-name-on-removed-element.html36
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/view-transition-name-removed-mid-transition-ref.html32
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/view-transition-name-removed-mid-transition.html50
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/web-animation-pseudo-incorrect-name.html39
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/web-animations-api-ref.html26
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/web-animations-api.html58
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/window-resize-aborts-transition-before-ready.html60
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/window-resize-aborts-transition.html76
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/writing-mode-container-resize-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-view-transitions/writing-mode-container-resize.html52
362 files changed, 17600 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-view-transitions/3d-transform-incoming-ref.html b/testing/web-platform/tests/css/css-view-transitions/3d-transform-incoming-ref.html
new file mode 100644
index 0000000000..c690ee2b9a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/3d-transform-incoming-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>View transitions: 3d transform ref</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+div { box-sizing: border-box; will-change: transform }
+.wrap_perspective {
+ perspective: 100px;
+ width: max-content;
+ transform: translate(200px);
+}
+.rotatex {
+ transform-style: preserve-3d;
+ transform: rotateX(20deg);
+ background: blue;
+}
+.shared {
+ width: 100px;
+ height: 100px;
+ view-transition-name: shared;
+}
+body { background: pink }
+
+</style>
+
+<div class="wrap_perspective"><div class="rotatex shared"></div></div>
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/3d-transform-incoming.html b/testing/web-platform/tests/css/css-view-transitions/3d-transform-incoming.html
new file mode 100644
index 0000000000..24ab886025
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/3d-transform-incoming.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: 3d transform</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="3d-transform-incoming-ref.html">
+<meta name=fuzzy content="3d-transform-incoming-ref.html:0-255;0-515">
+<script src="/common/reftest-wait.js"></script>
+<style>
+div { box-sizing: border-box; will-change: transform }
+.rotate3d {
+ transform: translate(20px, 100px) rotate3d(1, 1, 1, 45deg);
+ background: blue;
+}
+
+.wrap_perspective {
+ perspective: 100px;
+ width: max-content;
+ transform: translate(200px);
+}
+.rotatex {
+ transform-style: preserve-3d;
+ transform: rotateX(20deg);
+ background: green;
+}
+.shared {
+ view-transition-name: shared;
+ width: 100px;
+ height: 100px;
+}
+#hidden {
+ view-transition-name: hidden;
+ width: 10px;
+ height: 10px;
+ background: red;
+}
+
+::view-transition-group(hidden) { animation-duration: 300s; }
+::view-transition-image-pair(hidden) { visibility: hidden; }
+::view-transition-group(root) { visibility: hidden; }
+::view-transition { background: pink; }
+::view-transition-group(*) { animation-delay: 300s; }
+::view-transition-new(*) { animation: unset; opacity: 1; }
+::view-transition-old(*) { animation: unset; opacity: 0; }
+</style>
+
+<div id=wrapper class=wrap_perspective><div id=target class="shared rotatex"></div></div>
+<div id=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ document.startViewTransition(() => {
+ wrapper.classList.toggle("wrap_perspective");
+ target.classList.toggle("rotatex");
+ target.classList.toggle("rotate3d");
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/3d-transform-outgoing-ref.html b/testing/web-platform/tests/css/css-view-transitions/3d-transform-outgoing-ref.html
new file mode 100644
index 0000000000..393943e396
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/3d-transform-outgoing-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title>View transitions: 3d transform ref</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+div { box-sizing: border-box; will-change: transform }
+.rotate3d {
+ transform: translate(20px, 100px) rotate3d(1, 1, 1, 45deg);
+ background: green;
+}
+.shared {
+ width: 100px;
+ height: 100px;
+}
+body { background: pink }
+
+</style>
+
+<div class="rotate3d shared"></div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/3d-transform-outgoing.html b/testing/web-platform/tests/css/css-view-transitions/3d-transform-outgoing.html
new file mode 100644
index 0000000000..746b93afd4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/3d-transform-outgoing.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: 3d transform</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="3d-transform-outgoing-ref.html">
+<meta name=fuzzy content="3d-transform-outgoing-ref.html:0-255;0-1200">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div { box-sizing: border-box; will-change: transform }
+.rotate3d {
+ transform: translate(20px, 100px) rotate3d(1, 1, 1, 45deg);
+ background: blue;
+}
+
+.wrap_perspective {
+ perspective: 100px;
+ width: max-content;
+ transform: translate(200px);
+}
+.rotatex {
+ transform-style: preserve-3d;
+ transform: rotateX(20deg);
+ background: green;
+}
+.shared {
+ view-transition-name: shared;
+ width: 100px;
+ height: 100px;
+}
+#hidden {
+ view-transition-name: hidden;
+ width: 10px;
+ height: 10px;
+ background: red;
+}
+
+::view-transition-group(hidden) { animation-duration: 300s; }
+::view-transition-image-pair(hidden) { visibility: hidden; }
+::view-transition-group(root) { visibility: hidden; }
+::view-transition { background: pink; }
+::view-transition-group(*) { animation-duration: 0s; }
+::view-transition-new(*) { animation: unset; opacity: 0; }
+::view-transition-old(*) { animation: unset; opacity: 1; }
+</style>
+
+<div id=wrapper class=wrap_perspective><div id=target class="shared rotatex"></div></div>
+<div id=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ document.startViewTransition(() => {
+ wrapper.classList.toggle("wrap_perspective");
+ target.classList.toggle("rotatex");
+ target.classList.toggle("rotate3d");
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/WEB_FEATURES.yml b/testing/web-platform/tests/css/css-view-transitions/WEB_FEATURES.yml
new file mode 100644
index 0000000000..e1df1b8c67
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: view-transitions
+ files: "**"
diff --git a/testing/web-platform/tests/css/css-view-transitions/animating-new-content-ref.html b/testing/web-platform/tests/css/css-view-transitions/animating-new-content-ref.html
new file mode 100644
index 0000000000..eae9e2c471
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/animating-new-content-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: animations in the new element show up in the images (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<style>
+#target {
+ width:100px;
+ height:100px;
+ background: grey;
+ will-change: transform;
+}
+
+.child {
+ width: 50px;
+ height: 50px;
+ will-change: transform;
+ background: green;
+}
+</style>
+
+<div id="target">
+ <div class="child">
+ I'm the inner composited child.
+ </div>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/animating-new-content-subset-ref.html b/testing/web-platform/tests/css/css-view-transitions/animating-new-content-subset-ref.html
new file mode 100644
index 0000000000..eee7f19529
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/animating-new-content-subset-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: animations in the new element show up in the images if it partially changes (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<style>
+#target {
+ width:100px;
+ height:100px;
+ background: blue;
+ will-change: transform;
+}
+
+.child {
+ width: 50px;
+ height: 50px;
+ will-change: transform;
+ background: grey;
+}
+</style>
+
+<div id="target">
+ <div class="child">
+ I'm the inner composited child.
+ </div>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/animating-new-content-subset.html b/testing/web-platform/tests/css/css-view-transitions/animating-new-content-subset.html
new file mode 100644
index 0000000000..d5a342c572
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/animating-new-content-subset.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: animations in the new element show up in the images if it partially changes</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="animating-new-content-subset-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+<style>
+#target {
+ width:100px;
+ height:100px;
+ background: blue;
+ view-transition-name: target;
+ will-change: transform;
+}
+
+.child {
+ width: 50px;
+ height: 50px;
+ will-change: transform;
+ background: green;
+}
+
+.hidden {
+ width: 10px;
+ height: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; visibility: hidden;}
+
+html::view-transition-group(target) {
+ animation: unset;
+}
+
+html::view-transition-image-pair(target) {
+ isolation: unset;
+}
+html::view-transition-old(target), html::view-transition-new(target) {
+ animation: unset;
+ mix-blend-mode: normal;
+}
+
+html::view-transition-old(target) {
+ opacity: 0;
+}
+
+html::view-transition-new(target) {
+ opacity: 1;
+}
+</style>
+
+<div id="target">
+ <div class="child" id="child">
+ I'm the inner composited child.
+ </div>
+</div>
+<div class="hidden"></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition();
+ transition.ready.then(async () => {
+ await waitForAtLeastOneFrame();
+ await waitForAtLeastOneFrame();
+ child.style.background = "grey";
+
+ await waitForAtLeastOneFrame();
+ await waitForAtLeastOneFrame();
+ takeScreenshot();
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/animating-new-content.html b/testing/web-platform/tests/css/css-view-transitions/animating-new-content.html
new file mode 100644
index 0000000000..9bfcb51a91
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/animating-new-content.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: animations in the new element show up in the images</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="animating-new-content-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+<style>
+#target {
+ width:100px;
+ height:100px;
+ background: blue;
+ view-transition-name: target;
+ will-change: transform;
+}
+
+.child {
+ width: 50px;
+ height: 50px;
+ will-change: transform;
+ background: green;
+}
+
+.hidden {
+ width: 10px;
+ height: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(target) {
+ animation: unset;
+}
+
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 0;
+}
+
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+}
+</style>
+
+<div id="target">
+ <div class="child">
+ I'm the inner composited child.
+ </div>
+</div>
+<div class="hidden"></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition();
+ transition.ready.then(async () => {
+ await waitForAtLeastOneFrame();
+ await waitForAtLeastOneFrame();
+ target.style.background = "grey";
+
+ await waitForAtLeastOneFrame();
+ await waitForAtLeastOneFrame();
+ takeScreenshot();
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/backdrop-filter-animated-ref.html b/testing/web-platform/tests/css/css-view-transitions/backdrop-filter-animated-ref.html
new file mode 100644
index 0000000000..d3f1dffacd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/backdrop-filter-animated-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>View transitions: capture with backdrop filter on the element (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.box {
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+#target {
+ width: 50px;
+ height: 50px;
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ backdrop-filter: grayscale(0.5);
+}
+</style>
+
+<div class=box></div>
+<div id=target></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/backdrop-filter-animated.html b/testing/web-platform/tests/css/css-view-transitions/backdrop-filter-animated.html
new file mode 100644
index 0000000000..3a5f0665b0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/backdrop-filter-animated.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>View transitions: captured backdrop filter on the element animates</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="backdrop-filter-animated-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+#target {
+ view-transition-name: target;
+ width: 50px;
+ height: 50px;
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ backdrop-filter: grayscale(1);
+}
+#target.after {
+ backdrop-filter: grayscale(0);
+}
+
+html::view-transition-group(*) {
+ animation-duration: 1s;
+ animation-timing-function: linear;
+ animation-play-state: paused;
+}
+html::view-transition-new(*) { animation: unset; opacity: 1; }
+html::view-transition-old(*) { animation: unset; opacity: 0; }
+</style>
+<div class=box></div>
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition(() => target.classList.add("after"));
+ transition.ready.then(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() => {
+ document.getAnimations().forEach((animation) => {
+ animation.currentTime = 500;
+ });
+ requestAnimationFrame(takeScreenshot);
+ }));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/backdrop-filter-captured-ref.html b/testing/web-platform/tests/css/css-view-transitions/backdrop-filter-captured-ref.html
new file mode 100644
index 0000000000..4defa6b90d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/backdrop-filter-captured-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>View transitions: capture with backdrop filter on the element (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.box {
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+#target {
+ width: 50px;
+ height: 50px;
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ backdrop-filter: grayscale(1);
+}
+</style>
+
+<div class=box></div>
+<div id=target></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/backdrop-filter-captured.html b/testing/web-platform/tests/css/css-view-transitions/backdrop-filter-captured.html
new file mode 100644
index 0000000000..d42a197a30
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/backdrop-filter-captured.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>View transitions: capture with backdrop filter on the element</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="backdrop-filter-captured-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+#target {
+ view-transition-name: target;
+ width: 50px;
+ height: 50px;
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ backdrop-filter: grayscale(1);
+}
+
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 1; }
+html::view-transition-old(*) { animation: unset; opacity: 0; }
+</style>
+<div class=box></div>
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition().ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/block-with-overflowing-text-ref.html b/testing/web-platform/tests/css/css-view-transitions/block-with-overflowing-text-ref.html
new file mode 100644
index 0000000000..8d9c430fcc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/block-with-overflowing-text-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: block with overflowing text is rendered correctly (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<style>
+#target {
+ text-shadow: red -20px -50px;
+ position: relative;
+ top: 100px;
+ left: 100px;
+}
+
+body {
+ background: pink;
+}
+</style>
+
+<div id="target">This text should render correctly</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/block-with-overflowing-text.html b/testing/web-platform/tests/css/css-view-transitions/block-with-overflowing-text.html
new file mode 100644
index 0000000000..b3f8f42cfd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/block-with-overflowing-text.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: block with overflowing text is rendered correctly</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="block-with-overflowing-text-ref.html">
+<meta name="fuzzy" content="block-with-overflowing-text-ref.html:maxDifference=0-2;totalPixels=0-1200">
+
+
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+<style>
+#target {
+ text-shadow: red -20px -50px;
+ position: relative;
+ top: 100px;
+ left: 100px;
+ view-transition-name: target;
+}
+
+.hidden {
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+html::view-transition-group(root) { visibility: hidden; }
+
+html::view-transition-group(target) {
+ animation: unset;
+}
+
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 0;
+}
+
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+}
+
+html::view-transition {
+ background: pink;
+}
+</style>
+
+<div id="target">This text should render correctly</div>
+<div class="hidden"></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition();
+ transition.ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/break-inside-avoid-child-ref.html b/testing/web-platform/tests/css/css-view-transitions/break-inside-avoid-child-ref.html
new file mode 100644
index 0000000000..859abdfb5f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/break-inside-avoid-child-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>View transitions: break-inside: avoid child (ref)</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+.columns {
+ columns: 2;
+ contain: layout;
+ border: 1px solid black;
+}
+
+.inner {
+ break-inside: avoid;
+ position: relative;
+ top: 300px;
+ left: 0;
+ background: lightblue;
+ width: 300px;
+ height: 300px;
+}
+</style>
+
+<div class="columns">
+ <div class="inner"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/break-inside-avoid-child.html b/testing/web-platform/tests/css/css-view-transitions/break-inside-avoid-child.html
new file mode 100644
index 0000000000..7b2a83c776
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/break-inside-avoid-child.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: break-inside: avoid child</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="break-inside-avoid-child-ref.html">
+<meta name="fuzzy" content="break-inside-avoid-child-ref.html:0-5;0-1600">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.old {
+ position: relative;
+ top: 300px;
+ left: 0;
+ background: lightblue;
+}
+.new {
+ position: relative;
+ top: 0;
+ left: 0;
+ background: green;
+}
+.columns {
+ columns: 2;
+ contain: layout;
+ border: 1px solid black;
+ view-transition-name: target;
+}
+
+.inner {
+ break-inside: avoid;
+ width: 300px;
+ height: 300px;
+}
+
+html::view-transition-group(root) { animation-duration: 300s; }
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 1;
+}
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 0;
+}
+</style>
+
+<div class="columns">
+ <div id="inner" class="inner old"></div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ let transition = document.startViewTransition(() => {
+ inner.classList.replace("old", "new");
+ });
+ transition.ready.then(() => requestAnimationFrame(takeScreenshot));
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/capture-with-offscreen-child-ref.html b/testing/web-platform/tests/css/css-view-transitions/capture-with-offscreen-child-ref.html
new file mode 100644
index 0000000000..b8ebf1d0e2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/capture-with-offscreen-child-ref.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<html>
+<title>View transitions: offscreen child (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+body {
+ background: pink;
+}
+.target {
+ width: 100px;
+ height: 100px;
+ background: blue;
+}
+</style>
+
+<div class=target></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/capture-with-offscreen-child-translated-ref.html b/testing/web-platform/tests/css/css-view-transitions/capture-with-offscreen-child-translated-ref.html
new file mode 100644
index 0000000000..d724d0b7f9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/capture-with-offscreen-child-translated-ref.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<html>
+<title>View transitions: offscreen child (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+body {
+ background: pink;
+}
+
+.invisible {
+ position: absolute;
+ top: 100px;
+ width: 50px;
+ height: 50px;
+ background: green;
+}
+.target {
+ position: relative;
+ top: 200px;
+ width: 100px;
+ height: 100px;
+ background: blue;
+}
+</style>
+
+<div class=target></div>
+<div class=invisible></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/capture-with-offscreen-child-translated.html b/testing/web-platform/tests/css/css-view-transitions/capture-with-offscreen-child-translated.html
new file mode 100644
index 0000000000..925bb8dbc4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/capture-with-offscreen-child-translated.html
@@ -0,0 +1,51 @@
+<!doctype html>
+<html class=reftest-wait>
+<title>View transitions: offscreen child</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="capture-with-offscreen-child-translated-ref.html">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.target {
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+ background: blue;
+}
+.invisible {
+ position: absolute;
+ top: -100px;
+ width: 50px;
+ height: 50px;
+ background: green;
+}
+
+::view-transition-group(target) {
+ animation: unset;
+ top: 200px;
+}
+
+::view-transition-group(root) {
+ visibility: hidden;
+ animation-duration: 500s;
+}
+::view-transition {
+ background: pink;
+}
+</style>
+
+<div class=target>
+ <div class=invisible></div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ const transition = document.startViewTransition();
+ transition.ready.then(takeScreenshot);
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/capture-with-offscreen-child.html b/testing/web-platform/tests/css/css-view-transitions/capture-with-offscreen-child.html
new file mode 100644
index 0000000000..8588968d8a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/capture-with-offscreen-child.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<html class=reftest-wait>
+<title>View transitions: offscreen child</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="capture-with-offscreen-child-ref.html">
+<meta name="fuzzy" content="capture-with-offscreen-child-ref.html:0-5;0-200">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.target {
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+ background: blue;
+}
+.invisible {
+ position: absolute;
+ top: -100px;
+ width: 50px;
+ height: 50px;
+ background: green;
+}
+
+::view-transition-group(root) {
+ visibility: hidden;
+ animation-duration: 500s;
+}
+::view-transition {
+ background: pink;
+}
+</style>
+
+<div class=target>
+ <div class=invisible></div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ const transition = document.startViewTransition();
+ transition.ready.then(takeScreenshot);
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/capture-with-opacity-zero-child.html b/testing/web-platform/tests/css/css-view-transitions/capture-with-opacity-zero-child.html
new file mode 100644
index 0000000000..888d0d1720
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/capture-with-opacity-zero-child.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<html class=reftest-wait>
+<title>View transitions: visibility hidden child</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="capture-with-visibility-hidden-child-ref.html">
+<meta name="fuzzy" content="capture-with-visibility-hidden-child-ref.html:0-5;0-300">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.target {
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+ background: blue;
+}
+.invisible {
+ width: 500px;
+ height: 500px;
+ opacity: 0;
+}
+
+::view-transition-group(root) {
+ visibility: hidden;
+ animation-duration: 500s;
+}
+::view-transition {
+ background: pink;
+}
+</style>
+
+<div class=target>
+ <div class=invisible></div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ const transition = document.startViewTransition();
+ transition.ready.then(takeScreenshot);
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/capture-with-visibility-hidden-child-ref.html b/testing/web-platform/tests/css/css-view-transitions/capture-with-visibility-hidden-child-ref.html
new file mode 100644
index 0000000000..10067cc521
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/capture-with-visibility-hidden-child-ref.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html>
+<title>View transitions: visibility hidden child (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+body {
+ background: pink;
+}
+.target {
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+ background: blue;
+}
+.invisible {
+ width: 500px;
+ height: 500px;
+ visibility: hidden;
+}
+</style>
+
+<div class=target>
+ <div class=invisible></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/capture-with-visibility-hidden-child.html b/testing/web-platform/tests/css/css-view-transitions/capture-with-visibility-hidden-child.html
new file mode 100644
index 0000000000..2d17612499
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/capture-with-visibility-hidden-child.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<html class=reftest-wait>
+<title>View transitions: visibility hidden child</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="capture-with-visibility-hidden-child-ref.html">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.target {
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+ background: blue;
+}
+.invisible {
+ width: 500px;
+ height: 500px;
+ visibility: hidden;
+}
+
+::view-transition-group(root) {
+ visibility: hidden;
+ animation-duration: 500s;
+}
+::view-transition {
+ background: pink;
+}
+</style>
+
+<div class=target>
+ <div class=invisible></div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ const transition = document.startViewTransition();
+ transition.ready.then(takeScreenshot);
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/capture-with-visibility-mixed-descendants-ref.html b/testing/web-platform/tests/css/css-view-transitions/capture-with-visibility-mixed-descendants-ref.html
new file mode 100644
index 0000000000..c47b31e4d5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/capture-with-visibility-mixed-descendants-ref.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<html>
+<title>View transitions: visibility hidden/visible descendants (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+body {
+ background: pink;
+}
+.target {
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+ background: blue;
+}
+.invisible {
+ top: 200px;
+ left: 200px;
+ width: 500px;
+ height: 500px;
+ position: relative;
+ background: red;
+ visibility: hidden;
+}
+.visible {
+ background: green;
+ width: 10px;
+ height: 10px;
+ visibility: visible;
+}
+
+</style>
+
+<div class=target>
+ <div class=invisible><div class=visible></div></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/capture-with-visibility-mixed-descendants.html b/testing/web-platform/tests/css/css-view-transitions/capture-with-visibility-mixed-descendants.html
new file mode 100644
index 0000000000..462d267b94
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/capture-with-visibility-mixed-descendants.html
@@ -0,0 +1,56 @@
+<!doctype html>
+<html class=reftest-wait>
+<title>View transitions: visibility hidden/visible descendants</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="capture-with-visibility-mixed-descendants-ref.html">
+<meta name=fuzzy content="capture-with-visibility-mixed-descendants-ref.html:0-5;0-500">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.target {
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+ background: blue;
+}
+.invisible {
+ top: 200px;
+ left: 200px;
+ width: 500px;
+ height: 500px;
+ position: relative;
+ background: red;
+ visibility: hidden;
+}
+.visible {
+ background: green;
+ width: 10px;
+ height: 10px;
+ visibility: visible;
+}
+
+::view-transition-group(root) {
+ visibility: hidden;
+ animation-duration: 500s;
+}
+::view-transition {
+ background: pink;
+}
+</style>
+
+<div class=target>
+ <div class=invisible><div class=visible></div></div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ const transition = document.startViewTransition();
+ transition.ready.then(takeScreenshot);
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/class-specificity-ref.html b/testing/web-platform/tests/css/css-view-transitions/class-specificity-ref.html
new file mode 100644
index 0000000000..5c882ada04
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/class-specificity-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>View transitions: class specificity (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+body {
+ background: pink;
+}
+div {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ background: blue;
+ border: 10px solid green;
+}
+</style>
+<div></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/class-specificity.html b/testing/web-platform/tests/css/css-view-transitions/class-specificity.html
new file mode 100644
index 0000000000..55de2ec388
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/class-specificity.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: class specificity</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="class-specificity-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#shared {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ background: blue;
+ view-transition-name: shared;
+ view-transition-class: sharedclass1 sharedclass2;
+}
+
+/* We're verifying what we capture, so just display the old contents for 5 minutes. */
+html::view-transition { background: pink; }
+html::view-transition-group(shared) { animation-duration: 300s; }
+
+html::view-transition-old(shared) {
+ animation: unset;
+ opacity: 1;
+ border: 10px solid red;
+}
+html::view-transition-old(*.sharedclass1.sharedclass2) {
+ border: 10px solid yellow;
+}
+
+html::view-transition-old(*.sharedclass1) {
+ border: 10px solid green;
+}
+
+html::view-transition-old(*) {
+ border: 10px solid orange;
+}
+
+html::view-transition-new(shared) { animation: unset; opacity: 0; }
+
+html::view-transition-old(root) { animation: unset; opacity: 0; }
+html::view-transition-new(root) { animation: unset; opacity: 0 }
+</style>
+<div id=shared></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-object-fit-fill-ref.html b/testing/web-platform/tests/css/css-view-transitions/content-object-fit-fill-ref.html
new file mode 100644
index 0000000000..b86e0a95a1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-object-fit-fill-ref.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<title>View transitions: display content in a pseudo with object-fit: none (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+#container {
+ width: 50px;
+ height: 50px;
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ overflow: hidden;
+}
+#content {
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ transform-origin: top left;
+ transform: scale(0.5);
+}
+#inner {
+ width: 10px;
+ height: 10px;
+ background: green;
+ top: 5px;
+ left: 10px;
+}
+
+html { background: lightpink; }
+</style>
+
+<div id=container><div id=content><div id=inner></div></div></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-object-fit-none-ref.html b/testing/web-platform/tests/css/css-view-transitions/content-object-fit-none-ref.html
new file mode 100644
index 0000000000..8bd63e9a88
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-object-fit-none-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>View transitions: display content in a pseudo with object-fit: none (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+#container {
+ width: 50px;
+ height: 50px;
+ position: absolute;
+ top: 10px;
+ left: 10px;
+}
+#content {
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+}
+
+html { background: lightpink; }
+</style>
+
+<div id=container><div id=content>This is text</div></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-smaller-than-box-size-ref.html b/testing/web-platform/tests/css/css-view-transitions/content-smaller-than-box-size-ref.html
new file mode 100644
index 0000000000..381a311cc4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-smaller-than-box-size-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>View transitions: element with content less than box size (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+}
+#inner {
+ width: 10px;
+ height: 10px;
+ background: blue;
+ position: relative;
+ top: 10px;
+ left: 10px;
+}
+</style>
+
+<div id=target>
+ <div id=inner></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-smaller-than-box-size.html b/testing/web-platform/tests/css/css-view-transitions/content-smaller-than-box-size.html
new file mode 100644
index 0000000000..d2b8f63ca0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-smaller-than-box-size.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: element with content less than box size</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="content-smaller-than-box-size-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+div { contain: paint; }
+#target {
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+}
+#inner {
+ width: 10px;
+ height: 10px;
+ background: blue;
+ position: relative;
+ top: 10px;
+ left: 10px;
+}
+
+.hidden {
+ background: pink;
+ width: 10px;
+ height: 10px;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+html::view-transition-old(target) { animation: unset; opacity: 1; }
+
+</style>
+
+<div id=target>
+ <div id=inner></div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(takeScreenshot);
+ });
+}
+onload = () => requestAnimationFrame(runTest);
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-visibility-auto-shared-element-ref.html b/testing/web-platform/tests/css/css-view-transitions/content-visibility-auto-shared-element-ref.html
new file mode 100644
index 0000000000..f4a34967ec
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-visibility-auto-shared-element-ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: offscreen content</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+body { background: pink }
+.flex {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: flex-start;
+}
+.box {
+ width: 100px;
+ height: 500px;
+ contain: paint;
+ background: green;
+ border: 1px solid black;
+ box-sizing: border-box;
+}
+.vis-hidden {
+ visibility: hidden;
+}
+.cv-hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<div class=flex>
+ <div class="box vis-hidden">ancestor c-v</div>
+ <div class="box cv-hidden">self c-v</div>
+ <div class="box cv-hidden">descendant c-v</div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-visibility-auto-shared-element.html b/testing/web-platform/tests/css/css-view-transitions/content-visibility-auto-shared-element.html
new file mode 100644
index 0000000000..11b4957fbc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-visibility-auto-shared-element.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: offscreen content with content-visibility auto</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="content-visibility-auto-shared-element-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+body {
+ overflow: hidden;
+}
+.flex {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: flex-start;
+}
+.box {
+ width: 100px;
+ height: 500px;
+ contain: paint;
+}
+.shared {
+ background: green;
+ border: 1px solid black;
+ box-sizing: border-box;
+}
+.spacer {
+ height: 3000px;
+}
+#hidden {
+ width: 10px;
+ height: 10px;
+ background: red;
+ contain: paint;
+ view-transition-name: hidden;
+}
+.locked {
+ content-visibility: auto;
+ contain-intrinsic-size: 500px;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { visibility: hidden; }
+
+html::view-transition-group(*) { animation-duration: 0s; }
+html::view-transition-new(*) { animation: unset; opacity: 0; }
+html::view-transition-old(*) { animation: unset; opacity: 1; }
+html::view-transition-group(root) { display: none; }
+html::view-transition { background: pink }
+
+</style>
+
+<div class=flex>
+ <div id=dst1 class=box></div>
+ <div id=dst2 class=box></div>
+ <div id=dst3 class=box></div>
+</div>
+<div id=hidden></div>
+<div class=spacer></div>
+<div id=content>
+ <div id=lockme><div id=src1 class="box shared" style="view-transition-name: one">ancestor c-v</div></div>
+ <div id=src2 class="box shared locked" style="view-transition-name: two">self c-v</div>
+ <div id=src3 class="box shared" style="view-transition-name: three"><div class=locked>descendant c-v</div></div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ lockme.classList.add("locked");
+ document.startViewTransition(() => {
+ content.remove();
+ dst1.style = "view-transition-name: one";
+ dst2.style = "view-transition-name: two";
+ dst3.style = "view-transition-name: three";
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-with-child-with-transparent-background-ref.html b/testing/web-platform/tests/css/css-view-transitions/content-with-child-with-transparent-background-ref.html
new file mode 100644
index 0000000000..7b8c15b87f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-with-child-with-transparent-background-ref.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: element with child with transparent background (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+.shared {
+ width: 50px;
+ height: 50px;
+ background: grey;
+ position: fixed;
+ top: 25px;
+ left: 25px;
+ view-transition-name: target;
+}
+.target {
+ width: 100px;
+ height: 100px;
+ background: rgba(0,0,0,0);
+ will-change: opacity;
+ position: relative;
+ top: 50px;
+ left: 50px;
+}
+
+.embedded {
+ width: 25%;
+ height: 50%;
+ position: absolute;
+ top: 0px;
+ will-change: opacity;
+}
+
+#one{
+ left: 25%;
+ background: lightblue;
+}
+#two {
+ left: 50%;
+ background: lightgreen;
+}
+
+.hidden {
+ width: 10px;
+ height: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(shared) { animation: unset; }
+html::view-transition-old(shared) { animation: unset; opacity: 1; }
+html::view-transition-new(shared) { animation: unset; opacity: 0; }
+
+</style>
+<div class="shared">
+ <div class="target">
+ <div class="embedded" id="one"></div>
+ <div class="embedded" id="two"></div>
+ </div>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-with-child-with-transparent-background.html b/testing/web-platform/tests/css/css-view-transitions/content-with-child-with-transparent-background.html
new file mode 100644
index 0000000000..6c447aa1a8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-with-child-with-transparent-background.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: element with child with transparent background</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="content-with-child-with-transparent-background-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.shared {
+ width: 50px;
+ height: 50px;
+ background: grey;
+ position: fixed;
+ top: 25px;
+ left: 25px;
+ view-transition-name: shared;
+}
+.target {
+ width: 100px;
+ height: 100px;
+ background: rgba(0,0,0,0);
+ will-change: opacity;
+ position: relative;
+ top: 50px;
+ left: 50px;
+}
+
+.embedded {
+ width: 25%;
+ height: 50%;
+ position: absolute;
+ top: 0px;
+ will-change: opacity;
+}
+
+#one{
+ left: 25%;
+ background: lightblue;
+}
+#two {
+ left: 50%;
+ background: lightgreen;
+}
+
+.hidden {
+ width: 10px;
+ height: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(shared) { animation: unset; }
+html::view-transition-old(shared) { animation: unset; opacity: 1; }
+html::view-transition-new(shared) { animation: unset; opacity: 0; }
+
+</style>
+<div class="shared">
+ <div class="target">
+ <div class="embedded" id="one"></div>
+ <div class="embedded" id="two"></div>
+ </div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition().ready.then(requestAnimationFrame(takeScreenshot));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-with-clip-ref.html b/testing/web-platform/tests/css/css-view-transitions/content-with-clip-ref.html
new file mode 100644
index 0000000000..a322301686
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-with-clip-ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>View transitions: element with clip (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.target {
+ contain: paint;
+ width: 100px;
+ height: 100vh;
+ display: inline-block;
+}
+
+.embedded {
+ width: 100%;
+ height: 50%;
+}
+
+body {
+ height: 150vh;
+ background: pink;
+}
+</style>
+<div id="target1" class="target">
+ <div class="embedded" style="background: green;"></div>
+ <div class="embedded" style="background: blue"></div>
+</div>
+<div id="target2" class="target">
+ <div class="embedded" style="background: green;"></div>
+ <div class="embedded" style="background: blue"></div>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-with-clip-root-ref.html b/testing/web-platform/tests/css/css-view-transitions/content-with-clip-root-ref.html
new file mode 100644
index 0000000000..f81a96370e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-with-clip-root-ref.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>View transitions: element with clip (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.container {
+ width: 100vw;
+ height: 100vh;
+ position: fixed;
+ top: -50vh;
+ left: 0px;
+ overflow: auto;
+}
+.target {
+ contain: paint;
+ width: 100px;
+ height: 100vh;
+ display: inline-block;
+}
+
+.embedded {
+ width: 100%;
+ height: 50%;
+}
+
+body {
+ margin: 0px;
+ height: 150vh;
+}
+</style>
+<div id="container">
+<div id="target1" class="target">
+ <div class="embedded" style="background: green;"></div>
+</div>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-with-clip-root.html b/testing/web-platform/tests/css/css-view-transitions/content-with-clip-root.html
new file mode 100644
index 0000000000..5acd847734
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-with-clip-root.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: root element with clip</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="content-with-clip-root-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ contain: paint;
+ width: 100px;
+ height: 100vh;
+ position: relative;
+ top: 50vh;
+ display: inline-block;
+}
+
+.embedded {
+ width: 100%;
+ height: 50%;
+}
+
+.hidden {
+ contain: paint;
+ width: 10px;
+ height: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+body {
+ margin: 0px;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(target2) {
+ opacity: 0;
+}
+
+html::view-transition-group(root) {
+ top: -50vh;
+ bottom: 50vh;
+}
+
+html::view-transition-old(root) { animation: unset; opacity: 0; height: 100%; }
+html::view-transition-new(root) { animation: unset; opacity: 1; height: 100%; }
+
+</style>
+
+<div id="target1" class="target">
+ <div class="embedded" style="background: green;"></div>
+ <div class="embedded" style="background: blue"></div>
+</div>
+<div id="target2" class="target">
+ <div class="embedded" style="background: green;"></div>
+ <div class="embedded" style="background: blue"></div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ // Add a shared element to ensure its bounds don't expand the root snapshot
+ // size.
+ target2.style = "view-transition-name: target2";
+
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-with-clip.html b/testing/web-platform/tests/css/css-view-transitions/content-with-clip.html
new file mode 100644
index 0000000000..28bfa86875
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-with-clip.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: element with clip</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="content-with-clip-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ contain: paint;
+ width: 100px;
+ height: 100vh;
+ position: relative;
+ top: 50vh;
+ display: inline-block;
+}
+
+.embedded {
+ width: 100%;
+ height: 50%;
+}
+
+.hidden {
+ contain: paint;
+ width: 10px;
+ height: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+/* Makes sure the viewport height is consistent for scrollbars to align */
+body {
+ height: 150vh;
+}
+
+html::view-transition {
+ background: pink;
+ height: 100%;
+}
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(target1), html::view-transition-group(target2) {
+ position: absolute;
+ top: -50vh;
+}
+html::view-transition-old(target1) { animation: unset; opacity: 1; }
+html::view-transition-new(target2) { animation: unset; opacity: 1; }
+html::view-transition-group(root) { display: none }
+
+</style>
+
+<div id="target1" class="target" style="view-transition-name: target1">
+ <div class="embedded" style="background: green;"></div>
+ <div class="embedded" style="background: blue"></div>
+</div>
+<div id="target2" class="target">
+ <div class="embedded" style="background: green;"></div>
+ <div class="embedded" style="background: blue"></div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition(() => {
+ target1.style = "";
+ target2.style = "view-transition-name: target2";
+ });
+ transition.ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-with-inline-child-ref.html b/testing/web-platform/tests/css/css-view-transitions/content-with-inline-child-ref.html
new file mode 100644
index 0000000000..4bb87f316f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-with-inline-child-ref.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<title>View transitions: element with inline child (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<link rel="author" href="mailto:bokan@chromium.org">
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ overflow-clip-margin: 500px;
+ contain: paint;
+ view-transition-name: target;
+ background-color: grey;
+}
+
+#child {
+ position: relative;
+ left: 100px;
+ top: 100px;
+ color: lightgreen;
+ background-color: darkgreen;
+}
+
+#innerchild {
+ position: relative;
+ left: 100px;
+}
+</style>
+
+<div id="target" style="font: 25px/1 Ahem">
+ <span id="child">INLINE<br><span id="innerchild">BOX</span></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-with-inline-child.html b/testing/web-platform/tests/css/css-view-transitions/content-with-inline-child.html
new file mode 100644
index 0000000000..f1a5ca79af
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-with-inline-child.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: element with inline child</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<link rel="author" href="mailto:bokan@chromium.org">
+<link rel="match" href="content-with-inline-child-ref.html">
+<meta name="flags" content="ahem">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+
+#target {
+ width: 100px;
+ height: 100px;
+ overflow-clip-margin: 500px;
+ contain: paint;
+ view-transition-name: target;
+ background-color: grey;
+}
+
+#child {
+ position: relative;
+ left: 100px;
+ top: 100px;
+ color: lightgreen;
+ background-color: darkgreen;
+}
+
+#innerchild {
+ position: relative;
+ left: 100px;
+}
+
+html::view-transition-new(root) {
+ opacity: 0;
+}
+html::view-transition-old(root) {
+ opacity: 0;
+}
+
+html::view-transition-old(target) {
+ animation-duration: 3s;
+ animation-timing-function: steps(1, end);
+ opacity: 1;
+}
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+
+</style>
+
+<div id="target" style="font: 25px/1 Ahem">
+ <span id="child">INLINE<br><span id="innerchild">BOX</span></span>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ // Remove the target to ensure the ref is compared against the snapshot.
+ document.getElementById("target").remove();
+
+ requestAnimationFrame(
+ () => requestAnimationFrame(
+ () => requestAnimationFrame(
+ () => requestAnimationFrame(takeScreenshot))));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-with-object-view-box-ref.html b/testing/web-platform/tests/css/css-view-transitions/content-with-object-view-box-ref.html
new file mode 100644
index 0000000000..7aa2014397
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-with-object-view-box-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>View transitions: capture elements with object view box on the pseudo (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+body { background: pink }
+#target {
+ position: relative;
+ top: 93.75px;
+ left: 71px;
+ background: green;
+ width: 143px;
+ height: 125px;
+}
+</style>
+<div id=target></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-with-overflow-ref.html b/testing/web-platform/tests/css/css-view-transitions/content-with-overflow-ref.html
new file mode 100644
index 0000000000..a24e30ede9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-with-overflow-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>View transitions: shared element with overflow (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+.target {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ background: blue;
+ overflow-clip-margin: 50px;
+ view-transition-name: target;
+}
+.child {
+ width: 200px;
+ height: 200px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+ background: green;
+}
+body { background: lightpink; }
+</style>
+
+<div class=target>
+ <div class=child>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-with-overflow-zoomed-ref.html b/testing/web-platform/tests/css/css-view-transitions/content-with-overflow-zoomed-ref.html
new file mode 100644
index 0000000000..a9d873957a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-with-overflow-zoomed-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>View transitions: shared element with overflow (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+.target {
+ width: 80px;
+ height: 80px;
+ contain: paint;
+ background: blue;
+ overflow-clip-margin: 50px;
+ view-transition-name: target;
+ zoom: 1.5;
+ border: 2px solid black;
+}
+.child {
+ width: 200px;
+ height: 200px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+ background: green;
+ zoom: 1.2;
+}
+body { background: lightpink; }
+</style>
+
+<div class=ancestor>
+ <div class=target>
+ <div class=child>
+ </div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-with-transform-new-image.html b/testing/web-platform/tests/css/css-view-transitions/content-with-transform-new-image.html
new file mode 100644
index 0000000000..9baf9563d1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-with-transform-new-image.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: object-view-box</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="content-with-transform-ref.html">
+<meta name="fuzzy" content="content-with-transform-ref.html:0-1;0-500">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ transform: scale(2.0, 3.0);
+ view-transition-name: target;
+}
+
+.embedded {
+ width: 100px;
+ height: 50px;
+}
+
+.hidden {
+ contain: paint;
+ width: 10px;
+ height: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+}
+html::view-transition-old(target) { animation: unset; opacity: 0; }
+
+</style>
+
+<div id="target" class="target">
+ <div class="embedded" style="background: green;">Shared</div>
+ <div class="embedded" style="background: blue">Element</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let t = document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(runTest);
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-with-transform-old-image.html b/testing/web-platform/tests/css/css-view-transitions/content-with-transform-old-image.html
new file mode 100644
index 0000000000..e3bd7fff1d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-with-transform-old-image.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<html class=reftest-wait>
+<title>View transitions: object-view-box</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="content-with-transform-ref.html">
+<meta name="fuzzy" content="content-with-transform-ref.html:0-1;0-400">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ transform: scale(2.0, 3.0);
+ view-transition-name: target;
+}
+
+.embedded {
+ width: 100px;
+ height: 50px;
+}
+
+.hidden {
+ contain: paint;
+ width: 10px;
+ height: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 1;
+}
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+
+</style>
+
+<div id="target" class="target">
+ <div class="embedded" style="background: green;">Shared</div>
+ <div class="embedded" style="background: blue">Element</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(runTest);
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-with-transform-ref.html b/testing/web-platform/tests/css/css-view-transitions/content-with-transform-ref.html
new file mode 100644
index 0000000000..568e040c1e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-with-transform-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>View transitions: object-view-box (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.target {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ transform: scale(2.0, 3.0);
+}
+
+.embedded {
+ width: 100px;
+ height: 50px;
+}
+
+</style>
+<div id="target" class="target">
+ <div class="embedded" style="background: green;">Shared</div>
+ <div class="embedded" style="background: blue">Element</div>
+</div>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-with-transparent-background-ref.html b/testing/web-platform/tests/css/css-view-transitions/content-with-transparent-background-ref.html
new file mode 100644
index 0000000000..7349d131d7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-with-transparent-background-ref.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<title>View transitions: element with transparent background (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+.target {
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+ position: fixed;
+ top: 25px;
+ left: 25px;
+ background: rgba(0,0,0,0);
+}
+
+.embedded {
+ width: 25%;
+ height: 50%;
+ position: absolute;
+ top: 0px;
+ will-change: opacity;
+}
+
+#one{
+ left: 25%;
+ background: lightblue;
+}
+#two {
+ left: 50%;
+ background: lightgreen;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(target) { animation: unset; }
+html::view-transition-old(target) { animation: unset; opacity: 1; }
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+
+</style>
+<div class="target">
+ <div class="embedded" id="one"></div>
+ <div class="embedded" id="two"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/content-with-transparent-background.html b/testing/web-platform/tests/css/css-view-transitions/content-with-transparent-background.html
new file mode 100644
index 0000000000..b961a095e7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/content-with-transparent-background.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: element with transparent background</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="content-with-transparent-background-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+ position: fixed;
+ top: 25px;
+ left: 25px;
+ background: rgba(0,0,0,0);
+}
+
+.embedded {
+ width: 25%;
+ height: 50%;
+ position: absolute;
+ top: 0px;
+ will-change: opacity;
+}
+
+#one{
+ left: 25%;
+ background: lightblue;
+}
+#two {
+ left: 50%;
+ background: lightgreen;
+}
+
+.hidden {
+ width: 10px;
+ height: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(target) { animation: unset; }
+html::view-transition-old(target) { animation: unset; opacity: 1; }
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+
+</style>
+<div class="target">
+ <div class="embedded" id="one"></div>
+ <div class="embedded" id="two"></div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition().ready.then(requestAnimationFrame(takeScreenshot));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/css-tags-paint-order-ref.html b/testing/web-platform/tests/css/css-view-transitions/css-tags-paint-order-ref.html
new file mode 100644
index 0000000000..780d5fbd45
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/css-tags-paint-order-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>View transitions: css tags generate pseudo elements in paint order (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+div {
+ position: absolute;
+ top: 50px;
+ width: 100px;
+ height: 100px;
+}
+#one {
+ background: green;
+ left: 50px;
+ z-index: 1;
+}
+#two {
+ background: yellow;
+ left: 125px;
+ z-index: -1;
+}
+#three {
+ background: blue;
+ left: 200px;
+ z-index: 0;
+}
+body { background: lightpink; }
+</style>
+
+<div id=one></div>
+<div id=two></div>
+<div id=three></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/css-tags-paint-order-with-entry-ref.html b/testing/web-platform/tests/css/css-view-transitions/css-tags-paint-order-with-entry-ref.html
new file mode 100644
index 0000000000..e7f62c2346
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/css-tags-paint-order-with-entry-ref.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<title>View transitions: css tags generate pseudo elements in paint order (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+div {
+ contain: paint;
+ position: absolute;
+ top: 50px;
+ width: 100px;
+ height: 100px;
+}
+#one {
+ background: green;
+ left: 50px;
+ z-index: 1;
+}
+#two {
+ background: yellow;
+ left: 125px;
+ z-index: -1;
+}
+#three {
+ background: blue;
+ left: 200px;
+ z-index: 0;
+}
+#four {
+ background: lightgreen;
+ left: 275px;
+ z-index: 0;
+}
+body { background: lightpink; }
+</style>
+
+<div id=one></div>
+<div id=two></div>
+<div id=three></div>
+<div id=four></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/css-tags-paint-order-with-entry.html b/testing/web-platform/tests/css/css-view-transitions/css-tags-paint-order-with-entry.html
new file mode 100644
index 0000000000..703b64f5c6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/css-tags-paint-order-with-entry.html
@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: css tags generate pseudo elements in paint order</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="css-tags-paint-order-with-entry-ref.html">
+<meta name="fuzzy" content="css-tags-paint-order-with-entry-ref.html:0-120;0-300">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+div { contain: paint; }
+#one {
+ background: green;
+ width: 100px;
+ height: 100px;
+ position: relative;
+ z-index: 1;
+ view-transition-name: one;
+}
+#two {
+ background: yellow;
+ width: 100px;
+ height: 100px;
+ view-transition-name: two;
+}
+#three {
+ background: blue;
+ width: 100px;
+ height: 100px;
+ view-transition-name: three;
+}
+#four {
+ position: absolute;
+ background: lightgreen;
+ width: 100px;
+ height: 100px;
+ top: 50px;
+ left: 275px;
+ view-transition-name: four;
+}
+
+.hidden {
+ background: pink;
+ width: 10px;
+ height: 10px;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(one) {
+ animation: unset;
+ transform: unset;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+}
+html::view-transition-group(two) {
+ animation: unset;
+ transform: unset;
+ position: absolute;
+ top: 50px;
+ left: 125px;
+}
+html::view-transition-group(three) {
+ animation: unset;
+ transform: unset;
+ position: absolute;
+ top: 50px;
+ left: 200px;
+}
+html::view-transition-new(four) {
+ animation: unset;
+ opacity: 1;
+}
+
+html::view-transition-new(one),
+html::view-transition-new(two),
+html::view-transition-new(three) { animation: unset; opacity: 0; }
+
+html::view-transition-old(one),
+html::view-transition-old(two),
+html::view-transition-old(three) { animation: unset; opacity: 1; }
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+
+</style>
+
+<div id=one></div>
+<div id=two></div>
+<div id=three></div>
+
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ const f = document.createElement("div");
+ f.id = "four";
+ document.body.appendChild(f);
+
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/css-tags-paint-order.html b/testing/web-platform/tests/css/css-view-transitions/css-tags-paint-order.html
new file mode 100644
index 0000000000..c0e8769b47
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/css-tags-paint-order.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: css tags generate pseudo elements in paint order</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="css-tags-paint-order-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+#one {
+ background: green;
+ width: 100px;
+ height: 100px;
+ position: relative;
+ z-index: 1;
+ view-transition-name: one;
+}
+#two {
+ background: yellow;
+ width: 100px;
+ height: 100px;
+ view-transition-name: two;
+}
+#three {
+ background: blue;
+ width: 100px;
+ height: 100px;
+ view-transition-name: three;
+}
+
+.hidden {
+ background: pink;
+ width: 10px;
+ height: 10px;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(one) {
+ animation: unset;
+ transform: unset;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+}
+html::view-transition-group(two) {
+ animation: unset;
+ transform: unset;
+ position: absolute;
+ top: 50px;
+ left: 125px;
+}
+html::view-transition-group(three) {
+ animation: unset;
+ transform: unset;
+ position: absolute;
+ top: 50px;
+ left: 200px;
+}
+
+html::view-transition-new(one),
+html::view-transition-new(two),
+html::view-transition-new(three) { animation: unset; opacity: 0; }
+
+html::view-transition-old(one),
+html::view-transition-old(two),
+html::view-transition-old(three) { animation: unset; opacity: 1; }
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+
+</style>
+
+<div id=one></div>
+<div id=two></div>
+<div id=three></div>
+
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/css-tags-shared-element-ref.html b/testing/web-platform/tests/css/css-view-transitions/css-tags-shared-element-ref.html
new file mode 100644
index 0000000000..23fa74dd5e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/css-tags-shared-element-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>View transitions: use css tags for shared elements (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+div { contain: paint; }
+#left {
+ background: blue;
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+}
+#right {
+ width: 50px;
+ height: 50px;
+ background: green;
+ position: absolute;
+ top: 50px;
+ left: 250px;
+}
+body { background: lightpink; }
+</style>
+
+<div id=left></div>
+<div id=right></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/css-tags-shared-element.html b/testing/web-platform/tests/css/css-view-transitions/css-tags-shared-element.html
new file mode 100644
index 0000000000..33bbae70fc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/css-tags-shared-element.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: use css tags for shared elements</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="css-tags-shared-element-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+div { contain: paint; }
+#left {
+ background: green;
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+}
+#right {
+ width: 50px;
+ height: 50px;
+ background: blue;
+ position: absolute;
+ top: 50px;
+ left: 250px;
+}
+.left-tag {
+ view-transition-name: left-element;
+}
+.right-tag {
+ view-transition-name: right-element;
+}
+
+.hidden {
+ background: pink;
+ width: 10px;
+ height: 10px;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(left-element),
+html::view-transition-group(right-element) { animation-duration: 0s; }
+
+html::view-transition-new(left-element),
+html::view-transition-new(right-element) { animation: unset; opacity: 0; }
+
+html::view-transition-old(left-element),
+html::view-transition-old(right-element) { animation: unset; opacity: 1; }
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+
+</style>
+
+<div id=left class="left-tag"></div>
+<div id=right class="right-tag"></div>
+
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ left.classList.remove("left-tag");
+ left.classList.add("right-tag");
+
+ right.classList.remove("right-tag");
+ right.classList.add("left-tag");
+
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/dialog-in-rtl-iframe-ref.html b/testing/web-platform/tests/css/css-view-transitions/dialog-in-rtl-iframe-ref.html
new file mode 100644
index 0000000000..44ed0947ab
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/dialog-in-rtl-iframe-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>View transitions: Dialog element in RTL scrollable iframe</title>
+ <link rel="help" href="https://github.com/WICG/view-transitions">
+ <link rel="author" href="mailto:bokan@chromium.org">
+ <style>
+ iframe {
+ width: 50vw;
+ height: 50vh;
+ }
+ </style>
+</head>
+
+<body>
+ <iframe src="support/dialog-in-rtl-iframe-child.html?show">
+ </iframe>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/dialog-in-rtl-iframe.html b/testing/web-platform/tests/css/css-view-transitions/dialog-in-rtl-iframe.html
new file mode 100644
index 0000000000..b9c0f7e25c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/dialog-in-rtl-iframe.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<head>
+ <title>View transitions: Dialog element in RTL scrollable iframe</title>
+ <link rel="help" href="https://github.com/WICG/view-transitions">
+ <link rel="author" href="mailto:bokan@chromium.org">
+ <link rel="match" href="dialog-in-rtl-iframe-ref.html">
+ <meta name=fuzzy content="dialog-in-rtl-iframe-ref.html:0-80;0-500">
+ <script src="/common/reftest-wait.js"></script>
+ <style>
+ iframe {
+ width: 50vw;
+ height: 50vh;
+ }
+ </style>
+ <script>
+ failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+ onload = () => {
+ requestAnimationFrame(()=>{requestAnimationFrame(()=> {
+ frames[0].window.startTransition();
+ frames[0].window.transition.ready.then(() => {
+ requestAnimationFrame(()=>{requestAnimationFrame(()=> {
+ takeScreenshot();
+ })});
+ });
+ })});
+ }
+ </script>
+</head>
+
+<body>
+ <iframe src="support/dialog-in-rtl-iframe-child.html">
+ </iframe>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/dialog-in-top-layer-during-transition-new.html b/testing/web-platform/tests/css/css-view-transitions/dialog-in-top-layer-during-transition-new.html
new file mode 100644
index 0000000000..91c2277366
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/dialog-in-top-layer-during-transition-new.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: element in top layer during transition</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="dialog-in-top-layer-during-transition-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ background: lightblue;
+
+ border: unset;
+ margin: 0;
+ padding: 0;
+
+ view-transition-name: dialog;
+ outline: none;
+}
+
+#target::backdrop {
+ width: 100px;
+ height: 100px;
+ background: grey;
+
+ view-transition-name: backdrop;
+}
+
+.hidden {
+ contain: paint;
+ width: 10px;
+ height: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(backdrop) {
+ position: fixed;
+ top: 120px;
+ left: 0;
+}
+
+html::view-transition-new(backdrop), html::view-transition-new(dialog) {
+ opacity: 1;
+ animation: unset;
+}
+</style>
+
+<dialog id="target"></dialog>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ const transition = document.startViewTransition(() => {
+ target.showModal();
+ target.style.background = "lightgreen";
+ });
+ await transition.ready;
+ takeScreenshot();
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/dialog-in-top-layer-during-transition-old.html b/testing/web-platform/tests/css/css-view-transitions/dialog-in-top-layer-during-transition-old.html
new file mode 100644
index 0000000000..406bdac32b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/dialog-in-top-layer-during-transition-old.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: element in top layer during transition</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="dialog-in-top-layer-during-transition-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ background: lightgreen;
+
+ border: unset;
+ margin: 0;
+ padding: 0;
+
+ view-transition-name: dialog;
+ outline: none;
+}
+
+#target::backdrop {
+ width: 100px;
+ height: 100px;
+ background: grey;
+
+ view-transition-name: backdrop;
+}
+
+.hidden {
+ contain: paint;
+ width: 10px;
+ height: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(backdrop) {
+ position: fixed;
+ top: 120px;
+ left: 0;
+}
+
+html::view-transition-old(backdrop), html::view-transition-old(dialog) {
+ opacity: 1;
+ animation: unset;
+}
+</style>
+
+<dialog id="target"></dialog>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ target.showModal();
+ const transition = document.startViewTransition(() => {
+ target.close();
+ target.style.background = "lightblue";
+ });
+ await transition.ready;
+ takeScreenshot();
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/dialog-in-top-layer-during-transition-ref.html b/testing/web-platform/tests/css/css-view-transitions/dialog-in-top-layer-during-transition-ref.html
new file mode 100644
index 0000000000..41467678a3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/dialog-in-top-layer-during-transition-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: element in top layer during transition (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<style>
+div {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+}
+
+.dialog {
+ background: lightgreen;
+}
+
+.backdrop {
+ background: grey;
+ top: 120px;
+}
+
+</style>
+<div class="dialog"></div>
+<div class="backdrop"></div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/document-element-detached-crash.html b/testing/web-platform/tests/css/css-view-transitions/document-element-detached-crash.html
new file mode 100644
index 0000000000..cfdf769695
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/document-element-detached-crash.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html class="test-wait">
+<title>View transitions: documentElement.remove</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+html {
+ display: none;
+}
+</style>
+
+<script>
+function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => {
+ const html = document.documentElement;
+ html.remove();
+ html.classList.remove('test-wait');
+ });
+ });
+}
+onload = () => requestAnimationFrame(runTest);
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/duplicate-tag-rejects-capture.html b/testing/web-platform/tests/css/css-view-transitions/duplicate-tag-rejects-capture.html
new file mode 100644
index 0000000000..951294babc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/duplicate-tag-rejects-capture.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: duplicate tags in the old DOM skip the transition</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ contain: paint;
+}
+</style>
+
+<div id=first></div>
+<div id=second></div>
+
+<script>
+promise_test(async t => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise((resolve, reject) => {
+ first.style = "view-transition-name: target";
+ second.style = "view-transition-name: target";
+ let transition = document.startViewTransition();
+
+ // Ready rejected first since invoking the dom callback is an async task.
+ let readyRejected = false;
+ transition.ready.then(reject, () => {readyRejected = true;});
+
+ // The domUpdate promise resolves (since there is no callback).
+ let updateCallbackDoneResolved = false;
+ transition.updateCallbackDone.then(() => {
+ assert_true(readyRejected, "ready not rejected before updateCallbackDone");
+ updateCallbackDoneResolved = true;
+ }, reject);
+
+ // Finally finish resolves.
+ transition.finished.then(() => {
+ assert_true(updateCallbackDoneResolved, "updateCallbackDone not resolved before finish");
+ resolve();
+ }, reject);
+ });
+}, "Two different elements with the same name in the old DOM should skip the transition");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/duplicate-tag-rejects-start.html b/testing/web-platform/tests/css/css-view-transitions/duplicate-tag-rejects-start.html
new file mode 100644
index 0000000000..6c99d6426c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/duplicate-tag-rejects-start.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: duplicate tags in the new DOM skip the transition</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ contain: paint;
+}
+</style>
+
+<div id=first></div>
+<div id=second></div>
+
+<script>
+promise_test(async t => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise((resolve, reject) => {
+ first.style = "view-transition-name: target";
+ let transition = document.startViewTransition(() => {
+ first.style = "view-transition-name: target";
+ second.style = "view-transition-name: target";
+ });
+
+ // First updateCallbackDone resolves since the callback runs successfully.
+ let updateCallbackDoneResolved = false;
+ transition.updateCallbackDone.then(() => { updateCallbackDoneResolved = true; }, reject);
+
+ // Then finished resolves since updateCallbackDone was already resolved.
+ let finishResolved = false;
+ transition.updateCallbackDone.then(() => {
+ assert_true(updateCallbackDoneResolved, "updateCallbackDone not resolved before finish");
+ finishResolved = true;
+ }, reject);
+
+ // Finally ready rejects.
+ transition.ready.then(reject, () => {
+ assert_true(finishResolved, "finish not resolved before ready");
+ resolve();
+ });
+ });
+}, "Two different elements with the same name in the new DOM should skip the transition");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/element-is-grouping-during-animation-ref.html b/testing/web-platform/tests/css/css-view-transitions/element-is-grouping-during-animation-ref.html
new file mode 100644
index 0000000000..38fca3c528
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/element-is-grouping-during-animation-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: element remains grouping during transition</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+.parent {
+ top: 0;
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ background: green;
+}
+body {
+ perspective: 1000px;
+ height: 500px;
+ background: pink
+}
+</style>
+
+<div class=parent></div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/element-is-grouping-during-animation.html b/testing/web-platform/tests/css/css-view-transitions/element-is-grouping-during-animation.html
new file mode 100644
index 0000000000..b1ef745e0d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/element-is-grouping-during-animation.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: view transition element remains grouping during animation</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="element-is-grouping-during-animation-ref.html">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.parent {
+ top: 0;
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ background: red;
+ transform-style: preserve-3d;
+}
+.named {
+ view-transition-name: target;
+}
+
+.child {
+ background: green;
+ width: 100px;
+ height: 100px;
+ top: 0;
+ left: 0;
+ position: absolute;
+ transform: translateZ(-500px);
+}
+
+body {
+ perspective: 1000px;
+ height: 500px;
+}
+
+::view-transition-group(root) {
+ animation-duration: 500s;
+ opacity: 0;
+}
+::view-transition-group(target) {
+ animation-duration: 0s;
+}
+::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+}
+::view-transition-old(target) {
+ animation: unset;
+ opacity: 0;
+}
+
+::view-transition {
+ background: pink;
+}
+</style>
+
+<div id=target class="parent named"><div class=child></div></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ let transition = document.startViewTransition();
+ transition.ready.then(() => {
+ requestAnimationFrame(() => {
+ target.classList.remove("named");
+ requestAnimationFrame(takeScreenshot);
+ });
+ });
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/element-stops-grouping-after-animation-ref.html b/testing/web-platform/tests/css/css-view-transitions/element-stops-grouping-after-animation-ref.html
new file mode 100644
index 0000000000..ccbb794b00
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/element-stops-grouping-after-animation-ref.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: element remains grouping during transition</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+.parent {
+ top: 0;
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ background: blue;
+ transform-style: preserve-3d;
+}
+.child {
+ background: green;
+ width: 100px;
+ height: 100px;
+ top: 0;
+ left: 0;
+ position: absolute;
+ transform: translateZ(-500px);
+}
+body {
+ perspective: 1000px;
+ height: 500px;
+}
+</style>
+
+<div class=parent><div class=child></div></div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/element-stops-grouping-after-animation.html b/testing/web-platform/tests/css/css-view-transitions/element-stops-grouping-after-animation.html
new file mode 100644
index 0000000000..df7965215e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/element-stops-grouping-after-animation.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: view transition element remains grouping during animation</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="element-stops-grouping-after-animation-ref.html">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.parent {
+ top: 0;
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ background: blue;
+ transform-style: preserve-3d;
+}
+.named {
+ view-transition-name: target;
+}
+
+.child {
+ background: green;
+ width: 100px;
+ height: 100px;
+ top: 0;
+ left: 0;
+ position: absolute;
+ transform: translateZ(-500px);
+}
+
+body {
+ perspective: 1000px;
+ height: 500px;
+}
+
+::view-transition-group(root) {
+ animation-duration: 50ms;
+ opacity: 0;
+}
+::view-transition-group(target) {
+ animation-duration: 0s;
+}
+::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+}
+::view-transition-old(target) {
+ animation: unset;
+ opacity: 0;
+}
+
+::view-transition {
+ background: pink;
+}
+</style>
+
+<div id=target class="parent named"><div class=child></div></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ let transition = document.startViewTransition();
+ transition.ready.then(() => {
+ requestAnimationFrame(() => {
+ target.classList.remove("named");
+ });
+ });
+ transition.finished.then(takeScreenshot);
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/element-with-overflow-ref.html b/testing/web-platform/tests/css/css-view-transitions/element-with-overflow-ref.html
new file mode 100644
index 0000000000..523c8616a6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/element-with-overflow-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: element with overflow ref</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+ .old_target {
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ width: 100px;
+ height: 100px;
+ background: lightblue;
+ transform: translate(8px, 8px);
+ }
+
+ .new_target {
+ position: fixed;
+ top: 200px;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background: lightgreen;
+ transform: translate(8px, 8px);
+ }
+
+ .inner {
+ width: 100px;
+ height: 100px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+ border: 5px solid black;
+ }
+</style>
+<div class="old_target">
+ <div class="inner"></div>
+</div>
+<div class="new_target">
+ <div class="inner" style="border:5px solid blue"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/element-with-overflow.html b/testing/web-platform/tests/css/css-view-transitions/element-with-overflow.html
new file mode 100644
index 0000000000..678e0a062e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/element-with-overflow.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: element with overflow</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="element-with-overflow-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+ .hidden {
+ width: 10px;
+ height: 10px;
+ view-transition-name: hidden;
+ background: green;
+ }
+
+ .target {
+ width: 100px;
+ height: 100px;
+ background: lightblue;
+ view-transition-name: target;
+ }
+ .inner {
+ width: 100px;
+ height: 100px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+ border: 5px solid black;
+ }
+
+ html::view-transition-group(hidden) { animation-duration: 300s; }
+ html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+ html::view-transition-new(*), html::view-transition-old(*) {
+ opacity: 1;
+ animation: unset;
+ }
+
+ html::view-transition-old(target) {
+ top: 0px;
+ left: 0px;
+ }
+
+ html::view-transition-new(target) {
+ top: 200px;
+ left: 0px;
+ }
+</style>
+
+<div class="target">
+ <div class="inner"></div>
+</div>
+<div class="hidden"></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ document.getElementsByClassName("target")[0].style.background="lightgreen";
+ document.getElementsByClassName("inner")[0].style.border="5px solid blue";
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/event-pseudo-name.html b/testing/web-platform/tests/css/css-view-transitions/event-pseudo-name.html
new file mode 100644
index 0000000000..bccf64915d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/event-pseudo-name.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<title>View transitions: event pseudo name</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="web-animations-api-ref.html">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+:root { view-transition-name: none; }
+#first {
+ background: blue;
+ width: 100px;
+ height: 100px;
+ view-transition-name: shared;
+}
+
+html::view-transition-group(*),
+html::view-transition-image-pair(*),
+html::view-transition-new(*),
+html::view-transition-old(*) {
+ animation-duration: 600s;
+}
+
+@keyframes fade-in {
+ from { opacity: 0; }
+}
+html::view-transition-image-pair(*) {
+ animation: fade-in 600s both;
+}
+
+</style>
+<div id=first></div>
+<script>
+async_test(t => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ let groupAnimationCount = 0;
+ let oldAnimationCount = 0;
+ let newAnimationCount = 0;
+ let wrapperAnimationCount = 0;
+
+ document.documentElement.addEventListener("animationstart", (e) => {
+ let pseudo = e.pseudoElement;
+ if (pseudo == "::view-transition-group(shared)") {
+ groupAnimationCount++;
+ } else if (pseudo == "::view-transition-new(shared)") {
+ newAnimationCount++;
+ } else if (pseudo == "::view-transition-old(shared)") {
+ oldAnimationCount++;
+ } else if (pseudo = "::view-transition-image-pair(shared)") {
+ wrapperAnimationCount++;
+ }
+
+ let total =
+ groupAnimationCount + oldAnimationCount + newAnimationCount + wrapperAnimationCount;
+ // Old/new images have 2 animations : opacity and mix-blend-mode.
+ if (total == 6) {
+ t.step(() => assert_equals(groupAnimationCount, 1));
+ t.step(() => assert_equals(wrapperAnimationCount, 1));
+ t.step(() => assert_equals(oldAnimationCount, 2));
+ t.step(() => assert_equals(newAnimationCount, 2));
+ t.done();
+ }
+ });
+ document.startViewTransition();
+}, "verifies pseudo name includes a tag");
+
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/exit-transition-with-anonymous-layout-object-ref.html b/testing/web-platform/tests/css/css-view-transitions/exit-transition-with-anonymous-layout-object-ref.html
new file mode 100644
index 0000000000..10e04ac58a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/exit-transition-with-anonymous-layout-object-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: exit transition with layout objects that don't have a node (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<style>
+body {
+ width: 100vw;
+ height: 100vh;
+ background: pink;
+}
+
+#target {
+ width: 100px;
+ height: 100px;
+ background: blue;
+}
+</style>
+<div id="target"></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/exit-transition-with-anonymous-layout-object.html b/testing/web-platform/tests/css/css-view-transitions/exit-transition-with-anonymous-layout-object.html
new file mode 100644
index 0000000000..ea2d17b276
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/exit-transition-with-anonymous-layout-object.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: exit transition with layout objects that don't have a node</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="exit-transition-with-anonymous-layout-object-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+body {
+ width: 100vw;
+ height: 100vh;
+}
+
+#target {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ view-transition-name: target;
+}
+
+#hidden {
+ width: 10px;
+ height: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+fieldset {
+ width: 100px;
+ height: 100px;
+ background: lightgreen;
+ overflow: clip;
+}
+
+html::view-transition { background: pink; }
+html::view-transition-group(root) { visibility: hidden; }
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 1;
+}
+</style>
+<div id="target"></div>
+<fieldset id="anonymous">hi</fieldset>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let t = document.startViewTransition(() => {
+ target.style.viewTransitionName = "none";
+ });
+ await t.ready;
+ anonymous.style.position = "relative";
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/far-away-capture-ref.html b/testing/web-platform/tests/css/css-view-transitions/far-away-capture-ref.html
new file mode 100644
index 0000000000..9e10b9b44e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/far-away-capture-ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: offscreen content</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+body { background: pink }
+.flex {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: flex-start;
+}
+.box {
+ width: 100px;
+ height: 500px;
+ contain: paint;
+ background: green;
+ border: 1px solid black;
+ box-sizing: border-box;
+}
+</style>
+
+<div class=flex>
+ <div class=box>500</div>
+ <div class=box>2000</div>
+ <div class=box>3500</div>
+ <div class=box>5000</div>
+ <div class=box>6500</div>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/far-away-capture.html b/testing/web-platform/tests/css/css-view-transitions/far-away-capture.html
new file mode 100644
index 0000000000..bfe0b9fb94
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/far-away-capture.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: offscreen content</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="far-away-capture-ref.html">
+<meta name="fuzzy" content="far-away-capture-ref.html:0-1;0-5">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.flex {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: flex-start;
+}
+.box {
+ width: 100px;
+ height: 500px;
+ contain: paint;
+}
+.shared {
+ background: green;
+ border: 1px solid black;
+ box-sizing: border-box;
+}
+.spacer {
+ height: 1000px;
+}
+#hidden {
+ width: 10px;
+ height: 10px;
+ background: red;
+ contain: paint;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { visibility: hidden; }
+
+html::view-transition-group(*) { animation-duration: 0s; }
+html::view-transition-new(*) { animation: unset; opacity: 0; }
+html::view-transition-old(*) { animation: unset; opacity: 1; }
+html::view-transition-group(root) { display: none; }
+html::view-transition { background: pink }
+
+</style>
+
+<div class=flex>
+ <div id=dst1 class=box></div>
+ <div id=dst2 class=box></div>
+ <div id=dst3 class=box></div>
+ <div id=dst4 class=box></div>
+ <div id=dst5 class=box></div>
+</div>
+<div id=hidden></div>
+<div id=content>
+ <div id=src1 class="box shared" style="view-transition-name: one">500</div>
+ <div class=spacer></div>
+ <div id=src2 class="box shared" style="view-transition-name: two">2000</div>
+ <div class=spacer></div>
+ <div id=src3 class="box shared" style="view-transition-name: three">3500</div>
+ <div class=spacer></div>
+ <div id=src4 class="box shared" style="view-transition-name: four">5000</div>
+ <div class=spacer></div>
+ <div id=src5 class="box shared" style="view-transition-name: five">6500</div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ content.remove();
+ dst1.style = "view-transition-name: one";
+ dst2.style = "view-transition-name: two";
+ dst3.style = "view-transition-name: three";
+ dst4.style = "view-transition-name: four";
+ dst5.style = "view-transition-name: five";
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/fractional-box-new.html b/testing/web-platform/tests/css/css-view-transitions/fractional-box-new.html
new file mode 100644
index 0000000000..407636b967
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fractional-box-new.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: fractional box -- new content</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="fractional-box-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ margin: 15px;
+ background: green;
+ width: 100.125px;
+ height: 50.875px;
+}
+.shift {
+ position: relative;
+ left: 0.4px;
+}
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 1; }
+html::view-transition-old(*) { animation: unset; opacity: 0; }
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+<div class="box" style="view-transition-name: one"></div>
+<div class="box shift" style="view-transition-name: two"></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition().ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/fractional-box-old.html b/testing/web-platform/tests/css/css-view-transitions/fractional-box-old.html
new file mode 100644
index 0000000000..915cd41704
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fractional-box-old.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: fractional box -- old content</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="fractional-box-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ margin: 15px;
+ background: green;
+ width: 100.125px;
+ height: 50.875px;
+}
+.shift {
+ position: relative;
+ left: 0.4px;
+}
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 0; }
+html::view-transition-old(*) { animation: unset; opacity: 1; }
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+<div class="box" style="view-transition-name: one"></div>
+<div class="box shift" style="view-transition-name: two"></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition().ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/fractional-box-ref.html b/testing/web-platform/tests/css/css-view-transitions/fractional-box-ref.html
new file mode 100644
index 0000000000..e5fb0f80d9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fractional-box-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>View transitions: fractional box -- reference</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.box {
+ margin: 15px;
+ background: green;
+ width: 100.125px;
+ height: 50.875px;
+}
+.shift {
+ position: relative;
+ left: 0.4px;
+}
+body { background: lightpink }
+</style>
+<div class="box"></div>
+<div class="box shift"></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-overflow-children-new.html b/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-overflow-children-new.html
new file mode 100644
index 0000000000..e50e6654a7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-overflow-children-new.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: fractional box with overflow children -- new content</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="fractional-box-with-overflow-children-ref.html">
+<!-- subpixel differences are ok in this test (in highdpi), but channel difference
+ should not be perceptible -->
+<meta name=fuzzy content="fractional-box-with-overflow-children-ref.html:0-3;0-100">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ position: relative;
+ margin: 15px;
+ background: green;
+ width: 100.125px;
+ height: 50.875px;
+}
+.shift {
+ left: 0.4px;
+}
+.child1 {
+ position: absolute;
+ left: -2px;
+ width: 110px;
+ height: 25px;
+ background: darkgreen;
+}
+.child2 {
+ position: absolute;
+ top: -3px;
+ width: 50px;
+ height: 55px;
+ background: darkgreen;
+}
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 1; }
+html::view-transition-old(*) { animation: unset; opacity: 0; }
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+<div class="box" style="view-transition-name: one"><div class="child1"></div><div class="child2"></div></div>
+<div class="box shift" style="view-transition-name: two"><div class="child1"></div><div class="child2"></div></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition().ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-overflow-children-old.html b/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-overflow-children-old.html
new file mode 100644
index 0000000000..acf72e20df
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-overflow-children-old.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: fractional box with overflow children -- old content</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="fractional-box-with-overflow-children-ref.html">
+<!-- subpixel differences are ok in this test (in highdpi), but channel difference
+ should not be perceptible -->
+<meta name=fuzzy content="fractional-box-with-overflow-children-ref.html:0-3;0-100">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ position: relative;
+ margin: 15px;
+ background: green;
+ width: 100.125px;
+ height: 50.875px;
+}
+.shift {
+ left: 0.4px;
+}
+.child1 {
+ position: absolute;
+ left: -2px;
+ width: 110px;
+ height: 25px;
+ background: darkgreen;
+}
+.child2 {
+ position: absolute;
+ top: -3px;
+ width: 50px;
+ height: 55px;
+ background: darkgreen;
+}
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 0; }
+html::view-transition-old(*) { animation: unset; opacity: 1; }
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+<div class="box" style="view-transition-name: one"><div class="child1"></div><div class="child2"></div></div>
+<div class="box shift" style="view-transition-name: two"><div class="child1"></div><div class="child2"></div></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition().ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-overflow-children-ref.html b/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-overflow-children-ref.html
new file mode 100644
index 0000000000..8e53dcd266
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-overflow-children-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>View transitions: fractional box with overflow children-- reference</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.box {
+ position: relative;
+ margin: 15px;
+ background: green;
+ width: 100.125px;
+ height: 50.875px;
+}
+.shift {
+ left: 0.4px;
+}
+.child1 {
+ position: absolute;
+ left: -2px;
+ width: 110px;
+ height: 25px;
+ background: darkgreen;
+}
+.child2 {
+ position: absolute;
+ top: -3px;
+ width: 50px;
+ height: 55px;
+ background: darkgreen;
+}
+body { background: lightpink }
+</style>
+<div class="box"><div class="child1"></div><div class="child2"></div></div>
+<div class="box shift"><div class="child1"></div><div class="child2"></div></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-shadow-new.html b/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-shadow-new.html
new file mode 100644
index 0000000000..820a48b1b0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-shadow-new.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: fractional box with shadow -- new content</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="fractional-box-with-shadow-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ box-shadow: -2px -3px 0 7px darkgreen;
+ margin: 15px;
+ background: green;
+ width: 100.125px;
+ height: 50.875px;
+}
+.shift {
+ position: relative;
+ left: 0.4px;
+}
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 1; }
+html::view-transition-old(*) { animation: unset; opacity: 0; }
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+<div class="box" style="view-transition-name: one"></div>
+<div class="box shift" style="view-transition-name: two"></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition().ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-shadow-old.html b/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-shadow-old.html
new file mode 100644
index 0000000000..882f8992ad
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-shadow-old.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: fractional box with shadow -- old content</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="fractional-box-with-shadow-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ box-shadow: -2px -3px 0 7px darkgreen;
+ margin: 15px;
+ background: green;
+ width: 100.125px;
+ height: 50.875px;
+}
+.shift {
+ position: relative;
+ left: 0.4px;
+}
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 0; }
+html::view-transition-old(*) { animation: unset; opacity: 1; }
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+<div class="box" style="view-transition-name: one"></div>
+<div class="box shift" style="view-transition-name: two"></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition().ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-shadow-ref.html b/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-shadow-ref.html
new file mode 100644
index 0000000000..639641aeb5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fractional-box-with-shadow-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title>View transitions: fractional box with shadow -- reference</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.box {
+ box-shadow: -2px -3px 0 7px darkgreen;
+ margin: 15px;
+ background: green;
+ width: 100.125px;
+ height: 50.875px;
+}
+.shift {
+ position: relative;
+ left: 0.4px;
+}
+body { background: lightpink }
+</style>
+<div class="box"></div>
+<div class="box shift"></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/fractional-translation-from-position-ref.html b/testing/web-platform/tests/css/css-view-transitions/fractional-translation-from-position-ref.html
new file mode 100644
index 0000000000..0674b265ac
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fractional-translation-from-position-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: fractional translation from position (ref)</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+body {
+ width: 100vw;
+ height: 100vh;
+ background: grey;
+}
+
+#target {
+ width: 100px;
+ height: 100px;
+ position: fixed;
+ top: 100.52px;
+ left: 100.37px;
+
+ view-transition-name: target;
+ contain: layout;
+ will-change: filter;
+}
+</style>
+
+<div id=target>
+ Here is some text which should not be blurry.
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/fractional-translation-from-position.html b/testing/web-platform/tests/css/css-view-transitions/fractional-translation-from-position.html
new file mode 100644
index 0000000000..a09b08cf00
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fractional-translation-from-position.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: fractional translation from position</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="fractional-translation-from-position-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+body {
+ width: 100vw;
+ height: 100vh;
+ background: grey;
+}
+
+#target {
+ width: 100px;
+ height: 100px;
+ position: fixed;
+ top: 100.52px;
+ left: 100.37px;
+
+ view-transition-name: target;
+ contain: layout;
+}
+
+/* Keep the animation running for 30s to screenshot pseudo DOM */
+::view-transition-new(root), ::view-transition-old(root) {
+ animation-duration: 30s;
+}
+
+::view-transition-new(target) {
+ opacity: 1;
+ animation: unset;
+}
+::view-transition-old(target) {
+ opacity: 0;
+ animation: unset;
+}
+</style>
+
+<div id=target>
+ Here is some text which should not be blurry.
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/fractional-translation-from-transform-ref.html b/testing/web-platform/tests/css/css-view-transitions/fractional-translation-from-transform-ref.html
new file mode 100644
index 0000000000..0721fca578
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fractional-translation-from-transform-ref.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: fractional translation from CSS transform (ref)</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+body {
+ width: 100vw;
+ height: 100vh;
+ background: grey;
+}
+
+#target {
+ width: 100px;
+ height: 100px;
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ transform: translate(100.52px, 100.37px);
+
+ view-transition-name: target;
+ contain: layout;
+ will-change: transform;
+}
+</style>
+
+<div id=target>
+ Here is some text which should not be blurry.
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/fractional-translation-from-transform.html b/testing/web-platform/tests/css/css-view-transitions/fractional-translation-from-transform.html
new file mode 100644
index 0000000000..7027a90086
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fractional-translation-from-transform.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: fractional translation from CSS transform</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="fractional-translation-from-transform-ref.html">
+<meta name="fuzzy" content="maxDifference=0-2; totalPixels=0-100">
+<script src="/common/reftest-wait.js"></script>
+<style>
+body {
+ width: 100vw;
+ height: 100vh;
+ background: grey;
+}
+
+#target {
+ width: 100px;
+ height: 100px;
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ transform: translate(100.52px, 100.37px);
+
+ view-transition-name: target;
+ contain: layout;
+}
+
+/* Keep the animation running for 30s to screenshot pseudo DOM */
+::view-transition-new(root), ::view-transition-old(root) {
+ animation-duration: 30s;
+}
+
+::view-transition-new(target) {
+ opacity: 1;
+ animation: unset;
+}
+::view-transition-old(target) {
+ opacity: 0;
+ animation: unset;
+}
+</style>
+
+<div id=target>
+ Here is some text which should not be blurry.
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/fragmented-at-start-ignored-ref.html b/testing/web-platform/tests/css/css-view-transitions/fragmented-at-start-ignored-ref.html
new file mode 100644
index 0000000000..626e03d012
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fragmented-at-start-ignored-ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>View transitions: fragmented elements skipped (ref)</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+body { background: pink }
+#spacer {
+ width: 100px;
+ height: 950px;
+ background: lightgreen;
+}
+#container {
+ width: 500px;
+ columns: 2;
+ height: 500px;
+ visibility: hidden;
+}
+#target {
+ width: 200px;
+ height: 200px;
+ background: green;
+}
+#unrelated {
+ width: 100px;
+ height: 100px;
+ background: lightblue;
+}
+</style>
+<div id=container>
+ <div id=spacer></div>
+ <div id=target></div>
+</div>
+<div id=unrelated></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/fragmented-at-start-ignored.html b/testing/web-platform/tests/css/css-view-transitions/fragmented-at-start-ignored.html
new file mode 100644
index 0000000000..bab52f1567
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fragmented-at-start-ignored.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: fragmented elements skipped</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="fragmented-at-start-ignored-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+#spacer {
+ width: 100px;
+ height: 950px;
+ background: lightgreen;
+}
+#container {
+ width: 500px;
+ columns: 2;
+ height: 500px;
+}
+#target {
+ width: 200px;
+ height: 200px;
+ background: green;
+ view-transition-name: target;
+}
+#unrelated {
+ width: 100px;
+ height: 100px;
+ background: lightblue;
+ view-transition-name: unrelated;
+}
+
+::view-transition {
+ background: pink;
+}
+::view-transition-group(root) {
+ animation-duration: 500s;
+ visibility: hidden;
+}
+::view-transition-group(target) {
+ border: 1px solid black;
+}
+</style>
+<div id=container>
+ <div id=spacer></div>
+ <div id=target></div>
+</div>
+<div id=unrelated></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTransition() {
+ document.startViewTransition().ready.then(takeScreenshot);
+}
+
+requestAnimationFrame(() => requestAnimationFrame(runTransition))
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/fragmented-during-transition-skips-ref.html b/testing/web-platform/tests/css/css-view-transitions/fragmented-during-transition-skips-ref.html
new file mode 100644
index 0000000000..269a6a2b9a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fragmented-during-transition-skips-ref.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<title>View transitions: fragmented elements skipped</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+#spacer {
+ width: 100px;
+ height: 950px;
+ background: lightgreen;
+}
+#container {
+ width: 500px;
+ height: 500px;
+ columns: 2;
+}
+#target {
+ width: 200px;
+ height: 200px;
+ background: green;
+}
+#unrelated {
+ width: 100px;
+ height: 100px;
+ background: lightblue;
+}
+</style>
+<div id=container>
+ <div id=spacer></div>
+ <div id=target></div>
+</div>
+<div id=unrelated></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/fragmented-during-transition-skips.html b/testing/web-platform/tests/css/css-view-transitions/fragmented-during-transition-skips.html
new file mode 100644
index 0000000000..dc4164dae5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/fragmented-during-transition-skips.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: fragmented elements skipped</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="fragmented-during-transition-skips-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+#spacer {
+ width: 100px;
+ height: 950px;
+ background: lightgreen;
+}
+#container {
+ width: 500px;
+ height: 500px;
+}
+.fragment {
+ columns: 2;
+}
+#target {
+ width: 200px;
+ height: 200px;
+ background: green;
+ view-transition-name: target;
+}
+#unrelated {
+ width: 100px;
+ height: 100px;
+ background: lightblue;
+ view-transition-name: unrelated;
+}
+
+::view-transition {
+ background: pink;
+}
+::view-transition-group(root) {
+ animation-duration: 500s;
+ visibility: hidden;
+}
+::view-transition-group(target) {
+ border: 1px solid black;
+}
+</style>
+<div id=container>
+ <div id=spacer></div>
+ <div id=target></div>
+</div>
+<div id=unrelated></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTransition() {
+ let t = document.startViewTransition();
+ t.ready.then(() => {
+ requestAnimationFrame(() => container.classList.add("fragment"))
+ });
+ t.finished.then(takeScreenshot);
+}
+
+requestAnimationFrame(() => requestAnimationFrame(runTransition))
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/get-computed-style-crash.html b/testing/web-platform/tests/css/css-view-transitions/get-computed-style-crash.html
new file mode 100644
index 0000000000..38cd5af7f8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/get-computed-style-crash.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>getComputedStyle without transition should not crash</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<body onload="start();">
+
+<script>
+async function start() {
+ var el = document.createElement(undefined);
+ document.body.appendChild(el);
+
+ var style = self.getComputedStyle(el, ':view-transition');
+ style.getPropertyValue("--child");
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/group-animation-for-root-transition.html b/testing/web-platform/tests/css/css-view-transitions/group-animation-for-root-transition.html
new file mode 100644
index 0000000000..9c702663e6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/group-animation-for-root-transition.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: group pseudo for the root transition has animation</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ let transition = document.startViewTransition();
+ transition.ready.then(() => {
+ let groupAnimationCount = 0;
+ let oldAnimationCount = 0;
+ let newAnimationCount = 0;
+
+ document.getAnimations().forEach((animation) => {
+ let pseudo = animation.effect.pseudoElement;
+ if (pseudo == "::view-transition-group(root)") {
+ groupAnimationCount++;
+ } else if (pseudo == "::view-transition-new(root)") {
+ newAnimationCount++;
+ } else if (pseudo == "::view-transition-old(root)") {
+ oldAnimationCount++;
+ } else {
+ reject();
+ }
+ });
+
+ let total =
+ groupAnimationCount + oldAnimationCount + newAnimationCount;
+ // Old/new images have 2 animations : opacity and mix-blend-mode.
+ if (total == 5) {
+ assert_equals(groupAnimationCount, 1);
+ assert_equals(oldAnimationCount, 2);
+ assert_equals(newAnimationCount, 2);
+ resolve();
+ } else {
+ reject();
+ }
+ });
+ });
+}, "incorrect UA animations for root transition");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/hit-test-unpainted-element-from-point.html b/testing/web-platform/tests/css/css-view-transitions/hit-test-unpainted-element-from-point.html
new file mode 100644
index 0000000000..7c9ed911cb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/hit-test-unpainted-element-from-point.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<title>View transitions: hit test shared element at the real dom location</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="hit-test-unpainted-element-ref.html">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+html { view-transition-name: none }
+#target {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ view-transition-name: shared;
+ position: relative;
+ z-index: 1;
+}
+.before {
+ background: yellow;
+ left: 200px;
+}
+.after {
+ background: green;
+}
+.after:hover {
+ background: red;
+}
+#unrelated {
+ width: 50px;
+ height: 50px;
+ position: relative;
+ top: -50px;
+ background: blue;
+}
+
+html::view-transition {
+ pointer-events: none;
+}
+html::view-transition-group(*) {
+ pointer-events: auto;
+}
+
+html::view-transition-group(shared) {
+ animation-delay: 300s;
+}
+html::view-transition-old(shared) {
+ animation: unset;
+ opacity: 1;
+}
+html::view-transition-new(shared) {
+ display: none;
+}
+</style>
+
+<div id=target class=before></div>
+<div id=unrelated></div>
+
+<script>
+async_test(t => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ document.startViewTransition(() => {
+ target.classList.toggle("before");
+ target.classList.toggle("after");
+ requestAnimationFrame(async () => {
+ // Check the old location of the element, we should get body.
+ t.step(() => assert_equals(document.elementFromPoint(20, 20), document.body));
+ // Check the new location of the pseudo element, we should get documentElement,
+ // which is the originating element for the pseudo element.
+ t.step(() => assert_equals(document.elementFromPoint(220, 20), document.documentElement));
+ // Check the spot that used to be covered by the element but now has
+ // unrelated element, which is what we expect to get.
+ t.step(() => assert_equals(document.elementFromPoint(20, 70), unrelated));
+ t.done();
+ });
+ });
+}, "hit test should not hit unpainted element, but does hit pseudo and unrelated elements");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/hit-test-unpainted-element-ref.html b/testing/web-platform/tests/css/css-view-transitions/hit-test-unpainted-element-ref.html
new file mode 100644
index 0000000000..dce9f27d90
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/hit-test-unpainted-element-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>View transitions: hit test shared element at the real dom location (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: relative;
+ background: green;
+ left: 200px;
+}
+</style>
+
+<div></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/hit-test-unpainted-element.html b/testing/web-platform/tests/css/css-view-transitions/hit-test-unpainted-element.html
new file mode 100644
index 0000000000..68026edfb1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/hit-test-unpainted-element.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: hit test shared element at the real dom location</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="hit-test-unpainted-element-ref.html">
+
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+html { view-transition-name: none }
+div {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ view-transition-name: shared;
+}
+.before {
+ position: relative;
+ background: yellow;
+ left: 200px;
+}
+.after {
+ background: green;
+}
+.after:hover {
+ background: red;
+}
+
+html::view-transition-group(shared) {
+ animation-delay: 300s;
+}
+html::view-transition-old(shared) {
+ animation: unset;
+ opacity: 0;
+}
+html::view-transition-new(shared) {
+ animation: unset;
+ opacity: 1;
+}
+</style>
+
+<div id=target class=before></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function mouseMoveToTarget(x, y) {
+ return new test_driver.Actions().pointerMove(x, y).send();
+}
+
+async function runTest() {
+ document.startViewTransition(() => {
+ target.classList.toggle("before");
+ target.classList.toggle("after");
+ // Ensure that we exit the capture phase before doing the rest of the test,
+ // since we want the animating phase to do hit-testing.
+ requestAnimationFrame(async () => {
+ await mouseMoveToTarget(10, 10);
+ requestAnimationFrame(takeScreenshot);
+ });
+ });
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/hit-test-unrelated-element-ref.html b/testing/web-platform/tests/css/css-view-transitions/hit-test-unrelated-element-ref.html
new file mode 100644
index 0000000000..bca532b22c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/hit-test-unrelated-element-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>View transitions: hit test shared element at the real dom location (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ background: blue;
+ position: relative;
+ left: 200px;
+}
+#unrelated {
+ width: 100px;
+ height: 100px;
+ background: green;
+ position: relative;
+ top: 200px;
+ left: 200px;
+}
+
+</style>
+
+<div id=target></div>
+<div id=unrelated></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/hit-test-unrelated-element.html b/testing/web-platform/tests/css/css-view-transitions/hit-test-unrelated-element.html
new file mode 100644
index 0000000000..1b8868280b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/hit-test-unrelated-element.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: hit test shared element at the real dom location</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="hit-test-unrelated-element-ref.html">
+
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+html { view-transition-name: none }
+#target {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ background: blue;
+ view-transition-name: shared;
+}
+#target.before {
+ position: relative;
+ left: 200px;
+}
+
+#unrelated {
+ width: 100px;
+ height: 100px;
+ background: red;
+ position: relative;
+ top: 200px;
+ left: 200px;
+}
+#unrelated:hover {
+ background: green;
+}
+
+html::view-transition {
+ pointer-events: none;
+}
+html::view-transition-group(*) {
+ pointer-events: auto;
+}
+
+html::view-transition-group(shared) {
+ animation-delay: 300s;
+}
+html::view-transition-old(shared) {
+ animation: unset;
+ opacity: 0;
+}
+html::view-transition-new(shared) {
+ animation: unset;
+ opacity: 1;
+}
+</style>
+
+<div id=target class=before></div>
+<div id=unrelated></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function mouseMoveToTarget(x, y) {
+ return new test_driver.Actions().pointerMove(x, y).send();
+}
+
+async function runTest() {
+ document.startViewTransition(() => {
+ target.classList.toggle("before");
+ requestAnimationFrame(async () => {
+ await mouseMoveToTarget(210, 310);
+ requestAnimationFrame(takeScreenshot);
+ });
+ });
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/iframe-new-has-scrollbar-ref.html b/testing/web-platform/tests/css/css-view-transitions/iframe-new-has-scrollbar-ref.html
new file mode 100644
index 0000000000..ea895e8484
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/iframe-new-has-scrollbar-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>View transitions: iframe transition to scrollbar (ref)</title>
+ <link rel="help" href="https://github.com/WICG/view-transitions">
+ <link rel="author" href="mailto:bokan@chromium.org">
+ <style>
+ iframe {
+ width: 50vw;
+ height: 50vh;
+ }
+ </style>
+</head>
+
+<body>
+ <iframe src="support/iframe-scrollbar-child.html?scrollbar">
+ </iframe>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/iframe-new-has-scrollbar.html b/testing/web-platform/tests/css/css-view-transitions/iframe-new-has-scrollbar.html
new file mode 100644
index 0000000000..37a300902a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/iframe-new-has-scrollbar.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<head>
+ <title>View transitions: iframe transition to scrollbar</title>
+ <link rel="help" href="https://github.com/WICG/view-transitions">
+ <link rel="author" href="mailto:bokan@chromium.org">
+ <link rel="match" href="iframe-new-has-scrollbar-ref.html">
+ <meta name=fuzzy content="iframe-new-has-scrollbar-ref.html:0-80;0-500">
+ <script src="/common/reftest-wait.js"></script>
+ <style>
+ iframe {
+ width: 50vw;
+ height: 50vh;
+ }
+ </style>
+ <script>
+ failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+ onload = () => {
+ requestAnimationFrame(()=>{requestAnimationFrame(()=> {
+ frames[0].window.startTransition();
+ frames[0].window.transition.ready.then(() => {
+ requestAnimationFrame(()=>{requestAnimationFrame(()=> {
+ // Expect that the scrollbar should appear immediately, even though
+ // the new snapshot isn't visible (since the scrollbar isn't part
+ // of the snapshot).
+ takeScreenshot();
+ })});
+ });
+ })});
+ }
+ </script>
+</head>
+
+<body>
+ <iframe src="support/iframe-scrollbar-child.html">
+ </iframe>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/iframe-old-has-scrollbar-ref.html b/testing/web-platform/tests/css/css-view-transitions/iframe-old-has-scrollbar-ref.html
new file mode 100644
index 0000000000..3bb9bdb88d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/iframe-old-has-scrollbar-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>View transitions: iframe transition from scrollbar (ref)</title>
+ <link rel="help" href="https://github.com/WICG/view-transitions">
+ <link rel="author" href="mailto:bokan@chromium.org">
+ <style>
+ iframe {
+ width: 50vw;
+ height: 50vh;
+ }
+ </style>
+</head>
+
+<body>
+ <iframe src="support/iframe-scrollbar-child.html">
+ </iframe>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/iframe-old-has-scrollbar.html b/testing/web-platform/tests/css/css-view-transitions/iframe-old-has-scrollbar.html
new file mode 100644
index 0000000000..014a429994
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/iframe-old-has-scrollbar.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<head>
+ <title>View transitions: iframe transition from scrollbar</title>
+ <link rel="help" href="https://github.com/WICG/view-transitions">
+ <link rel="author" href="mailto:bokan@chromium.org">
+ <link rel="match" href="iframe-old-has-scrollbar-ref.html">
+ <meta name=fuzzy content="iframe-old-has-scrollbar-ref.html:0-80;0-500">
+ <script src="/common/reftest-wait.js"></script>
+ <style>
+ iframe {
+ width: 50vw;
+ height: 50vh;
+ }
+ </style>
+ <script>
+ failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+ onload = () => {
+ requestAnimationFrame(()=>{requestAnimationFrame(()=> {
+ frames[0].window.startTransition();
+ frames[0].window.transition.ready.then(() => {
+ requestAnimationFrame(()=>{requestAnimationFrame(()=> {
+ // Expect that the scrollbar should disappear immediately since it
+ // isn't part of the snapshot.
+ takeScreenshot();
+ })});
+ });
+ })});
+ }
+ </script>
+</head>
+
+<body>
+ <iframe src="support/iframe-scrollbar-child.html?scrollbar">
+ </iframe>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/iframe-transition-destroyed-document-crash.html b/testing/web-platform/tests/css/css-view-transitions/iframe-transition-destroyed-document-crash.html
new file mode 100644
index 0000000000..31f6a10ed6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/iframe-transition-destroyed-document-crash.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: crash test</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<script src="/common/reftest-wait.js"></script>
+<html>
+<head>
+<script>
+function eventhandler1() {
+ var var00106 = htmlvar00011.contentDocument;
+ var var00228 = var00106.startViewTransition();
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(takeScreenshot);
+ })
+ });
+}
+
+</script>
+</head>
+<body>
+<iframe id="htmlvar00011" onunload="eventhandler3()" border="0" srcdoc="A#:^;&lt;gV&lt;&gt;8" style=":{,J" referrerpolicy="unsafe-url" background="!xp&gt;" nohref="nohref" nonce="nonce" inputEncoding="s" offsetX="0.3538512271910753">:+j&amp;;&amp;-^&gt;.7xf\jZ1,xb</iframe>
+<style id="htmlvar00014" nonce="nonce" media="screen and (min-width:0px)" onerror="eventhandler1()" onload="eventhandler1()" dir="N5!" updateRangeEnd="0" abbr="4IvGMN[Wxd" symbols="=d##y#)DA4V8ya}KO.cv" frameBorder="^b*]&amp;:|#lB:" search="N">ynFXo*</style>
+</body>
+</html>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/iframe-transition-ref.html b/testing/web-platform/tests/css/css-view-transitions/iframe-transition-ref.html
new file mode 100644
index 0000000000..49394f35f6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/iframe-transition-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>View transitions: iframe</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+iframe { width: 500px; height: 500px }
+</style>
+
+<iframe srcdoc="
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+html { height: 50%; }
+</style>
+
+<div></div>
+"></iframe>
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/iframe-transition.sub.html b/testing/web-platform/tests/css/css-view-transitions/iframe-transition.sub.html
new file mode 100644
index 0000000000..93a5cbed66
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/iframe-transition.sub.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: iframe</title>
+<meta name="timeout" content="long">
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="iframe-transition-ref.html">
+<meta name="assert" content="Ensure that iframe root capture is sized and displayed correctly">
+<meta name=fuzzy content="iframe-transition-ref.html:0-200;0-200">
+<script src="/common/reftest-wait.js"></script>
+<style>
+iframe { width: 500px; height: 500px }
+</style>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+addEventListener("message", takeScreenshot);
+</script>
+
+<iframe id=frame src="http://{{domains[www]}}:{{ports[http][0]}}/css/css-view-transitions/support/frame-helper.html"></iframe>
diff --git a/testing/web-platform/tests/css/css-view-transitions/inline-child-with-filter-ref.html b/testing/web-platform/tests/css/css-view-transitions/inline-child-with-filter-ref.html
new file mode 100644
index 0000000000..44a41f1bf9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/inline-child-with-filter-ref.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>View transitions: inline child with filter (ref)</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+body { margin : 0; }
+#target {
+ width: 100px;
+ height: 100px;
+ background-color: grey;
+ overflow-clip-margin: 40px;
+ contain: paint;
+ view-transition-name: target;
+}
+
+#child {
+ position: relative;
+ left: 100px;
+ top: 100px;
+ color: lightgreen;
+ background-color: darkgreen;
+ filter: blur(30px);
+}
+</style>
+
+<div id="target">
+ <span id="child">INLINEBOX</span>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/inline-child-with-filter.html b/testing/web-platform/tests/css/css-view-transitions/inline-child-with-filter.html
new file mode 100644
index 0000000000..2c4a8b85ec
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/inline-child-with-filter.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: inline child with filter</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="inline-child-with-filter-ref.html">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+body { margin : 0; }
+#target {
+ width: 100px;
+ height: 100px;
+ background-color: grey;
+ overflow-clip-margin: 40px;
+ contain: paint;
+ view-transition-name: target;
+}
+
+#child {
+ position: relative;
+ left: 100px;
+ top: 100px;
+ color: lightgreen;
+ background-color: darkgreen;
+ filter: blur(30px);
+}
+
+html::view-transition-group(root) { animation-duration: 300s; }
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 1;
+}
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 0;
+}
+</style>
+
+<div id="target">
+ <span id="child">INLINEBOX</span>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition(async () => {
+ document.getElementById("target").remove();
+ });
+ transition.ready.then(() => requestAnimationFrame(takeScreenshot));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/inline-element-size-ref.html b/testing/web-platform/tests/css/css-view-transitions/inline-element-size-ref.html
new file mode 100644
index 0000000000..177594c870
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/inline-element-size-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: capture elements with display inline (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+body {
+ background: pink;
+}
+#box {
+ background: green;
+}
+
+</style>
+
+<span id=box>BOX</span>
+
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/inline-element-size.html b/testing/web-platform/tests/css/css-view-transitions/inline-element-size.html
new file mode 100644
index 0000000000..c9f0d48942
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/inline-element-size.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>View transitions: capture elements with display inline</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="inline-element-size-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#box {
+ background: green;
+ view-transition-name: target;
+}
+
+/* We're verifying what we capture, so just display the old contents for 5 minutes. */
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-group(target) { background: green; }
+html::view-transition-new(*) { animation: unset; opacity: 0; }
+html::view-transition-old(*) { animation: unset; opacity: 1; }
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: pink; }
+</style>
+
+<span id=box>BOX</span>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let t = document.startViewTransition();
+ t.ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/inline-with-offset-from-containing-block-ref.html b/testing/web-platform/tests/css/css-view-transitions/inline-with-offset-from-containing-block-ref.html
new file mode 100644
index 0000000000..4a66af4ece
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/inline-with-offset-from-containing-block-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: inline with offset from containing block (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<style>
+ .outer {
+ transform: scale(2);
+ width: 100vw;
+ text-align: center;
+ }
+ .inner {
+ transform: translate(10px);
+ padding: 10px;
+ border: 10px solid black;
+ }
+ body {
+ background: pink;
+ }
+</style>
+
+<div class="outer">
+ <a class="inner">Some text</a>
+</div>
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/inline-with-offset-from-containing-block.html b/testing/web-platform/tests/css/css-view-transitions/inline-with-offset-from-containing-block.html
new file mode 100644
index 0000000000..8640899814
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/inline-with-offset-from-containing-block.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: inline with offset from containing block</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="inline-with-offset-from-containing-block-ref.html">
+<meta name="fuzzy" content="inline-with-offset-from-containing-block-ref.html:0-255;0-1400">
+
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+<style>
+ .outer {
+ transform: scale(2);
+ width: 100vw;
+ text-align: center;
+ }
+ .inner {
+ padding: 10px;
+ transform: translate(20px);
+ view-transition-name: text;
+ }
+ :root {
+ view-transition-name: none;
+ }
+
+ html::view-transition {
+ background: pink;
+ }
+ html::view-transition-group(text) {
+ border: 10px solid black;
+ margin: -10px 0 0 -10px;
+ animation-play-state: paused;
+ }
+</style>
+
+<div class="outer">
+ <a class="inner">Some text</a>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition();
+ transition.ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/input-targets-root-while-render-blocked.html b/testing/web-platform/tests/css/css-view-transitions/input-targets-root-while-render-blocked.html
new file mode 100644
index 0000000000..dbeb39da54
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/input-targets-root-while-render-blocked.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: ensure input targets document root while rendering is suppressed</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7797">
+<link rel="author" href="mailto:bokan@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<style>
+:root {
+ /* Ensure clicks during the transition fall through the pseudo tree root to
+ * real DOM */
+ view-transition-name: none;
+}
+
+::view-transition {
+ /* Ensure clicks during the transition fall through the pseudo tree root to
+ * real DOM */
+ pointer-events: none;
+ width: 0;
+ height: 0;
+}
+
+::view-transition-group(*) {
+ animation-duration: 30s;
+}
+
+#clicktarget {
+ width: 100px;
+ height: 100px;
+ background: red;
+}
+
+#transition {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ contain: paint;
+ view-transition-name: transitionElement;
+}
+</style>
+
+<div id="clicktarget"></div>
+<div id="transition"></div>
+
+<script>
+const target = document.getElementById("clicktarget");
+
+async function sendAndWaitForClick() {
+ return new Promise(async (resolve) => {
+
+ function eventHandler(ev) {
+ resolve(ev);
+ }
+
+ document.documentElement.addEventListener("click", eventHandler);
+
+ await new test_driver.Actions()
+ .setContext(window)
+ .addPointer("mousePointer1", "mouse")
+ .pointerMove(10, 10, {origin: 'viewport', sourceName: "mousePointer1"})
+ .pointerDown({sourceName: "mousePointer1"})
+ .pointerUp({sourceName: "mousePointer1"})
+ .send();
+
+ document.documentElement.removeEventListener("click", eventHandler);
+ });
+}
+
+promise_test(async t => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ assert_not_equals(target, null, "PRECONDITION: target element is valid");
+
+ // Ensure input is initialized before blocking rendering.
+ await new test_driver.Actions()
+ .setContext(window)
+ .addPointer("mousePointer1", "mouse")
+ .pointerMove(0, 0, {origin: "viewport", sourceName: "mousePointer1"})
+ .send();
+
+ let clickEvent = null;
+
+ let transition = document.startViewTransition(async () => {
+ clickEvent = await sendAndWaitForClick();
+ });
+
+ await transition.ready;
+
+ assert_equals(clickEvent.target, document.documentElement,
+ "Events must target the transition root while render blocked");
+ clickEvent = null;
+
+ clickEvent = await sendAndWaitForClick();
+
+ // This just ensures we're not passing the above check by accident.
+ assert_equals(clickEvent.target, target,
+ "During transition, event should hit real DOM");
+
+}, "Input when rendering suppressed targets root");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/intrinsic-aspect-ratio-ref.html b/testing/web-platform/tests/css/css-view-transitions/intrinsic-aspect-ratio-ref.html
new file mode 100644
index 0000000000..4455ad6172
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/intrinsic-aspect-ratio-ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: different width container should keep aspect ratio (by default)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.spacer {
+ /* 10px - border from above and below */
+ height: 6px;
+}
+.smallbox {
+ width: 50px;
+ height: 50px;
+ background: blue;
+}
+.bigbox {
+ width: 200px;
+ height: 200px;
+ background: blue;
+}
+
+body { background: lightpink; }
+</style>
+
+<div style="width: 50px; height: 100px; border: 2px solid black">
+ <div style="height: 50px; background: blue"></div>
+</div>
+<div class=spacer></div>
+<div style="width: 200px; height: 100px; border: 2px solid black">
+ <div style="height: 200px; background: blue"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/japanese-tag-ref.html b/testing/web-platform/tests/css/css-view-transitions/japanese-tag-ref.html
new file mode 100644
index 0000000000..8c57dba658
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/japanese-tag-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>View transitions: shared element writing-modes (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+.tb { writing-mode: horizontal-tb; }
+.lr { writing-mode: vertical-lr; }
+.rl { writing-mode: vertical-rl; }
+.shared {
+ margin: 2px;
+ width: 100px;
+ height: 50px;
+ background: green;
+ contain: paint;
+ border: 1px solid black;
+}
+html { background: lightpink; }
+</style>
+
+<div id=one class="tb shared">T</div>
+<div id=two class="lr shared">T</div>
+<div id=three class="rl shared">T</div>
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/japanese-tag.html b/testing/web-platform/tests/css/css-view-transitions/japanese-tag.html
new file mode 100644
index 0000000000..976dcab4fc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/japanese-tag.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: shared element writing-modes</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="japanese-tag-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#hidden {
+ width: 100px;
+ height: 100px;
+ background: red;
+ position: absolute;
+ top: 0;
+ left: 0;
+ contain: paint;
+ view-transition-name: 隠れた;
+}
+.tb { writing-mode: horizontal-tb; }
+.lr { writing-mode: vertical-lr; }
+.rl { writing-mode: vertical-rl; }
+.shared {
+ margin: 2px;
+ width: 100px;
+ height: 50px;
+ background: green;
+ contain: paint;
+ border: 1px solid black;
+}
+#target1, #target2, #target3 {
+ background: red;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+ width: 100px;
+ height: 500px;
+ contain: paint;
+}
+#one { view-transition-name: 第一; }
+#two { view-transition-name: 第二; }
+#three { view-transition-name: 第三; }
+
+html::view-transition-group(隠れた) { animation-duration: 300s; }
+html::view-transition-image-pair(隠れた) { animation: unset; opacity: 0; }
+
+html::view-transition-group(第一),
+html::view-transition-group(第二),
+html::view-transition-group(第三) {
+ animation-delay: 300s;
+ animation-fill-mode: both;
+}
+
+html::view-transition-new(第一),
+html::view-transition-new(第二),
+html::view-transition-new(第三) { animation: unset; opacity: 0; }
+
+html::view-transition-old(第一),
+html::view-transition-old(第二),
+html::view-transition-old(第三) { animation: unset; opacity: 1; }
+
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+
+</style>
+
+<div id=hidden>Should not be visible</div>
+<div id=target1>Should not be visible</div>
+<div id=target2>Should not be visible</div>
+<div id=target3>Should not be visible</div>
+<div id=one class="shared tb">T</div>
+<div id=two class="shared lr">T</div>
+<div id=three class="shared rl">T</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ one.remove();
+ two.remove();
+ three.remove();
+ hidden.style.left = "200px";
+ target1.style.viewTransitionName = "第一";
+ target2.style.viewTransitionName = "第二";
+ target3.style.viewTransitionName = "第三";
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
+
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/list-style-position-style-change-crash.html b/testing/web-platform/tests/css/css-view-transitions/list-style-position-style-change-crash.html
new file mode 100644
index 0000000000..5910d5d95a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/list-style-position-style-change-crash.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html class="test-wait">
+<title>View transitions: list-style-position crash</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:bokan@chromium.org">
+
+<script>
+onload = async () => {
+ let vt = document.startViewTransition();
+ await vt.ready;
+ await new Promise(resolve => requestAnimationFrame(resolve));
+
+ document.documentElement.style.listStylePosition = 'inside';
+ // Force style update.
+ window.scrollX;
+
+ document.documentElement.classList.remove('test-wait');
+}
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-below-and-on-top-of-viewport-partially-onscreen-new.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-and-on-top-of-viewport-partially-onscreen-new.html
new file mode 100644
index 0000000000..9a00a62b7a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-and-on-top-of-viewport-partially-onscreen-new.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element below and on top of viewport partially onscreen (new content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-below-and-on-top-of-viewport-partially-onscreen-ref.html">
+<meta name="fuzzy" content="massive-element-below-and-on-top-of-viewport-partially-onscreen-ref.html:maxDifference=0-2;totalPixels=0-330">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ position: fixed;
+ inset-block-start: -90px;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+html::view-transition-old(target) { animation: unset; opacity: 0; }
+html::view-transition-new(target) { animation: unset; opacity: 1; }
+
+</style>
+
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-below-and-on-top-of-viewport-partially-onscreen-old.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-and-on-top-of-viewport-partially-onscreen-old.html
new file mode 100644
index 0000000000..ed16ac5662
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-and-on-top-of-viewport-partially-onscreen-old.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element below and on top of viewport partially onscreen (new content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-below-and-on-top-of-viewport-partially-onscreen-ref.html">
+<meta name="fuzzy" content="massive-element-below-and-on-top-of-viewport-partially-onscreen-ref.html:maxDifference=0-2;totalPixels=0-330">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ position: fixed;
+ inset-block-start: -90px;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+html::view-transition-old(target) { animation: unset; opacity: 1; }
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+
+</style>
+
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-below-and-on-top-of-viewport-partially-onscreen-ref.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-and-on-top-of-viewport-partially-onscreen-ref.html
new file mode 100644
index 0000000000..507f9b8c0a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-and-on-top-of-viewport-partially-onscreen-ref.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>View transitions: massive element below viewport partially onscreen (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+.target {
+ position: fixed;
+ inset-block-start: -90px;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+</style>
+<body>
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+</body>
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-offscreen-new.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-offscreen-new.html
new file mode 100644
index 0000000000..b5c0d4e9ae
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-offscreen-new.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element below viewport and completely offscreen (new content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-below-viewport-offscreen-ref.html">
+<meta name="fuzzy" content="massive-element-below-viewport-offscreen-ref.html:maxDifference=0-3;totalPixels=0-950">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target_after_bottom_edge {
+ position: fixed;
+ inset-block-start: 20000px;
+ inset-inline-start: 0px;
+}
+
+.target {
+ contain: paint;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ position: fixed;
+ inset-block-start: 10000px;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+/* We should capture at least viewport height worth of content from the element's top edge */
+html::view-transition-group(target) {
+ animation: unset;
+ transform: unset;
+
+ position: fixed;
+ inset-block-start: 0;
+ inset-inline-start: 0;
+}
+html::view-transition-old(target) { animation: unset; opacity: 0; }
+html::view-transition-new(target) { animation: unset; opacity: 1; }
+
+</style>
+
+<div class="target target_after_bottom_edge" id="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-offscreen-old.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-offscreen-old.html
new file mode 100644
index 0000000000..6eeb85af3e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-offscreen-old.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element below viewport and completely offscreen (old content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-below-viewport-offscreen-ref.html">
+<meta name="fuzzy" content="massive-element-below-viewport-offscreen-ref.html:maxDifference=0-2;totalPixels=0-445">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target_after_bottom_edge {
+ position: fixed;
+ inset-block-start: 20000px;
+ inset-inline-start: 0px;
+}
+
+.target {
+ contain: paint;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ position: fixed;
+ inset-block-start: 10000px;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+/* We should capture at least viewport height worth of content from the element's top edge */
+html::view-transition-group(target) {
+ animation: unset;
+ transform: unset;
+
+ position: fixed;
+ inset-block-start: 0;
+ inset-inline-start: 0;
+}
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+html::view-transition-old(target) { animation: unset; opacity: 1; }
+
+</style>
+
+<div class="target target_after_bottom_edge" id="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-offscreen-ref.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-offscreen-ref.html
new file mode 100644
index 0000000000..05827eb196
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-offscreen-ref.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: massive element below viewport and completely offscreen (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<style>
+.target_after_bottom_edge {
+ position: fixed;
+ inset-block-start: 0px;
+ inset-inline-start: 0px;
+}
+
+.target {
+ contain: paint;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+</style>
+
+<div class="target target_after_bottom_edge" id="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-partially-onscreen-new.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-partially-onscreen-new.html
new file mode 100644
index 0000000000..54232ead6f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-partially-onscreen-new.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element below viewport partially onscreen (new content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-below-viewport-partially-onscreen-ref.html">
+<meta name="fuzzy" content="massive-element-below-viewport-partially-onscreen-ref.html:maxDifference=0-2;totalPixels=0-330">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+html::view-transition-old(target) { animation: unset; opacity: 0; }
+html::view-transition-new(target) { animation: unset; opacity: 1; }
+
+</style>
+
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-partially-onscreen-old.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-partially-onscreen-old.html
new file mode 100644
index 0000000000..772720def1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-partially-onscreen-old.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element below viewport partially onscreen (new content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-below-viewport-partially-onscreen-ref.html">
+<meta name="fuzzy" content="massive-element-below-viewport-partially-onscreen-ref.html:maxDifference=0-2;totalPixels=0-445">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+html::view-transition-old(target) { animation: unset; opacity: 1; }
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+
+</style>
+
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-partially-onscreen-ref.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-partially-onscreen-ref.html
new file mode 100644
index 0000000000..001c135f0a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-below-viewport-partially-onscreen-ref.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<title>View transitions: massive element below viewport partially onscreen (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+.target {
+ contain: paint;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ visibility: hidden;
+}
+</style>
+<body>
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-offscreen-new.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-offscreen-new.html
new file mode 100644
index 0000000000..d9d03d1e91
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-offscreen-new.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element on top of viewport and completely offscreen (new content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-left-of-viewport-offscreen-ref.html">
+<meta name="fuzzy" content="massive-element-left-of-viewport-offscreen-ref.html:maxDifference=0-2;totalPixels=0-330">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root {
+ writing-mode: vertical-lr;
+}
+
+.target_before_block_start_edge {
+ position: fixed;
+ inset-block-start: -40100px;
+ inset-inline-start: 0px;
+}
+
+.target {
+ contain: paint;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+/* We should capture at least viewport height worth of content from the element's bottom edge */
+html::view-transition-group(target) {
+ animation: unset;
+ transform: unset;
+
+ position: fixed;
+ top: unset;
+ left: unset;
+ inset-block-end: 0;
+ inset-inline-start: 0;
+}
+html::view-transition-old(target) { animation: unset; opacity: 0; }
+html::view-transition-new(target) { animation: unset; opacity: 1; }
+
+</style>
+
+<div class="target target_before_block_start_edge" id="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-offscreen-old.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-offscreen-old.html
new file mode 100644
index 0000000000..7861e5c3b8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-offscreen-old.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element on top of viewport and completely offscreen (old content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-left-of-viewport-offscreen-ref.html">
+<meta name="fuzzy" content="massive-element-left-of-viewport-offscreen-ref.html:maxDifference=0-3;totalPixels=0-330">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root {
+ writing-mode: vertical-lr;
+}
+
+.target_before_block_start_edge {
+ position: fixed;
+ inset-block-start: -40100px;
+ inset-inline-start: 0px;
+}
+
+.target {
+ contain: paint;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+/* We should capture at least viewport height worth of content from the element's bottom edge */
+html::view-transition-group(target) {
+ animation: unset;
+ transform: unset;
+
+ position: fixed;
+ top: unset;
+ left: unset;
+ inset-block-end: 0;
+ inset-inline-start: 0;
+}
+html::view-transition-old(target) { animation: unset; opacity: 1; }
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+
+</style>
+
+<div class="target target_before_block_start_edge" id="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-offscreen-ref.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-offscreen-ref.html
new file mode 100644
index 0000000000..32e688bbdb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-offscreen-ref.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<title>View transitions: massive element on top of viewport and completely offscreen (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+:root {
+ writing-mode: vertical-lr;
+}
+
+.target_at_bottom_edge {
+ position: fixed;
+ inset-block-end: 0;
+ inset-inline-start: 0;
+}
+
+.target {
+ contain: paint;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+</style>
+<body>
+<div class="target target_at_bottom_edge">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+</body>
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-partially-onscreen-new.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-partially-onscreen-new.html
new file mode 100644
index 0000000000..7c14cef2d0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-partially-onscreen-new.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element on top of viewport partially onscreen (new content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-left-of-viewport-partially-onscreen-ref.html">
+<meta name="fuzzy" content="massive-element-left-of-viewport-partially-onscreen-ref.html:maxDifference=0-2;totalPixels=0-330">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root {
+ writing-mode: vertical-lr;
+}
+
+.target {
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+html::view-transition-old(target) { animation: unset; opacity: 0; }
+html::view-transition-new(target) { animation: unset; opacity: 1; }
+
+</style>
+
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ scrollblue.scrollIntoView();
+
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-partially-onscreen-old.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-partially-onscreen-old.html
new file mode 100644
index 0000000000..b586f96de9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-partially-onscreen-old.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element on top of viewport partially onscreen (old content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-left-of-viewport-partially-onscreen-ref.html">
+<meta name="fuzzy" content="massive-element-left-of-viewport-partially-onscreen-ref.html:maxDifference=0-3;totalPixels=0-330">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root {
+ writing-mode: vertical-lr;
+}
+
+.target {
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+html::view-transition-old(target) { animation: unset; opacity: 1; }
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+
+</style>
+
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ scrollblue.scrollIntoView();
+
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-partially-onscreen-ref.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-partially-onscreen-ref.html
new file mode 100644
index 0000000000..8fa3050535
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-left-of-viewport-partially-onscreen-ref.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<title>View transitions: massive element on top of viewport partially onscreen (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+:root {
+ writing-mode: vertical-lr;
+}
+
+.target {
+ contain: paint;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ visibility: hidden;
+}
+</style>
+<body>
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+</body>
+<script>
+ scrollblue.scrollIntoView();
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-offscreen-new.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-offscreen-new.html
new file mode 100644
index 0000000000..f4a9f833df
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-offscreen-new.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element on top of viewport and completely offscreen (new content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-on-top-of-viewport-offscreen-ref.html">
+<meta name="fuzzy" content="massive-element-on-top-of-viewport-offscreen-ref.html:maxDifference=0-6;totalPixels=0-920">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target_before_block_start_edge {
+ position: fixed;
+ inset-block-start: -40100px;
+ inset-inline-start: 0px;
+}
+
+.target {
+ contain: paint;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+/* We should capture at least viewport height worth of content from the element's bottom edge */
+html::view-transition-group(target) {
+ animation: unset;
+ transform: unset;
+
+ position: fixed;
+ top: unset;
+ right: unset;
+ inset-block-end: 0;
+ inset-inline-start: 0;
+}
+html::view-transition-old(target) { animation: unset; opacity: 0; }
+html::view-transition-new(target) { animation: unset; opacity: 1; }
+
+</style>
+
+<div class="target target_before_block_start_edge" id="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-offscreen-old.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-offscreen-old.html
new file mode 100644
index 0000000000..a2eb0447bd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-offscreen-old.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element on top of viewport and completely offscreen (old content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-on-top-of-viewport-offscreen-ref.html">
+<meta name="fuzzy" content="massive-element-on-top-of-viewport-offscreen-ref.html:maxDifference=0-3;totalPixels=0-330">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target_before_block_start_edge {
+ position: fixed;
+ inset-block-start: -40100px;
+ inset-inline-start: 0px;
+}
+
+.target {
+ contain: paint;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+/* We should capture at least viewport height worth of content from the element's bottom edge */
+html::view-transition-group(target) {
+ animation: unset;
+ transform: unset;
+
+ position: fixed;
+ top: unset;
+ right: unset;
+ inset-block-end: 0;
+ inset-inline-start: 0;
+}
+html::view-transition-old(target) { animation: unset; opacity: 1; }
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+
+</style>
+
+<div class="target target_before_block_start_edge" id="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-offscreen-ref.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-offscreen-ref.html
new file mode 100644
index 0000000000..e835907738
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-offscreen-ref.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<title>View transitions: massive element on top of viewport and completely offscreen (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+.target_at_bottom_edge {
+ position: fixed;
+ inset-block-end: 0;
+ inset-inline-start: 0;
+}
+
+.target {
+ contain: paint;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+</style>
+<body>
+<div class="target target_at_bottom_edge">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+</body>
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-partially-onscreen-new.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-partially-onscreen-new.html
new file mode 100644
index 0000000000..764a311fc9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-partially-onscreen-new.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element on top of viewport partially onscreen (new content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-on-top-of-viewport-partially-onscreen-ref.html">
+<meta name="fuzzy" content="massive-element-on-top-of-viewport-partially-onscreen-ref.html:maxDifference=0-2;totalPixels=0-330">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+html::view-transition-old(target) { animation: unset; opacity: 0; }
+html::view-transition-new(target) { animation: unset; opacity: 1; }
+
+</style>
+
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ scrollblue.scrollIntoView();
+
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-partially-onscreen-old.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-partially-onscreen-old.html
new file mode 100644
index 0000000000..cecefd8f58
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-partially-onscreen-old.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element on top of viewport partially onscreen (old content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-on-top-of-viewport-partially-onscreen-ref.html">
+<meta name="fuzzy" content="massive-element-on-top-of-viewport-partially-onscreen-ref.html:maxDifference=0-3;totalPixels=0-330">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+html::view-transition-old(target) { animation: unset; opacity: 1; }
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+
+</style>
+
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ scrollblue.scrollIntoView();
+
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-partially-onscreen-ref.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-partially-onscreen-ref.html
new file mode 100644
index 0000000000..9c60e8bf1d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-on-top-of-viewport-partially-onscreen-ref.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<title>View transitions: massive element on top of viewport partially onscreen (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+.target {
+ contain: paint;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ visibility: hidden;
+}
+</style>
+<body>
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+</body>
+<script>
+ scrollblue.scrollIntoView();
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-right-and-left-of-viewport-partially-onscreen-new.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-and-left-of-viewport-partially-onscreen-new.html
new file mode 100644
index 0000000000..b1bae1c09b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-and-left-of-viewport-partially-onscreen-new.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element below and on top of viewport partially onscreen (new content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-right-and-left-of-viewport-partially-onscreen-ref.html">
+<meta name="fuzzy" content="massive-element-right-and-left-of-viewport-partially-onscreen-ref.html:maxDifference=0-2;totalPixels=0-330">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root {
+ writing-mode: vertical-lr;
+}
+
+.target {
+ position: fixed;
+ inset-block-start: -90px;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+html::view-transition-old(target) { animation: unset; opacity: 0; }
+html::view-transition-new(target) { animation: unset; opacity: 1; }
+
+</style>
+
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-right-and-left-of-viewport-partially-onscreen-old.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-and-left-of-viewport-partially-onscreen-old.html
new file mode 100644
index 0000000000..c878ce881e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-and-left-of-viewport-partially-onscreen-old.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element below and on top of viewport partially onscreen (new content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-right-and-left-of-viewport-partially-onscreen-ref.html">
+<meta name="fuzzy" content="massive-element-right-and-left-of-viewport-partially-onscreen-ref.html:maxDifference=0-2;totalPixels=0-330">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root {
+ writing-mode: vertical-lr;
+}
+
+.target {
+ position: fixed;
+ inset-block-start: -90px;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+html::view-transition-old(target) { animation: unset; opacity: 1; }
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+
+</style>
+
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-right-and-left-of-viewport-partially-onscreen-ref.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-and-left-of-viewport-partially-onscreen-ref.html
new file mode 100644
index 0000000000..3516741da0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-and-left-of-viewport-partially-onscreen-ref.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<title>View transitions: massive element below viewport partially onscreen (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+:root {
+ writing-mode: vertical-lr;
+}
+
+.target {
+ position: fixed;
+ inset-block-start: -90px;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+</style>
+<body>
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+</body>
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-offscreen-new.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-offscreen-new.html
new file mode 100644
index 0000000000..91b133f2cf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-offscreen-new.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element below viewport and completely offscreen (new content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-right-of-viewport-offscreen-ref.html">
+<meta name="fuzzy" content="massive-element-right-of-viewport-offscreen-ref.html:maxDifference=0-2;totalPixels=0-445">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root {
+ writing-mode: vertical-lr;
+}
+
+.target_after_bottom_edge {
+ position: fixed;
+ inset-block-start: 20000px;
+ inset-inline-start: 0px;
+}
+
+.target {
+ contain: paint;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ position: fixed;
+ inset-block-start: 10000px;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+/* We should capture at least viewport height worth of content from the element's top edge */
+html::view-transition-group(target) {
+ animation: unset;
+ transform: unset;
+
+ position: fixed;
+ inset-block-start: 0;
+ inset-inline-start: 0;
+}
+html::view-transition-old(target) { animation: unset; opacity: 0; }
+html::view-transition-new(target) { animation: unset; opacity: 1; }
+
+</style>
+
+<div class="target target_after_bottom_edge" id="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-offscreen-old.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-offscreen-old.html
new file mode 100644
index 0000000000..164ff05f93
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-offscreen-old.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element below viewport and completely offscreen (old content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-right-of-viewport-offscreen-ref.html">
+<meta name="fuzzy" content="massive-element-right-of-viewport-offscreen-ref.html:maxDifference=0-3;totalPixels=0-445">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root {
+ writing-mode: vertical-lr;
+}
+
+.target_after_bottom_edge {
+ position: fixed;
+ inset-block-start: 20000px;
+ inset-inline-start: 0px;
+}
+
+.target {
+ contain: paint;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ position: fixed;
+ inset-block-start: 10000px;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+/* We should capture at least viewport height worth of content from the element's top edge */
+html::view-transition-group(target) {
+ animation: unset;
+ transform: unset;
+
+ position: fixed;
+ inset-block-start: 0;
+ inset-inline-start: 0;
+}
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+html::view-transition-old(target) { animation: unset; opacity: 1; }
+
+</style>
+
+<div class="target target_after_bottom_edge" id="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-offscreen-ref.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-offscreen-ref.html
new file mode 100644
index 0000000000..f29d3ac609
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-offscreen-ref.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: massive element below viewport and completely offscreen (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<style>
+:root {
+ writing-mode: vertical-lr;
+}
+
+.target_after_bottom_edge {
+ position: fixed;
+ inset-block-start: 0px;
+ inset-inline-start: 0px;
+}
+
+.target {
+ contain: paint;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+</style>
+
+<div class="target target_after_bottom_edge" id="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-partially-onscreen-new.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-partially-onscreen-new.html
new file mode 100644
index 0000000000..b63ed07225
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-partially-onscreen-new.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element below viewport partially onscreen (new content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-right-of-viewport-partially-onscreen-ref.html">
+<meta name="fuzzy" content="massive-element-right-of-viewport-partially-onscreen-ref.html:maxDifference=0-2;totalPixels=0-330">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root {
+ writing-mode: vertical-lr;
+}
+
+.target {
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+html::view-transition-old(target) { animation: unset; opacity: 0; }
+html::view-transition-new(target) { animation: unset; opacity: 1; }
+
+</style>
+
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-partially-onscreen-old.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-partially-onscreen-old.html
new file mode 100644
index 0000000000..cf090e0ab4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-partially-onscreen-old.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: massive element below viewport partially onscreen (new content)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="massive-element-right-of-viewport-partially-onscreen-ref.html">
+<meta name="fuzzy" content="massive-element-right-of-viewport-partially-onscreen-ref.html:maxDifference=0-3;totalPixels=0-445">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root {
+ writing-mode: vertical-lr;
+}
+
+.target {
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(*), html::view-transition-new(*) {
+ object-fit: none;
+}
+
+html::view-transition-old(target) { animation: unset; opacity: 1; }
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+
+</style>
+
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-partially-onscreen-ref.html b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-partially-onscreen-ref.html
new file mode 100644
index 0000000000..1df26bb375
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/massive-element-right-of-viewport-partially-onscreen-ref.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<title>View transitions: massive element below viewport partially onscreen (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+:root {
+ writing-mode: vertical-lr;
+}
+
+.target {
+ contain: paint;
+ inline-size: 100px;
+ block-size: 40000px;
+ view-transition-name: target;
+}
+
+.top {
+ inline-size: 100%;
+ block-size: 100px;
+ background: lightblue;
+}
+
+.middle {
+ inline-size: 100%;
+ block-size: 39800px;
+ background: green;
+}
+
+.bottom {
+ inline-size: 100%;
+ block-size: 100px;
+ background: blue;
+}
+
+.hidden {
+ contain: paint;
+ inline-size: 10px;
+ block-size: 10px;
+ background: grey;
+ visibility: hidden;
+}
+</style>
+<body>
+<div class="target">
+ <div class="top">This text is at the top of the box</div>
+ <div class="middle">This text is in the middle of the box</div>
+ <div id="scrollblue" class="bottom">This text is at the bottom of the box</div>
+</div>
+<div id=hidden class=hidden></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-view-transitions/mix-blend-mode-only-on-transition.html b/testing/web-platform/tests/css/css-view-transitions/mix-blend-mode-only-on-transition.html
new file mode 100644
index 0000000000..4149142cf3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/mix-blend-mode-only-on-transition.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+<title>view-transitions: Blend modes are set up only in paired transitions</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ contain: paint;
+}
+.tagone { view-transition-name: one }
+.tagtwo { view-transition-name: two }
+.tagthree { view-transition-name: three }
+.tagfour { view-transition-name: four }
+.tagfive { view-transition-name: five }
+
+::view-transition-old(four) {
+ animation-name: unset;
+}
+::view-transition-new(five) {
+ animation-name: unset;
+}
+</style>
+
+<div id=first class=tagone></div>
+<div id=second></div>
+<div class=tagthree></div>
+<div class=tagfour></div>
+<div class=tagfive></div>
+
+<script>
+async_test(t => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ let transition = document.startViewTransition(() => {
+ first.classList.toggle("tagone");
+ second.classList.toggle("tagtwo");
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ t.step(() => assert_equals(getComputedStyle(document.documentElement, "::view-transition-image-pair(one)").isolation, "auto"));
+ t.step(() => assert_equals(getComputedStyle(document.documentElement, "::view-transition-old(one)").mixBlendMode, "normal"));
+
+ t.step(() => assert_equals(getComputedStyle(document.documentElement, "::view-transition-image-pair(two)").isolation, "auto"));
+ t.step(() => assert_equals(getComputedStyle(document.documentElement, "::view-transition-new(two)").mixBlendMode, "normal"));
+
+ t.step(() => assert_equals(getComputedStyle(document.documentElement, "::view-transition-image-pair(three)").isolation, "isolate"));
+ t.step(() => assert_equals(getComputedStyle(document.documentElement, "::view-transition-old(three)").mixBlendMode, "plus-lighter"));
+ t.step(() => assert_equals(getComputedStyle(document.documentElement, "::view-transition-new(three)").mixBlendMode, "plus-lighter"));
+
+ t.step(() => assert_equals(getComputedStyle(document.documentElement, "::view-transition-image-pair(four)").isolation, "isolate"));
+ t.step(() => assert_equals(getComputedStyle(document.documentElement, "::view-transition-old(four)").mixBlendMode, "normal"));
+ t.step(() => assert_equals(getComputedStyle(document.documentElement, "::view-transition-new(four)").mixBlendMode, "plus-lighter"));
+
+ t.step(() => assert_equals(getComputedStyle(document.documentElement, "::view-transition-image-pair(five)").isolation, "isolate"));
+ t.step(() => assert_equals(getComputedStyle(document.documentElement, "::view-transition-old(five)").mixBlendMode, "plus-lighter"));
+ t.step(() => assert_equals(getComputedStyle(document.documentElement, "::view-transition-new(five)").mixBlendMode, "normal"));
+ t.done();
+ });
+ });
+ });
+}, "Blend modes are set up on paired transitions");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/modify-style-via-cssom-ref.html b/testing/web-platform/tests/css/css-view-transitions/modify-style-via-cssom-ref.html
new file mode 100644
index 0000000000..dd93e0b498
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/modify-style-via-cssom-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>View transitions: Modify style via CSSOM (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+#box {
+ width: 100px;
+ height: 100px;
+ background: limegreen;
+}
+#box {
+ transform: translateY(100px);
+}
+
+</style>
+<div id="box"></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/modify-style-via-cssom.html b/testing/web-platform/tests/css/css-view-transitions/modify-style-via-cssom.html
new file mode 100644
index 0000000000..6f026607bc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/modify-style-via-cssom.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>View transitions: Modify style via CSSOM</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:bokan@chromium.org">
+<link rel="match" href="modify-style-via-cssom-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#box {
+ width: 100px;
+ height: 100px;
+ background: limegreen;
+}
+html::view-transition-group(root) {
+ animation-duration: 300s;
+}
+html::view-transition-new(root) {
+ animation: none;
+ opacity: 0;
+}
+html::view-transition-old(root) {
+ animation: none;
+ opacity: 1;
+}
+</style>
+<div id="box"></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function rAF() {
+ return new Promise(resolve => requestAnimationFrame(resolve));
+}
+
+async function runTest() {
+ await document.startViewTransition().ready;
+ await rAF();
+ await rAF();
+
+ // Once the animation is running, ensure modifying style via CSSOM is
+ // effective.
+ const cssSheet = new CSSStyleSheet();
+ cssSheet.replaceSync(`::view-transition-old(root) {
+ transform: translateY(100px);
+ }`);
+ document.adoptedStyleSheets = [cssSheet];
+
+ await rAF();
+ takeScreenshot();
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/multiline-span-with-overflowing-text-and-box-decorations-ref.html b/testing/web-platform/tests/css/css-view-transitions/multiline-span-with-overflowing-text-and-box-decorations-ref.html
new file mode 100644
index 0000000000..ca9efc52d6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/multiline-span-with-overflowing-text-and-box-decorations-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: span with overflowing text is rendered correctly (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<style>
+div {
+ width: 250px;
+ visibility: hidden;
+}
+span {
+ text-shadow: red -2px -5px;
+ border: 2px solid black;
+ box-shadow: 3px 3px red, -1em 0 .4em olive;
+ view-transition-name: target;
+ visibility: visible;
+}
+
+body {
+ background: pink;
+}
+</style>
+
+<div>
+ FILLER FILLER<span>This text should render correctly</span>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/multiline-span-with-overflowing-text-and-box-decorations.html b/testing/web-platform/tests/css/css-view-transitions/multiline-span-with-overflowing-text-and-box-decorations.html
new file mode 100644
index 0000000000..e166b3c9df
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/multiline-span-with-overflowing-text-and-box-decorations.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: span with overflowing text is rendered correctly</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="multiline-span-with-overflowing-text-and-box-decorations-ref.html">
+<meta name="fuzzy" content="multiline-span-with-overflowing-text-and-box-decorations-ref.html:maxDifference=0-3;totalPixels=0-4900">
+
+
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+<style>
+#wrapper {
+ width: 250px;
+ visibility: hidden;
+}
+span {
+ text-shadow: red -2px -5px;
+ border: 2px solid black;
+ box-shadow: 3px 3px red, -1em 0 .4em olive;
+ view-transition-name: target;
+ visibility: visible;
+}
+
+.hidden {
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+html::view-transition-group(root) { visibility: hidden; }
+
+html::view-transition-group(target) {
+ animation: unset;
+}
+
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 0;
+}
+
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+}
+
+html::view-transition {
+ background: pink;
+}
+</style>
+
+<div id="wrapper">
+ FILLER FILLER<span>This text should render correctly</span>
+</div>
+
+<div class="hidden"></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition();
+ transition.ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/named-element-with-fix-pos-child-new.html b/testing/web-platform/tests/css/css-view-transitions/named-element-with-fix-pos-child-new.html
new file mode 100644
index 0000000000..8a552b03a5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/named-element-with-fix-pos-child-new.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: element with fixed position descendant</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="named-element-with-fix-pos-child-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ view-transition-name: target;
+}
+.child {
+ width: 100px;
+ height: 100px;
+ position: fixed;
+ top: 150px;
+ left: 150px;
+ background: grey;
+}
+
+html::view-transition-group(target) { animation-duration: 300s; }
+html::view-transition-old(target) { animation: unset; opacity: 0; }
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+}
+</style>
+
+<div class=target>
+ <div class=child></div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/named-element-with-fix-pos-child-old.html b/testing/web-platform/tests/css/css-view-transitions/named-element-with-fix-pos-child-old.html
new file mode 100644
index 0000000000..a8211f4200
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/named-element-with-fix-pos-child-old.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: element with fixed position descendant</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="named-element-with-fix-pos-child-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ view-transition-name: target;
+}
+.child {
+ width: 100px;
+ height: 100px;
+ position: fixed;
+ top: 150px;
+ left: 150px;
+ background: grey;
+}
+
+html::view-transition-group(target) { animation-duration: 300s; }
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 1;
+}
+</style>
+
+<div class=target>
+ <div class=child></div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/named-element-with-fix-pos-child-ref.html b/testing/web-platform/tests/css/css-view-transitions/named-element-with-fix-pos-child-ref.html
new file mode 100644
index 0000000000..a161cd8fc9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/named-element-with-fix-pos-child-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: element with fixed position descendant (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+.target {
+ width: 100px;
+ height: 100px;
+ background: blue;
+}
+.child {
+ width: 100px;
+ height: 100px;
+ position: fixed;
+ top: 150px;
+ left: 150px;
+ background: grey;
+}
+</style>
+
+<div class=target>
+ <div class=child></div>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-and-old-sizes-match-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-and-old-sizes-match-ref.html
new file mode 100644
index 0000000000..b8c3b34c03
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-and-old-sizes-match-ref.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: capture elements with different size capture</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ overflow-clip-margin: 50px;
+}
+#target {
+ top: 20px;
+ left: 20px;
+ view-transition-name: target;
+}
+.inner_overflow {
+ width: 50px;
+ height: 150px;
+ margin-left: -10px;
+ margin-top: -20px;
+ background: lightgreen;
+ clip-path: inset(1px 1px 1px 1px);
+}
+
+/* We're verifying what we capture, so just display the new contents for 5 minutes. */
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 0; }
+html::view-transition-old(*) { animation: unset; opacity: 1; }
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+<div id=target class=box><div class=inner_overflow>X</div></div>
+<script>
+failIfNot(document.startViewTransition, "Reference missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-and-old-sizes-match.html b/testing/web-platform/tests/css/css-view-transitions/new-and-old-sizes-match.html
new file mode 100644
index 0000000000..78efa9d82f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-and-old-sizes-match.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: capture elements with different size capture</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-and-old-sizes-match-ref.html">
+<meta name="fuzzy" content="new-and-old-sizes-match-ref.html:0-1;0-300">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ overflow-clip-margin: 50px;
+}
+#target {
+ top: 20px;
+ left: 20px;
+ view-transition-name: target;
+}
+.inner_overflow {
+ width: 50px;
+ height: 150px;
+ margin-left: -10px;
+ margin-top: -20px;
+ background: lightgreen;
+ clip-path: inset(1px 1px 1px 1px);
+}
+
+/* We're verifying what we capture, so just display the new contents for 5 minutes. */
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 1; }
+html::view-transition-old(*) { animation: unset; opacity: 0; }
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+<div id=target class=box><div class=inner_overflow>X</div></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let t = document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-captures-clip-path-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-clip-path-ref.html
new file mode 100644
index 0000000000..1b28bbf29b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-clip-path-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>View transitions: capture opacity elements (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.box {
+ color: red;
+ background: lightgreen;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ font-size: 30pt;
+}
+#e1 {
+ clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
+ top: 20px;
+ left: 20px;
+}
+body { background: lightpink; }
+</style>
+<div id=e1 class=box></div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-captures-clip-path.html b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-clip-path.html
new file mode 100644
index 0000000000..4a2dfc78c2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-clip-path.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: capture clip-path elements</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-content-captures-clip-path-ref.html">
+<meta name="fuzzy" content="new-content-captures-clip-path-ref.html:0-1;0-500">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ color: red;
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ font-size: 30pt;
+}
+#e1 {
+ clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
+ top: 20px;
+ left: 20px;
+ view-transition-name: e1;
+}
+
+div.dst { background: lightgreen; }
+/* We're verifying what we capture, so just display the new contents for 5 minutes. */
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-image-pair(*) { isolation: isolate; }
+html::view-transition-new(*) { animation: unset; opacity: 1; }
+html::view-transition-old(*) { animation: unset; opacity: 0; }
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+<div id=e1 class=box></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let t = document.startViewTransition(() => {
+ e1.classList.add("dst");
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-captures-different-size-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-different-size-ref.html
new file mode 100644
index 0000000000..2a80cf5568
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-different-size-ref.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>View transitions: capture elements with different size capture (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.box {
+ color: red;
+ background: lightgreen;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ font-size: 30pt;
+}
+#e1 {
+ clip-path: circle(30%);
+ top: 20px;
+ left: 20px;
+}
+#e2 {
+ clip-path: ellipse(70% 30%);
+ top: 160px;
+ left: 20px;
+}
+#e3 {
+ filter: blur(5px);
+ top: 300px;
+ left: 20px;
+}
+
+body { background: lightpink; }
+</style>
+<div id=e1 class=box>one</div>
+<div id=e2 class=box>two</div>
+<div id=e3 class=box>three</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-captures-different-size.html b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-different-size.html
new file mode 100644
index 0000000000..a891dec555
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-different-size.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<html class=reftest-wait>
+<title>View transitions: capture elements with different size capture</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-content-captures-different-size-ref.html">
+<meta name=fuzzy content="new-content-captures-different-size-ref.html:0-40;0-30000">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ color: red;
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ font-size: 30pt;
+}
+#e1 {
+ clip-path: circle(30%);
+ top: 20px;
+ left: 20px;
+ view-transition-name: e1;
+}
+#e2 {
+ clip-path: ellipse(70% 30%);
+ top: 160px;
+ left: 20px;
+ view-transition-name: e2;
+}
+#e3 {
+ filter: blur(5px);
+ top: 300px;
+ left: 20px;
+ view-transition-name: e3;
+}
+
+div.dst { background: lightgreen; }
+/* We're verifying what we capture, so just display the new contents for 5 minutes. */
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 1; }
+html::view-transition-old(*) { animation: unset; opacity: 0; }
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+<div id=e1 class=box>one</div>
+<div id=e2 class=box>two</div>
+<div id=e3 class=box>three</div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let t = document.startViewTransition(() => {
+ e1.classList.add("dst");
+ e2.classList.add("dst");
+ e3.classList.add("dst");
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-captures-opacity-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-opacity-ref.html
new file mode 100644
index 0000000000..deea6d139b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-opacity-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>View transitions: capture opacity elements (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.box {
+ color: red;
+ background: lightgreen;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ font-size: 30pt;
+ will-change: opacity;
+}
+#e1 { opacity: 0.75; top: 20px; left: 20px; }
+#e2 { opacity: 0.5; top: 160px; left: 20px; }
+#e3 { opacity: 0.25; top: 300px; left: 20px; }
+body { background: lightpink; }
+</style>
+<div id=e1 class=box></div>
+<div id=e2 class=box></div>
+<div id=e3 class=box></div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-captures-opacity.html b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-opacity.html
new file mode 100644
index 0000000000..ab4efd1f42
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-opacity.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: capture opacity elements</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-content-captures-opacity-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ color: red;
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ font-size: 30pt;
+ will-change: opacity;
+}
+#e1 { opacity: 0.75; top: 20px; left: 20px; view-transition-name: e1; }
+#e2 { opacity: 0.5; top: 160px; left: 20px; view-transition-name: e2; }
+#e3 { opacity: 0.25; top: 300px; left: 20px; view-transition-name: e3; }
+div.dst { background: lightgreen; }
+/* We're verifying what we capture, so just display the new contents for 5 minutes. */
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 1; }
+html::view-transition-old(*) { animation: unset; opacity: 0; }
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+<div id=e1 class=box></div>
+<div id=e2 class=box></div>
+<div id=e3 class=box></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let t = document.startViewTransition(() => {
+ e1.classList.add("dst");
+ e2.classList.add("dst");
+ e3.classList.add("dst");
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-captures-positioned-spans-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-positioned-spans-ref.html
new file mode 100644
index 0000000000..6d906fc6f1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-positioned-spans-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>View transitions: capture opacity elements (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+span {
+ background: lightgreen;
+ position: fixed;
+ top: 50px;
+ left: 50px;
+}
+body { background: lightpink; }
+</style>
+<span>This is a span</span>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-captures-positioned-spans.html b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-positioned-spans.html
new file mode 100644
index 0000000000..b88654cd37
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-positioned-spans.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: capture span elements</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-content-captures-positioned-spans-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+span {
+ background: lightblue;
+ view-transition-name: span;
+ position: fixed;
+ top: 50px;
+ left: 50px;
+}
+span.dst { background: lightgreen; }
+/* We're verifying what we capture, so just display the new contents for 5 minutes. */
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 1; }
+html::view-transition-old(*) { animation: unset; opacity: 0; }
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+<span id=target>This is a span</span>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let t = document.startViewTransition(() => {
+ target.classList.add("dst");
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-captures-root-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-root-ref.html
new file mode 100644
index 0000000000..2f2e5e7694
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-root-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title>View transitions: capture opacity elements (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.box {
+ background: lightgreen;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ will-change: transform;
+}
+#e1 {
+ top: 10px;
+ left: 30px;
+}
+</style>
+<div id=e1 class=box></div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-captures-root.html b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-root.html
new file mode 100644
index 0000000000..84e55de58a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-root.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: capture root elements</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-content-captures-root-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ will-change: transform;
+}
+#e1 {
+ top: 10px;
+ left: 30px;
+}
+#shared {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ background: red;
+ view-transition-name: shared;
+}
+
+div.dst { background: lightgreen; }
+/* We're verifying what we capture, so just display the old contents for 5 minutes. */
+html::view-transition { background: pink; }
+html::view-transition-group(shared) { animation-duration: 300s; }
+html::view-transition-image-pair(shared) { visibility: hidden }
+html::view-transition-old(root) { animation-duration: 0s; opacity: 0 }
+html::view-transition-new(root) { animation-duration: 0s; opacity: 1 }
+</style>
+<body style="background: red">
+<div id=e1 class=box></div>
+<div id=shared></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let t = document.startViewTransition(() => {
+ e1.classList.add("dst");
+ document.body.style = "";
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
+</body>
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-captures-spans-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-spans-ref.html
new file mode 100644
index 0000000000..b95233d712
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-spans-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title>View transitions: capture opacity elements (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+span {
+ background: lightgreen;
+ view-transition-name: span;
+}
+body { background: lightpink; }
+</style>
+<span>This is a span</span>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-captures-spans.html b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-spans.html
new file mode 100644
index 0000000000..843f6752d7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-captures-spans.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: capture span elements</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-content-captures-spans-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+span {
+ background: lightblue;
+ view-transition-name: span;
+}
+span.dst { background: lightgreen; }
+/* We're verifying what we capture, so just display the new contents for 5 minutes. */
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 1; }
+html::view-transition-old(*) { animation: unset; opacity: 0; }
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+<span id=target>This is a span</span>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let t = document.startViewTransition(() => {
+ target.classList.add("dst");
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-changes-overflow-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-changes-overflow-ref.html
new file mode 100644
index 0000000000..5f75909e82
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-changes-overflow-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>View transitions: capture elements and then change overflow (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+body { background: pink }
+#target {
+ position: relative;
+ background: green;
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+}
+#child {
+ background: blue;
+ position: relative;
+ top: 20px;
+ left: 30px;
+ width: 50px;
+ height: 100px;
+}
+#child.large {
+ height: 200px;
+}
+</style>
+
+<div id=target><div id=child class=large></div></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-changes-overflow.html b/testing/web-platform/tests/css/css-view-transitions/new-content-changes-overflow.html
new file mode 100644
index 0000000000..a8e2fa8c6b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-changes-overflow.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<html class=reftest-wait>
+<title>View transitions: capture elements and then change overflow</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-content-changes-overflow-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#target {
+ position: relative;
+ background: green;
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+}
+#child {
+ background: blue;
+ position: relative;
+ top: 20px;
+ left: 30px;
+ width: 50px;
+ height: 100px;
+}
+#child.large {
+ height: 200px;
+}
+
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 1; }
+html::view-transition-old(*) { animation: unset; opacity: 0; }
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: pink; }
+</style>
+
+<div id=target><div id=child></div></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition().ready.then(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ child.classList.add("large");
+ requestAnimationFrame(takeScreenshot);
+ });
+ });
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-container-writing-modes-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-container-writing-modes-ref.html
new file mode 100644
index 0000000000..34e36786f8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-container-writing-modes-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>View transitions: container of shared element writing-modes (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+.tb { writing-mode: horizontal-tb; }
+.lr { writing-mode: vertical-lr; }
+.rl { writing-mode: vertical-rl; }
+.shared {
+ margin: 2px;
+ width: 100px;
+ height: 50px;
+ background: green;
+ contain: paint;
+ border: 1px solid black;
+}
+html { background: lightpink; }
+</style>
+
+<div class=tb><div id=one class=shared>T</div></div>
+<div class=lr><div id=two class=shared>T</div></div>
+<div class=rl><div id=three class=shared>T</div></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-container-writing-modes.html b/testing/web-platform/tests/css/css-view-transitions/new-content-container-writing-modes.html
new file mode 100644
index 0000000000..e7ac768e17
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-container-writing-modes.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: container of shared element writing-modes</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-content-container-writing-modes-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#hidden {
+ width: 100px;
+ height: 100px;
+ background: red;
+ position: absolute;
+ top: 0;
+ left: 0;
+ contain: paint;
+ view-transition-name: hidden;
+}
+.tb { writing-mode: horizontal-tb; }
+.lr { writing-mode: vertical-lr; }
+.rl { writing-mode: vertical-rl; }
+.shared {
+ margin: 2px;
+ width: 100px;
+ height: 50px;
+ background: green;
+ contain: paint;
+ border: 1px solid black;
+}
+.source {
+ background: red;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+ width: 100px;
+ height: 500px;
+ contain: paint;
+}
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(s1),
+html::view-transition-group(s2),
+html::view-transition-group(s3) { animation-duration: 0s; }
+
+html::view-transition-new(s1),
+html::view-transition-new(s2),
+html::view-transition-new(s3) { animation: unset; opacity: 1; }
+
+html::view-transition-old(s1),
+html::view-transition-old(s2),
+html::view-transition-old(s3) { animation: unset; opacity: 0; }
+
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+
+</style>
+
+<div id=hidden>Should not be visible</div>
+<div id=s1 class=source>Should not be visible</div>
+<div id=s2 class=source>Should not be visible</div>
+<div id=s3 class=source>Should not be visible</div>
+<div class=tb><div id=one class=shared>T</div></div>
+<div class=lr><div id=two class=shared>T</div></div>
+<div class=rl><div id=three class=shared>T</div></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ s1.style = "view-transition-name: s1";
+ s2.style = "view-transition-name: s2";
+ s3.style = "view-transition-name: s3";
+ document.startViewTransition(() => {
+ s1.remove();
+ s2.remove();
+ s3.remove();
+ hidden.style.left = "200px";
+ one.style = "view-transition-name: s1";
+ two.style = "view-transition-name: s2";
+ three.style = "view-transition-name: s3";
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-element-writing-modes-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-element-writing-modes-ref.html
new file mode 100644
index 0000000000..94280ae3af
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-element-writing-modes-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>View transitions: shared element writing-modes (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+.tb { writing-mode: horizontal-tb; }
+.lr { writing-mode: vertical-lr; }
+.rl { writing-mode: vertical-rl; }
+.shared {
+ margin: 2px;
+ width: 100px;
+ height: 50px;
+ background: green;
+ contain: paint;
+ border: 1px solid black;
+}
+html { background: lightpink; }
+</style>
+
+<div id=one class="tb shared">T</div>
+<div id=two class="lr shared">T</div>
+<div id=three class="rl shared">T</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-element-writing-modes.html b/testing/web-platform/tests/css/css-view-transitions/new-content-element-writing-modes.html
new file mode 100644
index 0000000000..d7740d78f5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-element-writing-modes.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: shared element writing-modes</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-content-element-writing-modes-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#hidden {
+ width: 100px;
+ height: 100px;
+ background: red;
+ position: absolute;
+ top: 0;
+ left: 0;
+ contain: paint;
+ view-transition-name: hidden;
+}
+.tb { writing-mode: horizontal-tb; }
+.lr { writing-mode: vertical-lr; }
+.rl { writing-mode: vertical-rl; }
+.shared {
+ margin: 2px;
+ width: 100px;
+ height: 50px;
+ background: green;
+ contain: paint;
+ border: 1px solid black;
+}
+#target {
+ background: red;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+ width: 100px;
+ height: 500px;
+ contain: paint;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(s1),
+html::view-transition-group(s2),
+html::view-transition-group(s3) { animation-duration: 0s; }
+
+html::view-transition-new(s1),
+html::view-transition-new(s2),
+html::view-transition-new(s3) { animation: unset; opacity: 1; }
+
+html::view-transition-old(s1),
+html::view-transition-old(s2),
+html::view-transition-old(s3) { animation: unset; opacity: 0; }
+
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+
+</style>
+
+<div id=hidden>Should not be visible</div>
+<div id=s1 class=source>Should not be visible</div>
+<div id=s2 class=source>Should not be visible</div>
+<div id=s3 class=source>Should not be visible</div>
+<div id=one class="tb shared">T</div>
+<div id=two class="lr shared">T</div>
+<div id=three class="rl shared">T</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ s1.style = "view-transition-name: s1";
+ s2.style = "view-transition-name: s2";
+ s3.style = "view-transition-name: s3";
+ document.startViewTransition(() => {
+ s1.remove();
+ s2.remove();
+ s3.remove();
+ hidden.style.left = "200px";
+ one.style = "view-transition-name: s1";
+ two.style = "view-transition-name: s2";
+ three.style = "view-transition-name: s3";
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-from-root-display-none-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-from-root-display-none-ref.html
new file mode 100644
index 0000000000..e936a779c7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-from-root-display-none-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: capture starts with root being display none (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.tb { writing-mode: horizontal-tb; }
+.lr { writing-mode: vertical-lr; }
+.rl { writing-mode: vertical-rl; }
+.shared {
+ margin: 2px;
+ width: 100px;
+ height: 50px;
+ background: green;
+ contain: paint;
+ border: 1px solid black;
+}
+</style>
+
+<div class=tb><div id=one class=shared>T</div></div>
+<div class=lr><div id=two class=shared>T</div></div>
+<div class=rl><div id=three class=shared>T</div></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-from-root-display-none.html b/testing/web-platform/tests/css/css-view-transitions/new-content-from-root-display-none.html
new file mode 100644
index 0000000000..4d2ad28b17
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-from-root-display-none.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html class=reftest-wait style="display: none">
+<title>View transitions: capture starts with root being display none</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-content-from-root-display-none-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.tb { writing-mode: horizontal-tb; }
+.lr { writing-mode: vertical-lr; }
+.rl { writing-mode: vertical-rl; }
+.shared {
+ margin: 2px;
+ width: 100px;
+ height: 50px;
+ background: green;
+ contain: paint;
+ border: 1px solid black;
+}
+
+html::view-transition-group(root) { animation-duration: 500s; }
+html::view-transition-new(root) {
+ animation: unset;
+ opacity: 1;
+}
+html::view-transition-old(root) {
+ animation: unset;
+ opacity: 0;
+}
+
+</style>
+
+<div class=tb><div id=one class=shared>T</div></div>
+<div class=lr><div id=two class=shared>T</div></div>
+<div class=rl><div id=three class=shared>T</div></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition(() => {
+ document.documentElement.style = "";
+ });
+ transition.ready.then(() => requestAnimationFrame(takeScreenshot));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-has-scrollbars-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-has-scrollbars-ref.html
new file mode 100644
index 0000000000..eddd733014
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-has-scrollbars-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>View transitions: incoming viewport has scrollbars (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7859">
+<link rel="author" href="mailto:bokan@chromium.org">
+<style>
+ html, body {
+ width: 100%;
+ height: 100%;
+ background-color: lightpink;
+ }
+ body {
+ margin: 50px;
+ }
+ div {
+ background-image:
+ linear-gradient(45deg, #000 25%, transparent 25%),
+ linear-gradient(45deg, transparent 75%, #000 75%),
+ linear-gradient(45deg, transparent 75%, #000 75%),
+ linear-gradient(45deg, #000 25%, lightgreen 25%);
+ background-size: 200px 200px;
+ background-position: 0 0, 0 0, -100px -100px, 100px 100px;
+ width: 200%;
+ height: 200%;
+ }
+</style>
+<div></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-has-scrollbars.html b/testing/web-platform/tests/css/css-view-transitions/new-content-has-scrollbars.html
new file mode 100644
index 0000000000..4024952b13
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-has-scrollbars.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<html class=reftest-wait>
+<title>View transitions: incoming viewport has scrollbars</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7859">
+<link rel="author" href="mailto:bokan@chromium.org">
+<link rel="match" href="new-content-has-scrollbars-ref.html">
+<meta name=fuzzy content="new-content-has-scrollbars-ref.html:0-40;0-30000">
+<script src="/common/reftest-wait.js"></script>
+<style>
+ html, body {
+ width: 100%;
+ height: 100%;
+ background-color: lightpink;
+ }
+ html {
+ overflow: hidden;
+ }
+ body {
+ /* Margin to make sure background color is correctly drawn into the snapshot. */
+ margin: 50px;
+ }
+ div {
+ /* Draw a checkerboard pattern to make sure the snapshot is captured at the
+ * full size, rather than scaled. */
+ background-image:
+ linear-gradient(45deg, #000 25%, transparent 25%),
+ linear-gradient(45deg, transparent 75%, #000 75%),
+ linear-gradient(45deg, transparent 75%, #000 75%),
+ linear-gradient(45deg, #000 25%, lightgreen 25%);
+ background-size: 200px 200px;
+ background-position: 0 0, 0 0, -100px -100px, 100px 100px;
+ width: 200%;
+ height: 200%;
+ }
+
+ /* We're verifying what we capture, so just display the old contents for 5 minutes. */
+ html::view-transition-new(root) { animation: unset; opacity: 0; }
+ html::view-transition-old(root) {
+ animation-duration: 300s;
+ animation-timing-function: steps(1, end);
+ opacity: 1;
+ }
+</style>
+
+<div></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+// Ensure a root snapshot captured in the absence of scrollbars is displayed at
+// full size when rendered in the incoming viewport which is inset by
+// scrollbars. The content must not be scaled-to-fit.
+async function runTest() {
+ document.startViewTransition(() => {
+ document.documentElement.style.overflow = "unset";
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-intrinsic-aspect-ratio.html b/testing/web-platform/tests/css/css-view-transitions/new-content-intrinsic-aspect-ratio.html
new file mode 100644
index 0000000000..53ec94122f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-intrinsic-aspect-ratio.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: different width container should keep aspect ratio (by default)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="intrinsic-aspect-ratio-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.spacer {
+ height: 10px;
+}
+.box {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ background: blue;
+}
+#target1 {
+ view-transition-name: target1;
+}
+#target2 {
+ view-transition-name: target2;
+}
+#hidden {
+ view-transition-name: hidden;
+ width: 10px;
+ height: 10px;
+ visibility: hidden;
+ contain: paint;
+}
+
+/* We're verifying what we capture, so just display the new contents for 5 minutes. */
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 1; }
+html::view-transition-old(*) { animation: unset; opacity: 0; }
+
+html::view-transition-group(target1) {
+ animation: unset;
+ width: 50px;
+ border: 2px solid black;
+}
+html::view-transition-group(target2) {
+ animation: unset;
+ width: 200px;
+ border: 2px solid black;
+}
+
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div id=target1 class=box></div>
+<div class=spacer></div>
+<div id=target2 class=box></div>
+<div id=hidden></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-is-empty-div-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-is-empty-div-ref.html
new file mode 100644
index 0000000000..c85028d3bd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-is-empty-div-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>View transitions: new content captures an empty div (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ top: 50px;
+ left: 200px;
+ background: green;
+}
+body { background: lightpink; }
+</style>
+<div></div>
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-is-empty-div.html b/testing/web-platform/tests/css/css-view-transitions/new-content-is-empty-div.html
new file mode 100644
index 0000000000..bacc63f194
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-is-empty-div.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: old content captures an empty div</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-content-is-empty-div-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+div {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ top: 50px;
+}
+#source {
+ left: 50px;
+ background: green;
+}
+#target {
+ left: 200px;
+}
+#hidden {
+ background: red;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+/* The effect of the following should be position at the incoming element
+ but contents of the new element.
+*/
+html::view-transition-group(shared) { animation-duration: 0s; }
+html::view-transition-new(shared) { animation: unset; opacity: 1; }
+html::view-transition-old(shared) { animation: unset; opacity: 1; }
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+
+</style>
+
+<div id=source></div>
+<div id=target></div>
+<div id=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ source.style = "view-transition-name: shared";
+ document.startViewTransition(() => {
+ source.style = "";
+ target.style = "view-transition-name: shared";
+
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-is-inline-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-is-inline-ref.html
new file mode 100644
index 0000000000..c75cfcc252
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-is-inline-ref.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<title>View transitions: New content is an inline element (ref)</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:bokan@chromium.org">
+
+<style>
+:root { background-color: rebeccapurple; }
+body { margin: 0; }
+
+.container {
+ position: absolute;
+ left: 100px;
+ width: 400px;
+ height: 100px;
+ background-color: grey;
+}
+
+.container.start {
+ top: 100px;
+}
+
+.container.end {
+ top: 300px;
+}
+
+.container.transitioned {
+ left: 20px;
+ width: 600px;
+ transform: translateY(-50px);
+}
+
+.inline {
+ opacity: 0;
+ background-color: coral;
+ color: rgba(0, 0, 0, 0);
+}
+
+.transitioned .inline {
+ opacity: 1;
+}
+
+#dummyStartInline {
+ position: absolute;
+ left: 100px;
+ top: 100px;
+ width: 600px;
+ /* scale transform applied in script below */
+ transform-origin: top left;
+}
+
+</style>
+
+<div class="container start">
+ <span>FILLER FILLER</span>
+ <span id="start" class="inline">INLINE INLINE INLINE INLINE</span>
+ <p style="margin-top: 50px">START STATE</p>
+</div>
+
+<div class="container end transitioned">
+ <span>FILLER FILLER</span>
+ <span id="end" class="inline">INLINE INLINE INLINE INLINE</span>
+ <p>END STATE</p>
+</div>
+
+<div id="dummyStartInline" class="transitioned">
+ <span style="opacity:0">FILLER FILLER</span>
+ <span class="inline">INLINE INLINE INLINE INLINE</span>
+</div>
+<script>
+ let endWidth = document.getElementById('end').getBoundingClientRect().width;
+ let startWidth = document.getElementById('start').getBoundingClientRect().width;
+ let scale = startWidth / endWidth;
+ /* Default UA CSS scales the image pseudos to match the group in the inline
+ direction. The block direction scales to retain the image's aspect ratio.
+ So have the dummy end line scale to match the start state width and apply
+ the same scale to its height. */
+ document.getElementById('dummyStartInline').style.transform = `scale(${scale})`;
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-is-inline.html b/testing/web-platform/tests/css/css-view-transitions/new-content-is-inline.html
new file mode 100644
index 0000000000..46c96acb04
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-is-inline.html
@@ -0,0 +1,148 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: New content is an inline element.</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:bokan@chromium.org">
+<link rel="match" href="new-content-is-inline-ref.html">
+<meta name="fuzzy" content="new-content-is-inline-ref.html:0-255;0-1000">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+body { margin : 0; }
+.container {
+ position: absolute;
+ left: 100px;
+ width: 400px;
+ height: 100px;
+ background-color: grey;
+}
+
+.container.start {
+ top: 100px;
+ view-transition-name: container-start;
+}
+
+.container.end {
+ top: 300px;
+ view-transition-name: container-end;
+}
+
+.transitioned .container {
+ left: 20px;
+ width: 600px;
+ transform: translateY(-50px);
+}
+
+.inline {
+ background-color: limegreen;
+ /* allow small pixel diff in text */
+ color: rgba(0, 0, 0, 0);
+}
+
+.start .inline {
+ view-transition-name: start;
+}
+
+.end .inline {
+ view-transition-name: end;
+}
+
+.transitioned .inline {
+ background-color: coral;
+}
+
+/* Overlay the page with purple to ensure screenshots taken are of the view
+ * transition. */
+:root {
+ view-transition-name: none;
+}
+::view-transition {
+ background-color: rebeccapurple;
+}
+
+/* This step function keeps the old snapshots in their initial state for half
+ * the duration, then the new snapshots in their final state for the last half
+ * of the duration. */
+html::view-transition-group(*),
+html::view-transition-new(*),
+html::view-transition-old(*) {
+ animation-timing-function: steps(2, jump-none);
+}
+
+/* Set different durations for start and end so the two subtrees can be
+ * differentiated. The test will manually control animation playback so
+ * duration doesn't matter. */
+html::view-transition-group(container-start),
+html::view-transition-group(start),
+html::view-transition-new(container-start),
+html::view-transition-old(container-start) {
+ animation-duration: 2s;
+}
+html::view-transition-group(container-end),
+html::view-transition-group(end),
+html::view-transition-new(container-end),
+html::view-transition-old(container-end) {
+ animation-duration: 3s;
+}
+
+/* Hide the old states for the inlines, they're tested in
+ * old-content-is-inline.html */
+html::view-transition-old(start),
+html::view-transition-old(end) {
+ animation: unset;
+ opacity: 0;
+}
+html::view-transition-new(start),
+html::view-transition-new(end) {
+ animation: unset;
+ opacity: 1;
+}
+
+</style>
+
+<!--
+This subtree will be held at the animation start to test the old content's
+starting position.
+-->
+<div class="container start">
+ <span>FILLER FILLER</span>
+ <span id="start" class="inline">INLINE INLINE INLINE INLINE</span>
+ <p style="margin-top: 50px">START STATE</p>
+</div>
+
+<!--
+This subtree will be held at the animation end to test the old content's
+ending position.
+-->
+<div class="container end">
+ <span>FILLER FILLER</span>
+ <span id="end" class="inline">INLINE INLINE INLINE INLINE</span>
+ <p>END STATE</p>
+</div>
+
+<script>
+if (typeof failIfNot != 'undefined')
+ failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition(() => {
+ document.body.classList.add('transitioned');
+ });
+
+ transition.ready.then(() => {
+ for (const anim of document.getAnimations()) {
+ anim.pause();
+ if (anim.effect.getTiming().duration == 3000) {
+ // This is an animation for the end subtree. Adjust it to the end
+ // (without finishing the animation) so we're displaying the final
+ // position.
+ anim.currentTime = anim.effect.getTiming().duration - 1;
+ }
+ }
+
+ requestAnimationFrame(takeScreenshot);
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-object-fit-fill.html b/testing/web-platform/tests/css/css-view-transitions/new-content-object-fit-fill.html
new file mode 100644
index 0000000000..b891eee16d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-object-fit-fill.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: display content in a pseudo with object-fit: fill</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="content-object-fit-fill-ref.html">
+<meta name="fuzzy" content="content-object-fit-fill-ref.html:0-60;0-20">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ view-transition-name: target;
+ background: lightblue;
+}
+#inner {
+ width: 10px;
+ height: 10px;
+ background: green;
+ top: 5px;
+ left: 10px;
+}
+#hidden {
+ background: pink;
+ width: 10px;
+ height: 10px;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(target) {
+ animation: unset;
+ transform: unset;
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ width: 50px;
+ height: 50px;
+}
+
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+ object-fit: fill;
+}
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 0;
+}
+
+html::view-transition-group(hidden) {
+ animation-duration: 500s;
+ visibility: hidden;
+}
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div id=target><div id=inner></div></div>
+<div id=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-object-fit-none.html b/testing/web-platform/tests/css/css-view-transitions/new-content-object-fit-none.html
new file mode 100644
index 0000000000..d4b81b1a0e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-object-fit-none.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: display content in a pseudo with object-fit: none</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="content-object-fit-none-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ view-transition-name: target;
+ background: lightblue;
+}
+#hidden {
+ background: pink;
+ width: 10px;
+ height: 10px;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(target) {
+ animation: unset;
+ transform: unset;
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ width: 50px;
+ height: 50px;
+}
+
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+ object-fit: none;
+ object-position: 0% 0%;
+}
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 0;
+}
+
+html::view-transition-group(hidden) {
+ animation-duration: 500s;
+ visibility: hidden;
+}
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div id=target>This is text</div>
+<div id=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-clip-path-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-clip-path-ref.html
new file mode 100644
index 0000000000..28e22b8ca2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-clip-path-ref.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<title>View transitions: object-view-box with larger overflow (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.target {
+ color: red;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: relative;
+ top: 50px;
+ left: 50px;
+}
+.child {
+ width: 123px;
+ height: 150px;
+ background: lightblue;
+ position: relative;
+ top: -10px;
+ left: -20px;
+}
+.grandchild {
+ width: 25px;
+ height: 25px;
+ position: relative;
+ top: 20px;
+ left: 40px;
+ background: green;
+}
+#one { clip-path: inset(10px 12px 20px 28px); }
+#two { clip-path: inset(10px -12px 20px -28px); }
+body { background: lightpink; }
+</style>
+
+<div id=one class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+<div style="height: 20px;"></div>
+<div id=two class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-clip-path-reference-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-clip-path-reference-ref.html
new file mode 100644
index 0000000000..b1871141c2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-clip-path-reference-ref.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<title>View transitions: object-view-box with larger overflow (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.target {
+ color: red;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: relative;
+ top: 50px;
+ left: 50px;
+}
+.child {
+ width: 123px;
+ height: 150px;
+ background: lightblue;
+ position: relative;
+ top: -10px;
+ left: -20px;
+}
+.grandchild {
+ width: 25px;
+ height: 25px;
+ position: relative;
+ top: 20px;
+ left: 40px;
+ background: green;
+}
+#one { clip-path: url(#clip1); }
+#two { clip-path: url(#clip2); }
+body { background: lightpink; }
+</style>
+
+<div id=one class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+<div style="height: 20px;"></div>
+<div id=two class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+
+<svg>
+ <defs>
+ <clipPath id="clip1">
+ <rect x="10" y="20" width="70" height="50" />
+ </clipPath>
+ <clipPath id="clip2">
+ <rect x="-10" y="20" width="130" height="50" />
+ </clipPath>
+ </defs>
+</svg>
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-clip-path-reference.html b/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-clip-path-reference.html
new file mode 100644
index 0000000000..01a3ed3204
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-clip-path-reference.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: object-view-box with larger clip-path</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-content-object-view-box-clip-path-reference-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ color: red;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ overflow-clip-margin: 1000px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+}
+.child {
+ width: 123px;
+ height: 150px;
+ background: lightblue;
+ position: relative;
+ top: -10px;
+ left: -20px;
+}
+.grandchild {
+ width: 25px;
+ height: 25px;
+ position: relative;
+ top: 20px;
+ left: 40px;
+ background: green;
+}
+#one {
+ view-transition-name: target-one;
+ clip-path: url(#clip1);
+}
+#two {
+ view-transition-name: target-two;
+ clip-path: url(#clip2);
+}
+
+html::view-transition-group(target-one),
+html::view-transition-group(target-two) { animation-duration: 300s; }
+html::view-transition-old(target-one),
+html::view-transition-old(target-two) { animation: unset; opacity: 0; height: 100%; }
+html::view-transition-new(target-one),
+html::view-transition-new(target-two) {
+ animation: unset;
+ opacity: 1;
+ /* clip overflow, and verify inner contents only */
+ overflow: hidden;
+ height: 100%;
+}
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div id=one class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+<div style="height: 20px;"></div>
+<div id=two class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+
+<svg>
+ <defs>
+ <clipPath id="clip1">
+ <rect x="10" y="20" width="70" height="50" />
+ </clipPath>
+ <clipPath id="clip2">
+ <rect x="-10" y="20" width="130" height="50" />
+ </clipPath>
+ </defs>
+</svg>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-clip-path.html b/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-clip-path.html
new file mode 100644
index 0000000000..dcd5fec70a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-clip-path.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: object-view-box with larger clip-path</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-content-object-view-box-clip-path-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ color: red;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ overflow-clip-margin: 1000px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+}
+.child {
+ width: 123px;
+ height: 150px;
+ background: lightblue;
+ position: relative;
+ top: -10px;
+ left: -20px;
+}
+.grandchild {
+ width: 25px;
+ height: 25px;
+ position: relative;
+ top: 20px;
+ left: 40px;
+ background: green;
+}
+#one {
+ view-transition-name: target-one;
+ clip-path: inset(10px 12px 20px 28px);
+}
+#two {
+ view-transition-name: target-two;
+ clip-path: inset(10px -12px 20px -28px);
+}
+
+html::view-transition-group(target-one),
+html::view-transition-group(target-two) { animation-duration: 300s; }
+html::view-transition-old(target-one),
+html::view-transition-old(target-two) { animation: unset; opacity: 0; height: 100%; }
+html::view-transition-new(target-one),
+html::view-transition-new(target-two) {
+ animation: unset;
+ opacity: 1;
+ /* clip overflow, and verify inner contents only */
+ overflow: hidden;
+ height: 100%;
+}
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div id=one class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+<div style="height: 20px;"></div>
+<div id=two class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-overflow-clipped-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-overflow-clipped-ref.html
new file mode 100644
index 0000000000..d6016c950e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-overflow-clipped-ref.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>View transitions: object-view-box with larger overflow (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.target {
+ color: red;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: relative;
+ top: 50px;
+ left: 50px;
+}
+.child {
+ width: 123px;
+ height: 150px;
+ background: lightblue;
+ position: relative;
+ top: -10px;
+ left: -20px;
+}
+.grandchild {
+ width: 25px;
+ height: 25px;
+ position: relative;
+ top: 20px;
+ left: 40px;
+ background: green;
+}
+body { background: lightpink; }
+</style>
+
+<div class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-overflow-clipped.html b/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-overflow-clipped.html
new file mode 100644
index 0000000000..593901529f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-overflow-clipped.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: object-view-box with larger overflow</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-content-object-view-box-overflow-clipped-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ color: red;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ overflow-clip-margin: 10px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+ view-transition-name: target;
+}
+.child {
+ width: 123px;
+ height: 150px;
+ background: lightblue;
+ position: relative;
+ top: -10px;
+ left: -20px;
+}
+.grandchild {
+ width: 25px;
+ height: 25px;
+ position: relative;
+ top: 20px;
+ left: 40px;
+ background: green;
+}
+
+html::view-transition-group(target) { animation-duration: 300s; }
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+
+ /* clip overflow, and verify inner contents only */
+ overflow: hidden;
+ height: 100%;
+}
+html::view-transition-old(target) { animation: unset; opacity: 0; height: 100%; }
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-overflow-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-overflow-ref.html
new file mode 100644
index 0000000000..d6016c950e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-overflow-ref.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>View transitions: object-view-box with larger overflow (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.target {
+ color: red;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: relative;
+ top: 50px;
+ left: 50px;
+}
+.child {
+ width: 123px;
+ height: 150px;
+ background: lightblue;
+ position: relative;
+ top: -10px;
+ left: -20px;
+}
+.grandchild {
+ width: 25px;
+ height: 25px;
+ position: relative;
+ top: 20px;
+ left: 40px;
+ background: green;
+}
+body { background: lightpink; }
+</style>
+
+<div class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-overflow.html b/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-overflow.html
new file mode 100644
index 0000000000..2bbea1e1c4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-object-view-box-overflow.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: object-view-box with larger overflow</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-content-object-view-box-overflow-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ color: red;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ overflow-clip-margin: 1000px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+ view-transition-name: target;
+}
+.child {
+ width: 123px;
+ height: 150px;
+ background: lightblue;
+ position: relative;
+ top: -10px;
+ left: -20px;
+}
+.grandchild {
+ width: 25px;
+ height: 25px;
+ position: relative;
+ top: 20px;
+ left: 40px;
+ background: green;
+}
+
+html::view-transition-group(target) { animation-duration: 300s; }
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+
+ /* clip overflow, and verify inner contents only */
+ overflow: hidden;
+ height: 100%;
+}
+html::view-transition-old(target) { animation: unset; opacity: 0; height: 100%; }
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-scaling-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-content-scaling-ref.html
new file mode 100644
index 0000000000..1ca35f5a42
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-scaling-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<title>View transitions: display content in a pseudo with proper scaling (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.inner {
+ position: absolute;
+ inset: 4px;
+ background: green;
+}
+.dst {
+ position: relative;
+ width: 100px;
+ height: 100px;
+ border: 1px solid blue;
+ box-sizing: border-box;
+}
+body { background: lightpink; }
+</style>
+
+<div class=dst><div class=inner></div></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-scaling.html b/testing/web-platform/tests/css/css-view-transitions/new-content-scaling.html
new file mode 100644
index 0000000000..4ea3c2e04a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-scaling.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: display content in a pseudo with proper scaling</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-content-scaling-ref.html">
+<meta name="fuzzy" content="new-content-scaling-ref.html:maxDifference=0-16;totalPixels=0-400">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.shared {
+ view-transition-name: shared;
+ contain: paint;
+}
+.src {
+ position: relative;
+ width: 100px;
+ height: 100px;
+}
+.inner {
+ position: absolute;
+ inset: 20px;
+ background: green;
+}
+.dst {
+ position: relative;
+ width: 500px;
+ height: 500px;
+ border: 5px solid blue;
+ box-sizing: border-box;
+}
+
+html::view-transition-group(shared) {
+ animation-delay: 500s;
+}
+
+html::view-transition-new(shared) {
+ animation: unset;
+ opacity: 1;
+}
+html::view-transition-old(shared) {
+ animation: unset;
+ opacity: 0;
+}
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div id=target class="shared src"><div class=inner></div></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let t = document.startViewTransition(() => {
+ target.classList.remove("src");
+ target.classList.add("dst");
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-with-object-view-box.html b/testing/web-platform/tests/css/css-view-transitions/new-content-with-object-view-box.html
new file mode 100644
index 0000000000..47917e90f3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-with-object-view-box.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<html class=reftest-wait>
+<title>View transitions: capture elements with object view box on the pseudo</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="content-with-object-view-box-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#target {
+ position: relative;
+ top: 100px;
+ left: 100px;
+ background: green;
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+}
+
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) {
+ object-view-box: inset(5px 10px 15px 20px);
+ /* Set explicit width height so that we can check the object view box math */
+ width: 100px;
+ height: 100px;
+ animation: unset;
+ opacity: 1;
+}
+html::view-transition-old(*) { animation: unset; opacity: 0; }
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: pink; }
+</style>
+<div id=target></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition().ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-with-overflow-zoomed.html b/testing/web-platform/tests/css/css-view-transitions/new-content-with-overflow-zoomed.html
new file mode 100644
index 0000000000..59170ebf00
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-with-overflow-zoomed.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: shared element with overflow</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="content-with-overflow-zoomed-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ width: 80px;
+ height: 80px;
+ contain: paint;
+ background: blue;
+ overflow-clip-margin: 50px;
+ view-transition-name: target;
+ zoom: 1.5;
+}
+.child {
+ width: 200px;
+ height: 200px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+ background: green;
+ zoom: 1.2;
+}
+
+html::view-transition-group(target) { animation-duration: 300s; }
+html::view-transition-old(target) { animation: unset; opacity: 0; }
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+ border: 3px solid black;
+}
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div class=ancestor>
+ <div class=target>
+ <div class=child>
+ </div>
+ </div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-content-with-overflow.html b/testing/web-platform/tests/css/css-view-transitions/new-content-with-overflow.html
new file mode 100644
index 0000000000..e2dc045089
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-content-with-overflow.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: shared element with overflow</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="content-with-overflow-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ background: blue;
+ overflow-clip-margin: 50px;
+ view-transition-name: target;
+}
+.child {
+ width: 200px;
+ height: 200px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+ background: green;
+}
+
+html::view-transition-group(target) { animation-duration: 300s; }
+html::view-transition-old(target) { animation: unset; opacity: 0; }
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+}
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div class=target>
+ <div class=child>
+ </div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-element-on-start-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-element-on-start-ref.html
new file mode 100644
index 0000000000..b3db1f2e19
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-element-on-start-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>View transitions: one element captured for two tags (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ top: 50px;
+ background: black;
+ left: 200px;
+ filter: invert(1);
+}
+body { background: lightpink; }
+</style>
+<div></div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-element-on-start.html b/testing/web-platform/tests/css/css-view-transitions/new-element-on-start.html
new file mode 100644
index 0000000000..7e870e9d89
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-element-on-start.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: new element tag specified for start phase</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-element-on-start-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ top: 50px;
+}
+
+.before {
+ background: lightblue;
+ left: 50px;
+}
+.after {
+ background: black;
+ left: 200px;
+}
+.hidden {
+ background: red;
+ left: 350px;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { opacity: 0; }
+
+html::view-transition-group(before) { animation-duration: 0s; }
+html::view-transition-image-pair(before) { filter: invert(1); }
+
+html::view-transition-group(after) { animation-duration: 0s; }
+html::view-transition-image-pair(after) { filter: invert(1); }
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+
+</style>
+
+<div id=before class=before></div>
+<div id=after class=after></div>
+
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ hidden.style.viewTransitionName = "hidden";
+ before.style.viewTransitionName = "before";
+ let transition = document.startViewTransition(() => {
+ before.remove();
+ after.style.viewTransitionName = "after";
+ });
+ transition.ready.then(() => requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-root-vertical-writing-mode-ref.html b/testing/web-platform/tests/css/css-view-transitions/new-root-vertical-writing-mode-ref.html
new file mode 100644
index 0000000000..f6b817d92b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-root-vertical-writing-mode-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>View transitions: container of shared element writing-modes (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+html { writing-mode: vertical-lr; }
+.shared {
+ margin: 2px;
+ width: 90px;
+ height: 50px;
+ background: green;
+ contain: paint;
+}
+#two {
+ background: lightblue;
+}
+</style>
+
+<div id=one class=shared>T</div>
+<div id=two class=shared></div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/new-root-vertical-writing-mode.html b/testing/web-platform/tests/css/css-view-transitions/new-root-vertical-writing-mode.html
new file mode 100644
index 0000000000..61dc5aca17
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/new-root-vertical-writing-mode.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: container of shared element writing-modes</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-root-vertical-writing-mode-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+html { writing-mode: vertical-lr; }
+#hidden {
+ width: 100px;
+ height: 100px;
+ background: red;
+ position: absolute;
+ top: 0;
+ left: 0;
+ contain: paint;
+ view-transition-name: hidden;
+}
+.shared {
+ margin: 2px;
+ width: 90px;
+ height: 50px;
+ background: green;
+ contain: paint;
+}
+#target {
+ background: red;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+ width: 100px;
+ height: 500px;
+ contain: paint;
+ view-transition-name: s1;
+}
+#two {
+ background: lightblue;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(s1) { animation-duration: 0s; }
+html::view-transition-new(s1) { animation: unset; opacity: 1; }
+html::view-transition-old(s1) { animation: unset; opacity: 0; }
+
+html::view-transition-new(root) { animation: unset; opacity: 1; }
+html::view-transition-old(root) { animation: unset; opacity: 0; }
+
+</style>
+
+<div id=hidden>Should not be visible</div>
+<div id=target>Should not be visible</div>
+<div id=one class=shared>T</div>
+<div id=two class=shared></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ target.remove();
+ hidden.style.left = "200px";
+ one.style.viewTransitionName = "s1";
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/no-crash-set-exception.html b/testing/web-platform/tests/css/css-view-transitions/no-crash-set-exception.html
new file mode 100644
index 0000000000..e1596cf76e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/no-crash-set-exception.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: author styles ignored during prepare</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ contain: paint;
+ view-transition-name: shared;
+}
+
+html::view-transition,
+html::view-transition-group(shared),
+html::view-transition-image-pair(shared),
+html::view-transition-old(shared),
+html::view-transition-new(shared) {
+ background: blue;
+}
+</style>
+
+<div></div>
+
+<script>
+promise_test(async t => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise((resolve, reject) => {
+ document.startViewTransition(() => {
+ resolve();
+ throw 'error';
+ });
+ });
+}, "An exception thrown during a transition shouldn't crash.");
+
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/no-crash-view-transition-in-massive-iframe.html b/testing/web-platform/tests/css/css-view-transitions/no-crash-view-transition-in-massive-iframe.html
new file mode 100644
index 0000000000..c004a94dcb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/no-crash-view-transition-in-massive-iframe.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>View transitions: no crash with view-transitions in massive iframe</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:roger.johannesson@xperi.com">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+iframe { width: 40000px; height: 40000px }
+</style>
+
+<iframe></iframe>
+
+<script>
+promise_test(async t => {
+ const iframeDoc = document.getElementsByTagName("iframe")[0].contentDocument;
+ assert_implements(iframeDoc.startViewTransition, "Missing document.startViewTransition in iframe");
+ const transition = iframeDoc.startViewTransition();
+ try { await transition.ready; } catch {}
+}, "startViewTransition in massive iframe shouldn't crash.");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/no-css-animation-while-render-blocked.html b/testing/web-platform/tests/css/css-view-transitions/no-css-animation-while-render-blocked.html
new file mode 100644
index 0000000000..ae9cfda9bb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/no-css-animation-while-render-blocked.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<html>
+<title>View transitions: CSS Animations are paused while render-blocked</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+@keyframes fade {
+ from {
+ opacity: 0;
+ }
+}
+
+div {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ contain: paint;
+ view-transition-name: target;
+}
+
+.animated {
+ animation: fade 0.5s;
+}
+</style>
+
+<div id=target></div>
+
+<script>
+let renderBlocked = true;
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ requestAnimationFrame(() => {
+ document.startViewTransition(() => {
+ return new Promise(async (inner_resolve) => {
+ step_timeout(() => {
+ renderBlocked = false;
+ inner_resolve();
+ }, 1000);
+ });
+ });
+
+ target.classList.toggle("animated");
+ target.onanimationend = () => {
+ if (renderBlocked)
+ reject();
+ else
+ resolve();
+ };
+ });
+ });
+}, "CSS animation is blocked until prepare callback");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/no-raf-while-render-blocked.html b/testing/web-platform/tests/css/css-view-transitions/no-raf-while-render-blocked.html
new file mode 100644
index 0000000000..52058b7a04
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/no-raf-while-render-blocked.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<html>
+<title>View transitions: rAF is not issued while render-blocked</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ contain: paint;
+ view-transition-name: target;
+}
+</style>
+
+<div id=target></div>
+
+<script>
+let renderBlocked = true;
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ requestAnimationFrame(() => {
+ document.startViewTransition(() => {
+ return new Promise(async (inner_resolve) => {
+ step_timeout(() => {
+ renderBlocked = false;
+ inner_resolve();
+ }, 1000);
+ });
+ });
+
+ requestAnimationFrame(() => {
+ if (renderBlocked)
+ reject();
+ else
+ resolve();
+ });
+ });
+ });
+}, "rAF is blocked until prepare callback");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/no-root-capture-ref.html b/testing/web-platform/tests/css/css-view-transitions/no-root-capture-ref.html
new file mode 100644
index 0000000000..98ac7c9de9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/no-root-capture-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>View transitions: shared element with overflow (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+.target {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ background: blue;
+ overflow-clip-margin: 50px;
+ view-transition-name: target;
+}
+.child {
+ width: 200px;
+ height: 200px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+ background: green;
+}
+</style>
+
+This text should appear unmodified, since the root isn't captured.
+<div class=target>
+ <div class=child>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/no-root-capture.html b/testing/web-platform/tests/css/css-view-transitions/no-root-capture.html
new file mode 100644
index 0000000000..9e16d1e447
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/no-root-capture.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: shared element with overflow</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="no-root-capture-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root { view-transition-name: none; }
+.target {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ background: blue;
+ overflow-clip-margin: 50px;
+ view-transition-name: target;
+}
+.child {
+ width: 200px;
+ height: 200px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+ background: green;
+}
+
+html::view-transition-group(target) { animation-duration: 300s; }
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 1;
+}
+
+/* None of these should apply, so make everything red if it does */
+html::view-transition-group(root) { animation: unset; opacity: 1; background: red; }
+html::view-transition-image-pair(root) { visibility: hidden }
+</style>
+
+This text should appear unmodified, since the root isn't captured.
+<div class=target>
+ <div class=child>
+ </div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/nothing-captured-ref.html b/testing/web-platform/tests/css/css-view-transitions/nothing-captured-ref.html
new file mode 100644
index 0000000000..98ac7c9de9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/nothing-captured-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>View transitions: shared element with overflow (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+.target {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ background: blue;
+ overflow-clip-margin: 50px;
+ view-transition-name: target;
+}
+.child {
+ width: 200px;
+ height: 200px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+ background: green;
+}
+</style>
+
+This text should appear unmodified, since the root isn't captured.
+<div class=target>
+ <div class=child>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/nothing-captured.html b/testing/web-platform/tests/css/css-view-transitions/nothing-captured.html
new file mode 100644
index 0000000000..468cb6e199
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/nothing-captured.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: shared element with overflow</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="nothing-captured-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root { view-transition-name: none; }
+.target {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ background: blue;
+ overflow-clip-margin: 50px;
+}
+.child {
+ width: 200px;
+ height: 200px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+ background: green;
+}
+
+/* None of these should apply, so make everything red if it does */
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-image-pair(*) { visibility: hidden }
+html::view-transition { background: red; }
+</style>
+
+This text should appear unmodified, since the root isn't captured.
+<div class=target>
+ <div class=child>
+ </div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/object-view-box-new-image.html b/testing/web-platform/tests/css/css-view-transitions/object-view-box-new-image.html
new file mode 100644
index 0000000000..3ea7eb96b6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/object-view-box-new-image.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: object-view-box</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="object-view-box-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ transform: scale(2.0, 3.0);
+ position: relative;
+ top: 200px;
+ left: 200px;
+ view-transition-name: target;
+}
+
+.embedded {
+ width: 100%;
+ height: 50%;
+}
+
+.hidden {
+ contain: paint;
+ width: 10px;
+ height: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 0;
+ height: 100%;
+}
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+ object-view-box: inset(50px 0px 0px 0px);
+ object-fit: none;
+ object-position: 0% 0%;
+ height: 100%;
+ contain: paint;
+}
+
+</style>
+
+<div id="target" class="target">
+ <div class="embedded" style="background: green;"></div>
+ <div class="embedded" style="background: blue">SharedElement</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(runTest);
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/object-view-box-old-image.html b/testing/web-platform/tests/css/css-view-transitions/object-view-box-old-image.html
new file mode 100644
index 0000000000..7f6f79ba44
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/object-view-box-old-image.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<html class=reftest-wait>
+<title>View transitions: object-view-box</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="object-view-box-ref.html">
+<meta name="fuzzy" content="object-view-box-ref.html:0-1;0-300">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ transform: scale(2.0, 3.0);
+ position: relative;
+ top: 200px;
+ left: 200px;
+ view-transition-name: target;
+}
+
+.embedded {
+ width: 100%;
+ height: 50%;
+}
+
+.hidden {
+ contain: paint;
+ width: 10px;
+ height: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 0;
+ height: 100%;
+}
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 1;
+ object-view-box: inset(50px 0px 0px 0px);
+ object-fit: none;
+ object-position: 0% 0%;
+ height: 100%;
+ contain: paint;
+}
+
+</style>
+
+<div id="target" class="target">
+ <div class="embedded" style="background: green;"></div>
+ <div class="embedded" style="background: blue">SharedElement</div>
+</div>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(runTest);
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/object-view-box-ref.html b/testing/web-platform/tests/css/css-view-transitions/object-view-box-ref.html
new file mode 100644
index 0000000000..9ed1e50309
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/object-view-box-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>View transitions: object-view-box (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.target {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ transform: scale(2.0, 3.0);
+ position: relative;
+ top: 200px;
+ left: 200px;
+}
+.content {
+ width: 100px;
+ height: 50px;
+ background: blue;
+}
+
+</style>
+<div class="target">
+ <div class="content">SharedElement</div>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/offscreen-element-modified-before-coming-onscreen-ref.html b/testing/web-platform/tests/css/css-view-transitions/offscreen-element-modified-before-coming-onscreen-ref.html
new file mode 100644
index 0000000000..171f999554
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/offscreen-element-modified-before-coming-onscreen-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: new element is modified while offscren and brought onscreen using pseudo (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+ position: fixed;
+ background: blue;
+ left: 0;
+ top: 0;
+}
+</style>
+
+<div id="target" class="target">
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/offscreen-element-modified-before-coming-onscreen.html b/testing/web-platform/tests/css/css-view-transitions/offscreen-element-modified-before-coming-onscreen.html
new file mode 100644
index 0000000000..77c35ab583
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/offscreen-element-modified-before-coming-onscreen.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: new element is modified while offscren and brought onscreen using pseudo</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="offscreen-element-modified-before-coming-onscreen-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+ position: fixed;
+ background: green;
+ left: 0;
+ top: 200vh;
+}
+
+.hidden {
+ width: 10px;
+ height: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+.onscreen::view-transition-group(target) {
+ transform: unset;
+ position: fixed;
+ top: 0;
+ left: 0;
+ animation: unset;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-old(target) { animation: unset; opacity: 0; }
+html::view-transition-new(target) { animation: unset; opacity: 1; }
+
+</style>
+
+<div id=target class=target>
+<div id=hidden class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function bringOnscreenAndScreenshot() {
+ document.documentElement.classList.add("onscreen");
+
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ ));
+}
+
+async function runTest() {
+ // Start the transition while the element is offscreen.
+ let transition = document.startViewTransition();
+ await transition.ready;
+
+ // Change the element's color while its still offscreen.
+ target.style.background = "blue";
+
+ // Bring the element onscreen and ensure the color change is presented.
+ requestAnimationFrame(() => requestAnimationFrame(() =>
+ requestAnimationFrame(() => requestAnimationFrame(
+ bringOnscreenAndScreenshot))
+ ));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-captures-clip-path-ref.html b/testing/web-platform/tests/css/css-view-transitions/old-content-captures-clip-path-ref.html
new file mode 100644
index 0000000000..0d9d498b6b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-captures-clip-path-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>View transitions: capture clip-path elements (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.box {
+ color: red;
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ font-size: 30pt;
+}
+#e1 {
+ clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
+ top: 20px;
+ left: 20px;
+}
+body { background: lightpink; }
+</style>
+<div id=e1 class=box></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-captures-clip-path.html b/testing/web-platform/tests/css/css-view-transitions/old-content-captures-clip-path.html
new file mode 100644
index 0000000000..467b19d928
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-captures-clip-path.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: capture clip-path elements</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="old-content-captures-clip-path-ref.html">
+<meta name="fuzzy" content="old-content-captures-clip-path-ref.html:0-1;0-500">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ color: red;
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ font-size: 30pt;
+}
+#e1 {
+ clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
+ top: 20px;
+ left: 20px;
+ view-transition-name: e1;
+}
+
+div.dst { background: lightgreen; }
+/* We're verifying what we capture, so just display the old contents for 5 minutes. */
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 0; }
+html::view-transition-old(*) { animation: unset; opacity: 1; }
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+<div id=e1 class=box></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ e1.classList.add("dst");
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-captures-different-size-ref.html b/testing/web-platform/tests/css/css-view-transitions/old-content-captures-different-size-ref.html
new file mode 100644
index 0000000000..4fbabd48f7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-captures-different-size-ref.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>View transitions: capture elements with different size capture (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.box {
+ color: red;
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ font-size: 30pt;
+}
+#e1 {
+ clip-path: circle(30%);
+ top: 20px;
+ left: 20px;
+}
+#e2 {
+ clip-path: ellipse(70% 30%);
+ top: 160px;
+ left: 20px;
+}
+#e3 {
+ filter: blur(5px);
+ top: 300px;
+ left: 20px;
+}
+body { background: lightpink; }
+</style>
+<div id=e1 class=box>one</div>
+<div id=e2 class=box>two</div>
+<div id=e3 class=box>three</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-captures-different-size.html b/testing/web-platform/tests/css/css-view-transitions/old-content-captures-different-size.html
new file mode 100644
index 0000000000..a8d375f064
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-captures-different-size.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<html class=reftest-wait>
+<title>View transitions: capture elements with different size capture</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="old-content-captures-different-size-ref.html">
+<meta name=fuzzy content="old-content-captures-different-size-ref.html:0-40;0-30000">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ color: red;
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ font-size: 30pt;
+}
+#e1 {
+ clip-path: circle(30%);
+ top: 20px;
+ left: 20px;
+ view-transition-name: e1;
+}
+#e2 {
+ clip-path: ellipse(70% 30%);
+ top: 160px;
+ left: 20px;
+ view-transition-name: e2;
+}
+#e3 {
+ filter: blur(5px);
+ top: 300px;
+ left: 20px;
+ view-transition-name: e3;
+}
+
+div.dst { background: lightgreen; }
+/* We're verifying what we capture, so just display the old contents for 5 minutes. */
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 0; }
+html::view-transition-old(*) { animation: unset; opacity: 1; }
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+<div id=e1 class=box>one</div>
+<div id=e2 class=box>two</div>
+<div id=e3 class=box>three</div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ e1.classList.add("dst");
+ e2.classList.add("dst");
+ e3.classList.add("dst");
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-captures-opacity-ref.html b/testing/web-platform/tests/css/css-view-transitions/old-content-captures-opacity-ref.html
new file mode 100644
index 0000000000..33f7f5b14a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-captures-opacity-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>View transitions: capture opacity elements (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.box {
+ color: red;
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ font-size: 30pt;
+ will-change: opacity;
+}
+#e1 { opacity: 0.75; top: 20px; left: 20px; }
+#e2 { opacity: 0.5; top: 160px; left: 20px; }
+#e3 { opacity: 0.25; top: 300px; left: 20px; }
+body { background: lightpink; }
+</style>
+<div id=e1 class=box>one</div>
+<div id=e2 class=box>two</div>
+<div id=e3 class=box>three</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-captures-opacity.html b/testing/web-platform/tests/css/css-view-transitions/old-content-captures-opacity.html
new file mode 100644
index 0000000000..ee3e3e4cde
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-captures-opacity.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: capture opacity elements</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="old-content-captures-opacity-ref.html">
+<meta name=fuzzy content="old-content-captures-opacity-ref.html:0-1;0-50000">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ color: red;
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ font-size: 30pt;
+}
+#e1 { opacity: 0.75; top: 20px; left: 20px; view-transition-name: e1; }
+#e2 { opacity: 0.5; top: 160px; left: 20px; view-transition-name: e2; }
+#e3 { opacity: 0.25; top: 300px; left: 20px; view-transition-name: e3; }
+div.dst { background: lightgreen; }
+/* We're verifying what we capture, so just display the old contents for 5 minutes. */
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 0; }
+html::view-transition-old(*) { animation: unset; opacity: 1; }
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+<div id=e1 class=box>one</div>
+<div id=e2 class=box>two</div>
+<div id=e3 class=box>three</div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ e1.classList.add("dst");
+ e2.classList.add("dst");
+ e3.classList.add("dst");
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-captures-root-ref.html b/testing/web-platform/tests/css/css-view-transitions/old-content-captures-root-ref.html
new file mode 100644
index 0000000000..92bd70f6f4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-captures-root-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>View transitions: capture root elements (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.box {
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ font-size: 30pt;
+}
+#e1 {
+ top: 20px;
+ left: 20px;
+}
+</style>
+<div id=e1 class=box></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-captures-root.html b/testing/web-platform/tests/css/css-view-transitions/old-content-captures-root.html
new file mode 100644
index 0000000000..96acb9f455
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-captures-root.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: capture root elements</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="old-content-captures-root-ref.html">
+<meta name="fuzzy" content="old-content-captures-root-ref.html:0-1;0-500">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.box {
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ font-size: 30pt;
+}
+#e1 {
+ top: 20px;
+ left: 20px;
+}
+#shared {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ background: red;
+ view-transition-name: shared;
+}
+
+div.dst { background: lightgreen; }
+/* We're verifying what we capture, so just display the old contents for 5 minutes. */
+html::view-transition { background: pink; }
+html::view-transition-group(shared) { animation-duration: 300s; }
+html::view-transition-image-pair(shared) { visibility: hidden }
+html::view-transition-old(root) { animation: unset; opacity: 1 }
+html::view-transition-new(root) { animation: unset; opacity: 0 }
+</style>
+<div id=e1 class=box></div>
+<div id=shared></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ e1.classList.add("dst");
+ document.body.style.background = "red";
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-container-writing-modes-ref.html b/testing/web-platform/tests/css/css-view-transitions/old-content-container-writing-modes-ref.html
new file mode 100644
index 0000000000..be264399c8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-container-writing-modes-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>View transitions: container of shared element writing-modes (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+.tb { writing-mode: horizontal-tb; }
+.lr { writing-mode: vertical-lr; }
+.rl { writing-mode: vertical-rl; }
+.shared {
+ margin: 2px;
+ width: 100px;
+ height: 50px;
+ background: green;
+ contain: paint;
+ border: 1px solid black;
+}
+html { background: lightpink; }
+</style>
+
+<div class=tb><div id=one class=shared>T</div></div>
+<div class=lr><div id=two class=shared>T</div></div>
+<div class=rl><div id=three class=shared>T</div></div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-container-writing-modes.html b/testing/web-platform/tests/css/css-view-transitions/old-content-container-writing-modes.html
new file mode 100644
index 0000000000..9896c27152
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-container-writing-modes.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: container of shared element writing-modes</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="old-content-container-writing-modes-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#hidden {
+ width: 100px;
+ height: 100px;
+ background: red;
+ position: absolute;
+ top: 0;
+ left: 0;
+ contain: paint;
+ view-transition-name: hidden;
+}
+.tb { writing-mode: horizontal-tb; }
+.lr { writing-mode: vertical-lr; }
+.rl { writing-mode: vertical-rl; }
+.shared {
+ margin: 2px;
+ width: 100px;
+ height: 50px;
+ background: green;
+ contain: paint;
+ border: 1px solid black;
+}
+#target1, #target2, #target3 {
+ background: red;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+ width: 100px;
+ height: 500px;
+ contain: paint;
+}
+#one { view-transition-name: s1; }
+#two { view-transition-name: s2; }
+#three { view-transition-name: s3; }
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(s1),
+html::view-transition-group(s2),
+html::view-transition-group(s3) {
+ animation-delay: 300s;
+ animation-fill-mode: both;
+}
+
+html::view-transition-new(s1),
+html::view-transition-new(s2),
+html::view-transition-new(s3) { animation: unset; opacity: 0; }
+
+html::view-transition-old(s1),
+html::view-transition-old(s2),
+html::view-transition-old(s3) { animation: unset; opacity: 1; }
+
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+
+</style>
+
+<div id=hidden>Should not be visible</div>
+<div id=target1>Should not be visible</div>
+<div id=target2>Should not be visible</div>
+<div id=target3>Should not be visible</div>
+<div class=tb><div id=one class=shared>T</div></div>
+<div class=lr><div id=two class=shared>T</div></div>
+<div class=rl><div id=three class=shared>T</div></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ one.remove();
+ two.remove();
+ three.remove();
+ hidden.style.left = "200px";
+ target1.style.viewTransitionName = "s1";
+ target2.style.viewTransitionName = "s2";
+ target3.style.viewTransitionName = "s3";
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-element-writing-modes-ref.html b/testing/web-platform/tests/css/css-view-transitions/old-content-element-writing-modes-ref.html
new file mode 100644
index 0000000000..8c57dba658
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-element-writing-modes-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>View transitions: shared element writing-modes (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+.tb { writing-mode: horizontal-tb; }
+.lr { writing-mode: vertical-lr; }
+.rl { writing-mode: vertical-rl; }
+.shared {
+ margin: 2px;
+ width: 100px;
+ height: 50px;
+ background: green;
+ contain: paint;
+ border: 1px solid black;
+}
+html { background: lightpink; }
+</style>
+
+<div id=one class="tb shared">T</div>
+<div id=two class="lr shared">T</div>
+<div id=three class="rl shared">T</div>
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-element-writing-modes.html b/testing/web-platform/tests/css/css-view-transitions/old-content-element-writing-modes.html
new file mode 100644
index 0000000000..5029c6aaaa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-element-writing-modes.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: shared element writing-modes</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="old-content-element-writing-modes-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#hidden {
+ width: 100px;
+ height: 100px;
+ background: red;
+ position: absolute;
+ top: 0;
+ left: 0;
+ contain: paint;
+ view-transition-name: hidden;
+}
+.tb { writing-mode: horizontal-tb; }
+.lr { writing-mode: vertical-lr; }
+.rl { writing-mode: vertical-rl; }
+.shared {
+ margin: 2px;
+ width: 100px;
+ height: 50px;
+ background: green;
+ contain: paint;
+ border: 1px solid black;
+}
+#target1, #target2, #target3 {
+ background: red;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+ width: 100px;
+ height: 500px;
+ contain: paint;
+}
+#one { view-transition-name: s1; }
+#two { view-transition-name: s2; }
+#three { view-transition-name: s3; }
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(s1),
+html::view-transition-group(s2),
+html::view-transition-group(s3) {
+ animation-delay: 300s;
+ animation-fill-mode: both;
+}
+
+html::view-transition-new(s1),
+html::view-transition-new(s2),
+html::view-transition-new(s3) { animation: unset; opacity: 0; }
+
+html::view-transition-old(s1),
+html::view-transition-old(s2),
+html::view-transition-old(s3) { animation: unset; opacity: 1; }
+
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+
+</style>
+
+<div id=hidden>Should not be visible</div>
+<div id=target1>Should not be visible</div>
+<div id=target2>Should not be visible</div>
+<div id=target3>Should not be visible</div>
+<div id=one class="shared tb">T</div>
+<div id=two class="shared lr">T</div>
+<div id=three class="shared rl">T</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ one.remove();
+ two.remove();
+ three.remove();
+ hidden.style.left = "200px";
+ target1.style.viewTransitionName = "s1";
+ target2.style.viewTransitionName = "s2";
+ target3.style.viewTransitionName = "s3";
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
+
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-has-scrollbars-ref.html b/testing/web-platform/tests/css/css-view-transitions/old-content-has-scrollbars-ref.html
new file mode 100644
index 0000000000..b349e80700
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-has-scrollbars-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>View transitions: outgoing viewport has scrollbars (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7859">
+<link rel="author" href="mailto:bokan@chromium.org">
+<style>
+ html, body {
+ width: 100%;
+ height: 100%;
+ background-color: lightpink;
+ }
+ html {
+ overflow: hidden;
+ }
+ body {
+ margin: 50px;
+ }
+ div {
+ background-image:
+ linear-gradient(45deg, #000 25%, transparent 25%),
+ linear-gradient(45deg, transparent 75%, #000 75%),
+ linear-gradient(45deg, transparent 75%, #000 75%),
+ linear-gradient(45deg, #000 25%, lightgreen 25%);
+ background-size: 200px 200px;
+ background-position: 0 0, 0 0, -100px -100px, 100px 100px;
+ width: 200%;
+ height: 200%;
+ }
+</style>
+<div></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-has-scrollbars.html b/testing/web-platform/tests/css/css-view-transitions/old-content-has-scrollbars.html
new file mode 100644
index 0000000000..781ff7c125
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-has-scrollbars.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<html class=reftest-wait>
+<title>View transitions: outgoing viewport has scrollbars</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7859">
+<link rel="author" href="mailto:bokan@chromium.org">
+<link rel="match" href="old-content-has-scrollbars-ref.html">
+<meta name=fuzzy content="old-content-has-scrollbars-ref.html:0-40;0-30000">
+<script src="/common/reftest-wait.js"></script>
+<style>
+ html, body {
+ width: 100%;
+ height: 100%;
+ background-color: lightpink;
+ }
+ body {
+ /* Margin to make sure background color is correctly drawn into the snapshot. */
+ margin: 50px;
+ }
+ div {
+ /* Draw a checkerboard pattern to make sure the snapshot is captured at the
+ * full size, rather than scaled. */
+ background-image:
+ linear-gradient(45deg, #000 25%, transparent 25%),
+ linear-gradient(45deg, transparent 75%, #000 75%),
+ linear-gradient(45deg, transparent 75%, #000 75%),
+ linear-gradient(45deg, #000 25%, lightgreen 25%);
+ background-size: 200px 200px;
+ background-position: 0 0, 0 0, -100px -100px, 100px 100px;
+ width: 200%;
+ height: 200%;
+ }
+
+ /* We're verifying what we capture, so just display the old contents for 5 minutes. */
+ html::view-transition-new(root) { animation: unset; opacity: 0; }
+ html::view-transition-old(root) {
+ animation-duration: 300s;
+ animation-timing-function: steps(1, end);
+ opacity: 1;
+ }
+</style>
+
+<div></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+// Ensure a root snapshot captured on a page with scrollbars uses the full
+// viewport size (including scrollbars). Areas obscured by scrollbars should be
+// filled with background and content; the snapshot should not be scaled-to-fit.
+async function runTest() {
+ document.startViewTransition(() => {
+ document.querySelector('div').remove();
+ document.documentElement.style.overflow = "hidden";
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-intrinsic-aspect-ratio.html b/testing/web-platform/tests/css/css-view-transitions/old-content-intrinsic-aspect-ratio.html
new file mode 100644
index 0000000000..b46a778217
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-intrinsic-aspect-ratio.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: different width container should keep aspect ratio (by default)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="intrinsic-aspect-ratio-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.spacer {
+ height: 10px;
+}
+.box {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ background: blue;
+}
+#target1 {
+ view-transition-name: target1;
+}
+#target2 {
+ view-transition-name: target2;
+}
+#hidden {
+ view-transition-name: hidden;
+ width: 10px;
+ height: 10px;
+ visibility: hidden;
+ contain: paint;
+}
+
+/* We're verifying what we capture, so just display the new contents for 5 minutes. */
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 0; }
+html::view-transition-old(*) { animation: unset; opacity: 1; }
+
+html::view-transition-group(target1) {
+ animation: unset;
+ width: 50px;
+ border: 2px solid black;
+}
+html::view-transition-group(target2) {
+ animation: unset;
+ width: 200px;
+ border: 2px solid black;
+}
+
+/* hide the root so we show transition background to ensure we're in a transition */
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div id=target1 class=box></div>
+<div class=spacer></div>
+<div id=target2 class=box></div>
+<div id=hidden></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-is-empty-div-ref.html b/testing/web-platform/tests/css/css-view-transitions/old-content-is-empty-div-ref.html
new file mode 100644
index 0000000000..b4b17ee780
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-is-empty-div-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>View transitions: old content captures an empty div (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+ background: green;
+}
+body { background: lightpink; }
+</style>
+<div></div>
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-is-empty-div.html b/testing/web-platform/tests/css/css-view-transitions/old-content-is-empty-div.html
new file mode 100644
index 0000000000..137060c1dd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-is-empty-div.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: old content captures an empty div</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="old-content-is-empty-div-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+div {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ top: 50px;
+}
+#empty {
+ left: 50px;
+}
+#target {
+ left: 200px;
+ background: green;
+}
+#hidden {
+ background: red;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+/* The effect of the following should be position at the outgoing element
+ but contents of the new element.
+*/
+html::view-transition-group(shared) { animation-delay: 100s; }
+html::view-transition-new(shared) { animation: unset; opacity: 1; }
+html::view-transition-old(shared) { animation: unset; opacity: 1; }
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+
+</style>
+
+<div id=empty></div>
+<div id=target></div>
+<div id=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ empty.style.viewTransitionName = "shared";
+ document.startViewTransition(() => {
+ empty.style.viewTransitionName = "";
+ target.style.viewTransitionName = "shared";
+
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-is-inline-ref.html b/testing/web-platform/tests/css/css-view-transitions/old-content-is-inline-ref.html
new file mode 100644
index 0000000000..5459d1d482
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-is-inline-ref.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<title>View transitions: Old content is an inline element (ref)</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:bokan@chromium.org">
+
+<style>
+:root { background-color: rebeccapurple; }
+body { margin: 0; }
+
+.container {
+ position: absolute;
+ left: 100px;
+ width: 400px;
+ height: 100px;
+ background-color: grey;
+}
+
+.container.start {
+ top: 100px;
+}
+
+.container.end {
+ top: 300px;
+}
+
+.container.transitioned {
+ left: 20px;
+ width: 600px;
+ transform: translateY(-50px);
+}
+
+.inline {
+ background-color: limegreen;
+ color: rgba(0, 0, 0, 0);
+}
+
+.transitioned .inline {
+ opacity: 0;
+}
+
+#dummyEndInline {
+ position: absolute;
+ left: 20px;
+ top: 250px;
+ /* scale transform applied in script below */
+ transform-origin: top left;
+}
+
+</style>
+
+<div class="container start">
+ <span>FILLER FILLER</span>
+ <span id="start" class="inline">INLINE INLINE INLINE INLINE</span>
+ <p>START STATE</p>
+</div>
+
+<div class="container end transitioned">
+ <span>FILLER FILLER</span>
+ <span id="end" class="inline">INLINE INLINE INLINE INLINE</span>
+ <p>END STATE</p>
+</div>
+
+<div id="dummyEndInline">
+ <span style="opacity:0">FILLER FILLER</span>
+ <span class="inline">INLINE INLINE INLINE INLINE</span>
+</div>
+<script>
+ let endWidth = document.getElementById('end').getBoundingClientRect().width;
+ let startWidth = document.getElementById('start').getBoundingClientRect().width;
+ let scale = endWidth / startWidth;
+ /* Default UA CSS scales the image pseudos to match the group in the inline
+ direction. The block direction scales to retain the image's aspect ratio.
+ So have the dummy end line scale to match the end state width and apply the
+ same scale to its height. */
+ document.getElementById('dummyEndInline').style.transform = `scale(${scale})`;
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-is-inline.html b/testing/web-platform/tests/css/css-view-transitions/old-content-is-inline.html
new file mode 100644
index 0000000000..70ff67c0e0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-is-inline.html
@@ -0,0 +1,148 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: Old content is an inline element.</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:bokan@chromium.org">
+<link rel="match" href="old-content-is-inline-ref.html">
+<meta name="fuzzy" content="old-content-is-inline-ref.html:0-255;0-500">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+body { margin : 0; }
+.container {
+ position: absolute;
+ left: 100px;
+ width: 400px;
+ height: 100px;
+ background-color: grey;
+}
+
+.container.start {
+ top: 100px;
+ view-transition-name: container-start;
+}
+
+.container.end {
+ top: 300px;
+ view-transition-name: container-end;
+}
+
+.transitioned .container {
+ left: 20px;
+ width: 600px;
+ transform: translateY(-50px);
+}
+
+.inline {
+ background-color: limegreen;
+ /* allow small pixel diff in text */
+ color: rgba(0, 0, 0, 0);
+}
+
+.start .inline {
+ view-transition-name: start;
+}
+
+.end .inline {
+ view-transition-name: end;
+}
+
+.transitioned .inline {
+ background-color: coral;
+}
+
+/* Overlay the page with purple to ensure screenshots taken are of the view
+ * transition. */
+:root {
+ view-transition-name: none;
+}
+::view-transition {
+ background-color: rebeccapurple;
+}
+
+/* This step function keeps the old snapshots in their initial state for half
+ * the duration, then the new snapshots in their final state for the last half
+ * of the duration. */
+html::view-transition-group(*),
+html::view-transition-new(*),
+html::view-transition-old(*) {
+ animation-timing-function: steps(2, jump-none);
+}
+
+/* Set different durations for start and end so the two subtrees can be
+ * differentiated. The test will manually control animation playback so
+ * duration doesn't matter. */
+html::view-transition-group(container-start),
+html::view-transition-group(start),
+html::view-transition-new(container-start),
+html::view-transition-old(container-start) {
+ animation-duration: 2s;
+}
+html::view-transition-group(container-end),
+html::view-transition-group(end),
+html::view-transition-new(container-end),
+html::view-transition-old(container-end) {
+ animation-duration: 3s;
+}
+
+/* Hide the new states for the inlines, they're tested in
+ * new-content-is-inline.html */
+html::view-transition-new(start),
+html::view-transition-new(end) {
+ animation: unset;
+ opacity: 0;
+}
+html::view-transition-old(start),
+html::view-transition-old(end) {
+ animation: unset;
+ opacity: 1;
+}
+
+</style>
+
+<!--
+This subtree will be held at the animation start to test the old content's
+starting position.
+-->
+<div class="container start">
+ <span>FILLER FILLER</span>
+ <span id="start" class="inline">INLINE INLINE INLINE INLINE</span>
+ <p>START STATE</p>
+</div>
+
+<!--
+This subtree will be held at the animation end to test the old content's
+ending position.
+-->
+<div class="container end">
+ <span>FILLER FILLER</span>
+ <span id="end" class="inline">INLINE INLINE INLINE INLINE</span>
+ <p>END STATE</p>
+</div>
+
+<script>
+if (typeof failIfNot != 'undefined')
+ failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition(() => {
+ document.body.classList.add('transitioned');
+ });
+
+ transition.ready.then(() => {
+ for (const anim of document.getAnimations()) {
+ anim.pause();
+ if (anim.effect.getTiming().duration == 3000) {
+ // This is an animation for the end subtree. Adjust it to the end
+ // (without finishing the animation) so we're displaying the final
+ // position.
+ anim.currentTime = anim.effect.getTiming().duration - 1;
+ }
+ }
+
+ requestAnimationFrame(takeScreenshot);
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-object-fit-fill.html b/testing/web-platform/tests/css/css-view-transitions/old-content-object-fit-fill.html
new file mode 100644
index 0000000000..9ad8b14843
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-object-fit-fill.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: display content in a pseudo with object-fit: fill</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="content-object-fit-fill-ref.html">
+<meta name="fuzzy" content="content-object-fit-fill-ref.html:0-60;0-20">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ view-transition-name: target;
+ background: lightblue;
+}
+#inner {
+ width: 10px;
+ height: 10px;
+ background: green;
+ top: 5px;
+ left: 10px;
+}
+#hidden {
+ background: pink;
+ width: 10px;
+ height: 10px;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(target) {
+ animation: unset;
+ transform: unset;
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ width: 50px;
+ height: 50px;
+}
+
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 0;
+}
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 1;
+ object-fit: fill;
+}
+
+html::view-transition-group(hidden) {
+ animation-duration: 500s;
+ visibility: hidden;
+}
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div id=target><div id=inner></div></div>
+<div id=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-object-fit-none.html b/testing/web-platform/tests/css/css-view-transitions/old-content-object-fit-none.html
new file mode 100644
index 0000000000..1275aece7c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-object-fit-none.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: display content in a pseudo with object-fit: none</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="content-object-fit-none-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ view-transition-name: target;
+ background: lightblue;
+}
+#hidden {
+ background: pink;
+ width: 10px;
+ height: 10px;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(target) {
+ animation: unset;
+ transform: unset;
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ width: 50px;
+ height: 50px;
+}
+
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 0;
+}
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 1;
+ object-fit: none;
+ object-position: 0% 0%;
+}
+
+html::view-transition-group(hidden) {
+ animation-duration: 500s;
+ visibility: hidden;
+}
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div id=target>This is text</div>
+<div id=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-clip-path-ref.html b/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-clip-path-ref.html
new file mode 100644
index 0000000000..28e22b8ca2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-clip-path-ref.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<title>View transitions: object-view-box with larger overflow (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.target {
+ color: red;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: relative;
+ top: 50px;
+ left: 50px;
+}
+.child {
+ width: 123px;
+ height: 150px;
+ background: lightblue;
+ position: relative;
+ top: -10px;
+ left: -20px;
+}
+.grandchild {
+ width: 25px;
+ height: 25px;
+ position: relative;
+ top: 20px;
+ left: 40px;
+ background: green;
+}
+#one { clip-path: inset(10px 12px 20px 28px); }
+#two { clip-path: inset(10px -12px 20px -28px); }
+body { background: lightpink; }
+</style>
+
+<div id=one class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+<div style="height: 20px;"></div>
+<div id=two class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-clip-path-reference-ref.html b/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-clip-path-reference-ref.html
new file mode 100644
index 0000000000..b1871141c2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-clip-path-reference-ref.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<title>View transitions: object-view-box with larger overflow (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.target {
+ color: red;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: relative;
+ top: 50px;
+ left: 50px;
+}
+.child {
+ width: 123px;
+ height: 150px;
+ background: lightblue;
+ position: relative;
+ top: -10px;
+ left: -20px;
+}
+.grandchild {
+ width: 25px;
+ height: 25px;
+ position: relative;
+ top: 20px;
+ left: 40px;
+ background: green;
+}
+#one { clip-path: url(#clip1); }
+#two { clip-path: url(#clip2); }
+body { background: lightpink; }
+</style>
+
+<div id=one class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+<div style="height: 20px;"></div>
+<div id=two class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+
+<svg>
+ <defs>
+ <clipPath id="clip1">
+ <rect x="10" y="20" width="70" height="50" />
+ </clipPath>
+ <clipPath id="clip2">
+ <rect x="-10" y="20" width="130" height="50" />
+ </clipPath>
+ </defs>
+</svg>
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-clip-path-reference.html b/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-clip-path-reference.html
new file mode 100644
index 0000000000..14a1ee83d9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-clip-path-reference.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: object-view-box with larger clip-path</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="old-content-object-view-box-clip-path-reference-ref.html">
+<meta name="fuzzy" content="old-content-object-view-box-clip-path-reference-ref.html:0-1;0-100">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ color: red;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ overflow-clip-margin: 1000px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+}
+.child {
+ width: 123px;
+ height: 150px;
+ background: lightblue;
+ position: relative;
+ top: -10px;
+ left: -20px;
+}
+.grandchild {
+ width: 25px;
+ height: 25px;
+ position: relative;
+ top: 20px;
+ left: 40px;
+ background: green;
+}
+#one {
+ view-transition-name: target-one;
+ clip-path: url(#clip1);
+}
+#two {
+ view-transition-name: target-two;
+ clip-path: url(#clip2)
+}
+
+html::view-transition-group(target-one),
+html::view-transition-group(target-two) { animation-duration: 300s; }
+html::view-transition-new(target-one),
+html::view-transition-new(target-two) { animation: unset; opacity: 0; height: 100%; }
+html::view-transition-old(target-one),
+html::view-transition-old(target-two) {
+ animation: unset;
+ opacity: 1;
+ /* clip overflow, and verify inner contents only */
+ overflow: hidden;
+ height: 100%;
+}
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div id=one class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+<div style="height: 20px;"></div>
+<div id=two class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+
+<svg>
+ <defs>
+ <clipPath id="clip1">
+ <rect x="10" y="20" width="70" height="50" />
+ </clipPath>
+ <clipPath id="clip2">
+ <rect x="-10" y="20" width="130" height="50" />
+ </clipPath>
+ </defs>
+</svg>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-clip-path.html b/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-clip-path.html
new file mode 100644
index 0000000000..dff57c68f6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-clip-path.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: object-view-box with larger clip-path</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="old-content-object-view-box-clip-path-ref.html">
+<meta name="fuzzy" content="old-content-object-view-box-clip-path-ref.html:0-1;0-30">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ color: red;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ overflow-clip-margin: 1000px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+}
+.child {
+ width: 123px;
+ height: 150px;
+ background: lightblue;
+ position: relative;
+ top: -10px;
+ left: -20px;
+}
+.grandchild {
+ width: 25px;
+ height: 25px;
+ position: relative;
+ top: 20px;
+ left: 40px;
+ background: green;
+}
+#one {
+ view-transition-name: target-one;
+ clip-path: inset(10px 12px 20px 28px);
+}
+#two {
+ view-transition-name: target-two;
+ clip-path: inset(10px -12px 20px -28px);
+}
+
+html::view-transition-group(target-one),
+html::view-transition-group(target-two) { animation-duration: 300s; }
+html::view-transition-new(target-one),
+html::view-transition-new(target-two) { animation: unset; opacity: 0; height: 100%; }
+html::view-transition-old(target-one),
+html::view-transition-old(target-two) {
+ animation: unset;
+ opacity: 1;
+ /* clip overflow, and verify inner contents only */
+ overflow: hidden;
+ height: 100%;
+}
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div id=one class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+<div style="height: 20px;"></div>
+<div id=two class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-overflow-ref.html b/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-overflow-ref.html
new file mode 100644
index 0000000000..d6016c950e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-overflow-ref.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>View transitions: object-view-box with larger overflow (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.target {
+ color: red;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: relative;
+ top: 50px;
+ left: 50px;
+}
+.child {
+ width: 123px;
+ height: 150px;
+ background: lightblue;
+ position: relative;
+ top: -10px;
+ left: -20px;
+}
+.grandchild {
+ width: 25px;
+ height: 25px;
+ position: relative;
+ top: 20px;
+ left: 40px;
+ background: green;
+}
+body { background: lightpink; }
+</style>
+
+<div class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-overflow.html b/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-overflow.html
new file mode 100644
index 0000000000..ff9bb4e7d2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-object-view-box-overflow.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: object-view-box with larger overflow</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="old-content-object-view-box-overflow-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ color: red;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ overflow-clip-margin: 1000px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+ view-transition-name: target;
+}
+.child {
+ width: 123px;
+ height: 150px;
+ background: lightblue;
+ position: relative;
+ top: -10px;
+ left: -20px;
+}
+.grandchild {
+ width: 25px;
+ height: 25px;
+ position: relative;
+ top: 20px;
+ left: 40px;
+ background: green;
+}
+
+html::view-transition-group(target) { animation-duration: 300s; }
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 1;
+ /* clip overflow, and verify inner contents only */
+ overflow: hidden;
+ height: 100%;
+}
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div class=target>
+ <div class=child>
+ <div class=grandchild></div>
+ </div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-with-object-view-box.html b/testing/web-platform/tests/css/css-view-transitions/old-content-with-object-view-box.html
new file mode 100644
index 0000000000..f24c8e60d1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-with-object-view-box.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<html class=reftest-wait>
+<title>View transitions: capture elements with object view box on the pseudo</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="content-with-object-view-box-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#target {
+ position: relative;
+ top: 100px;
+ left: 100px;
+ background: green;
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+}
+
+html::view-transition-group(*) { animation-duration: 300s; }
+html::view-transition-old(*) {
+ object-view-box: inset(5px 10px 15px 20px);
+ /* Need to specify explicit dimensions since view box changes intrinsic size */
+ width: 100px;
+ height: 100px;
+ animation: unset;
+ opacity: 1;
+}
+html::view-transition-new(*) { animation: unset; opacity: 0; }
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: pink; }
+</style>
+<div id=target></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition().ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-with-overflow-zoomed.html b/testing/web-platform/tests/css/css-view-transitions/old-content-with-overflow-zoomed.html
new file mode 100644
index 0000000000..10257b761f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-with-overflow-zoomed.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: shared element with overflow</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="content-with-overflow-zoomed-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ width: 80px;
+ height: 80px;
+ contain: paint;
+ background: blue;
+ overflow-clip-margin: 50px;
+ view-transition-name: target;
+ zoom: 1.5;
+}
+.child {
+ width: 200px;
+ height: 200px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+ background: green;
+ zoom: 1.2;
+}
+
+html::view-transition-group(target) { animation-duration: 300s; }
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 1;
+ border: 3px solid black;
+}
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div class=ancestor>
+ <div class=target>
+ <div class=child>
+ </div>
+ </div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-content-with-overflow.html b/testing/web-platform/tests/css/css-view-transitions/old-content-with-overflow.html
new file mode 100644
index 0000000000..6ed31d375c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-content-with-overflow.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: shared element with overflow</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="content-with-overflow-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ background: blue;
+ overflow-clip-margin: 50px;
+ view-transition-name: target;
+}
+.child {
+ width: 200px;
+ height: 200px;
+ position: relative;
+ top: 50px;
+ left: 50px;
+ background: green;
+}
+
+html::view-transition-group(target) { animation-duration: 300s; }
+html::view-transition-new(target) { animation: unset; opacity: 0; }
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 1;
+}
+
+html::view-transition-group(root) { animation: unset; opacity: 0; }
+html::view-transition { background: lightpink; }
+</style>
+
+<div class=target>
+ <div class=child>
+ </div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-root-vertical-writing-mode-ref.html b/testing/web-platform/tests/css/css-view-transitions/old-root-vertical-writing-mode-ref.html
new file mode 100644
index 0000000000..bb4f2df0f8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-root-vertical-writing-mode-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>View transitions: container of shared element writing-modes (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+html { writing-mode: vertical-lr; }
+.shared {
+ margin: 2px;
+ width: 90px;
+ height: 50px;
+ background: green;
+ contain: paint;
+}
+#two {
+ background: lightblue;
+ will-change: transform;
+}
+</style>
+
+<div id=one class=shared>T</div>
+<div id=two class=shared></div>
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/old-root-vertical-writing-mode.html b/testing/web-platform/tests/css/css-view-transitions/old-root-vertical-writing-mode.html
new file mode 100644
index 0000000000..5f4425f64d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/old-root-vertical-writing-mode.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: container of shared element writing-modes</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="new-root-vertical-writing-mode-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+html { writing-mode: vertical-lr; }
+#hidden {
+ width: 100px;
+ height: 100px;
+ background: red;
+ position: absolute;
+ top: 0;
+ left: 0;
+ contain: paint;
+ view-transition-name: hidden;
+}
+.shared {
+ margin: 2px;
+ width: 90px;
+ height: 50px;
+ background: green;
+ contain: paint;
+}
+#target {
+ background: red;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+ width: 100px;
+ height: 500px;
+ contain: paint;
+}
+#one { view-transition-name: s1; }
+#two {
+ background: lightblue;
+ will-change: transform;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(s1) { animation-delay: 100s; animation-fill-mode: both; }
+html::view-transition-new(s1) { animation: unset; opacity: 0; }
+html::view-transition-old(s1) { animation: unset; opacity: 1; }
+
+html::view-transition-new(root) { animation: unset; opacity: 0; }
+html::view-transition-old(root) { animation: unset; opacity: 1; }
+
+</style>
+
+<div id=hidden>Should not be visible</div>
+<div id=target style="display: none">Should not be visible</div>
+<div id=one class=shared>T</div>
+<div id=two class=shared></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ one.remove();
+ target.style = "";
+ target.style.viewTransitionName = "s1";
+ hidden.style.left = "200px";
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
+
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/only-child-group.html b/testing/web-platform/tests/css/css-view-transitions/only-child-group.html
new file mode 100644
index 0000000000..05275a3448
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/only-child-group.html
@@ -0,0 +1,117 @@
+<!DOCTYPE html>
+<html class="reftest-wait foo">
+<title>View transitions: ensure :only-child is supported on view-transition-group</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+::view-transition {
+ background-color: black;
+}
+html:only-child {
+ background-color: black;
+}
+:root:only-child {
+ background-color: black;
+}
+:only-child {
+ background-color: black;
+}
+.foo:only-child {
+ background-color: black;
+}
+
+::view-transition-group(root) {
+ background-color: blue;
+}
+::view-transition-group(target) {
+ background-color: blue;
+}
+::view-transition-group(*) {
+ color: blue;
+}
+
+::view-transition-group(root):only-child {
+ background-color: red;
+}
+::view-transition-group(target):only-child {
+ background-color: red;
+}
+::view-transition-group(*):only-child {
+ color: red;
+}
+
+</style>
+<div id="target"></div>
+<div id="target2"></div>
+
+<script>
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ let transition = document.startViewTransition();
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-group(root)");
+ if (style.backgroundColor == "rgb(255, 0, 0)" && style.color == "rgb(255, 0, 0)")
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should match because ::view-transition-group is generated for root element only");
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ target.style.viewTransitionName = "target";
+ let transition = document.startViewTransition();
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-group(root)");
+ if (style.backgroundColor == "rgb(0, 0, 255)" && style.color == "rgb(0, 0, 255)")
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should not match because ::view-transition-group is generated for multiple elements");
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ document.documentElement.style.viewTransitionName = "none";
+ target.style.viewTransitionName = "target";
+ let transition = document.startViewTransition();
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-group(target)");
+ if (style.backgroundColor == "rgb(255, 0, 0)" && style.color == "rgb(255, 0, 0)")
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should match because ::view-transition-group is generated for sub element only");
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ document.documentElement.style.viewTransitionName = "none";
+ target.style.viewTransitionName = "target";
+ target2.style.viewTransitionName = "target2";
+ let transition = document.startViewTransition();
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-group(target)");
+ if (style.backgroundColor == "rgb(0, 0, 255)" && style.color == "rgb(0, 0, 255)")
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should not match because ::view-transition-group is generated for multiple sub elements");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/only-child-image-pair.html b/testing/web-platform/tests/css/css-view-transitions/only-child-image-pair.html
new file mode 100644
index 0000000000..288d496346
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/only-child-image-pair.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html class="reftest-wait foo">
+<title>View transitions: ensure :only-child is supported on view-transition-image-pair</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+::view-transition {
+ background-color: black;
+}
+html:only-child {
+ background-color: black;
+}
+:root:only-child {
+ background-color: black;
+}
+:only-child {
+ background-color: black;
+}
+.foo:only-child {
+ background-color: black;
+}
+
+::view-transition-image-pair(root):only-child {
+ background-color: red;
+}
+::view-transition-image-pair(*):only-child {
+ color: red;
+}
+</style>
+
+<script>
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ let transition = document.startViewTransition();
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-image-pair(root)");
+ if (style.backgroundColor == "rgb(255, 0, 0)" && style.color == "rgb(255, 0, 0)")
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should always match for ::view-transition-image-pair");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/only-child-new.html b/testing/web-platform/tests/css/css-view-transitions/only-child-new.html
new file mode 100644
index 0000000000..9f36528219
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/only-child-new.html
@@ -0,0 +1,171 @@
+<!DOCTYPE html>
+<html class="reftest-wait foo">
+<title>View transitions: ensure :only-child is supported on view-transition-new</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+::view-transition {
+ background-color: black;
+}
+html:only-child {
+ background-color: black;
+}
+:root:only-child {
+ background-color: black;
+}
+:only-child {
+ background-color: black;
+}
+.foo:only-child {
+ background-color: black;
+}
+
+::view-transition-new(root) {
+ background-color: blue;
+}
+::view-transition-new(target) {
+ background-color: blue;
+}
+::view-transition-new(*) {
+ color: blue;
+}
+
+::view-transition-new(root):only-child {
+ background-color: red;
+}
+::view-transition-new(target):only-child {
+ background-color: red;
+}
+::view-transition-new(*):only-child {
+ color: red;
+}
+
+</style>
+<div id="target"></div>
+
+<script>
+let matchedColor = "rgb(255, 0, 0)";
+let notMatchedColor = "rgb(0, 0, 255)";
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ document.documentElement.style.viewTransitionName = "none";
+ target.style.viewTransitionName = "none";
+ let transition = document.startViewTransition(() => {
+ document.documentElement.style.viewTransitionName = "root";
+ });
+
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-new(root)");
+ if (style.backgroundColor == matchedColor && style.color == matchedColor)
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should match because ::view-transition-old is not generated (none to root)");
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ document.documentElement.style.viewTransitionName = "root";
+ target.style.viewTransitionName = "none";
+ let transition = document.startViewTransition();
+
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-new(root)");
+ if (style.backgroundColor == notMatchedColor && style.color == notMatchedColor)
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should not match because ::view-transition-old is generated (root to root)");
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ document.documentElement.style.viewTransitionName = "none";
+ target.style.viewTransitionName = "root";
+ let transition = document.startViewTransition(() => {
+ document.documentElement.style.viewTransitionName = "root";
+ target.style.viewTransitionName = "none";
+ });
+
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-new(root)");
+ if (style.backgroundColor == notMatchedColor && style.color == notMatchedColor)
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should not match because ::view-transition-old is generated (element to root)");
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ target.style.viewTransitionName = "none";
+ document.documentElement.style.viewTransitionName = "none";
+ let transition = document.startViewTransition(() => {
+ target.style.viewTransitionName = "target";
+ });
+
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-new(target)");
+ if (style.backgroundColor == matchedColor && style.color == matchedColor)
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should match because ::view-transition-old is not generated (none to element)");
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ target.style.viewTransitionName = "none";
+ document.documentElement.style.viewTransitionName = "root";
+ let transition = document.startViewTransition(() => {
+ document.documentElement.style.viewTransitionName = "none";
+ target.style.viewTransitionName = "element";
+ });
+
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-new(root)");
+ if (style.backgroundColor == notMatchedColor && style.color == notMatchedColor)
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should not match because ::view-transition-old is generated (root to element)");
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ target.style.viewTransitionName = "target";
+ document.documentElement.style.viewTransitionName = "none";
+ let transition = document.startViewTransition();
+
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-new(target)");
+ if (style.backgroundColor == notMatchedColor && style.color == notMatchedColor)
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should not match because ::view-transition-old is generated (element to element)");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/only-child-no-transition.html b/testing/web-platform/tests/css/css-view-transitions/only-child-no-transition.html
new file mode 100644
index 0000000000..7dc2bf1217
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/only-child-no-transition.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: :only-child style queries without transition shouldn't crash</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+::view-transition:only-child,
+::view-transition-group(*):only-child,
+::view-transition-image-pair(*):only-child,
+::view-transition-old(*):only-child,
+::view-transition-new(*):only-child {
+ background-color: blue;
+}
+</style>
+
+<script>
+promise_test(() => {
+ return new Promise(async (resolve, reject) => {
+ let elements = [
+ "view-transition",
+ "view-transition-group(foo)",
+ "view-transition-image-pair(foo)",
+ "view-transition-old(foo)",
+ "view-transition-old(foo)"
+ ];
+
+ for (let i = 0; i < elements.length; i++) {
+ let style = window.getComputedStyle(document.documentElement, elements[i]);
+ if (style.backgroundColor == "rgb(0, 0, 255")
+ reject();
+ }
+ resolve();
+ });
+}, ":only-child style queries without transition shouldn't crash");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/only-child-old.html b/testing/web-platform/tests/css/css-view-transitions/only-child-old.html
new file mode 100644
index 0000000000..7a55af7397
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/only-child-old.html
@@ -0,0 +1,171 @@
+<!DOCTYPE html>
+<html class="reftest-wait foo">
+<title>View transitions: ensure :only-child is supported on view-transition-old</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+::view-transition {
+ background-color: black;
+}
+html:only-child {
+ background-color: black;
+}
+:root:only-child {
+ background-color: black;
+}
+:only-child {
+ background-color: black;
+}
+.foo:only-child {
+ background-color: black;
+}
+
+::view-transition-old(root) {
+ background-color: blue;
+}
+::view-transition-old(target) {
+ background-color: blue;
+}
+::view-transition-old(*) {
+ color: blue;
+}
+
+::view-transition-old(root):only-child {
+ background-color: red;
+}
+::view-transition-old(target):only-child {
+ background-color: red;
+}
+::view-transition-old(*):only-child {
+ color: red;
+}
+
+</style>
+<div id="target"></div>
+
+<script>
+let matchedColor = "rgb(255, 0, 0)";
+let notMatchedColor = "rgb(0, 0, 255)";
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ document.documentElement.style.viewTransitionName = "root";
+ target.style.viewTransitionName = "none";
+ let transition = document.startViewTransition(() => {
+ document.documentElement.style.viewTransitionName = "none";
+ });
+
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-old(root)");
+ if (style.backgroundColor == matchedColor && style.color == matchedColor)
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should match because ::view-transition-new is not generated (root to none)");
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ document.documentElement.style.viewTransitionName = "root";
+ target.style.viewTransitionName = "none";
+ let transition = document.startViewTransition();
+
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-old(root)");
+ if (style.backgroundColor == notMatchedColor && style.color == notMatchedColor)
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should not match because ::view-transition-new is generated (root to root)");
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ document.documentElement.style.viewTransitionName = "root";
+ target.style.viewTransitionName = "none";
+ let transition = document.startViewTransition(() => {
+ document.documentElement.style.viewTransitionName = "none";
+ target.style.viewTransitionName = "root";
+ });
+
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-old(root)");
+ if (style.backgroundColor == notMatchedColor && style.color == notMatchedColor)
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should not match because ::view-transition-new is generated (root to element)");
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ target.style.viewTransitionName = "target";
+ document.documentElement.style.viewTransitionName = "none";
+ let transition = document.startViewTransition(() => {
+ target.style.viewTransitionName = "none";
+ });
+
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-old(target)");
+ if (style.backgroundColor == matchedColor && style.color == matchedColor)
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should match because ::view-transition-new is not generated (element to none)");
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ target.style.viewTransitionName = "root";
+ document.documentElement.style.viewTransitionName = "none";
+ let transition = document.startViewTransition(() => {
+ document.documentElement.style.viewTransitionName = "root";
+ target.style.viewTransitionName = "none";
+ });
+
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-old(root)");
+ if (style.backgroundColor == notMatchedColor && style.color == notMatchedColor)
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should not match because ::view-transition-new is generated (element to root)");
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ target.style.viewTransitionName = "target";
+ document.documentElement.style.viewTransitionName = "none";
+ let transition = document.startViewTransition();
+
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, ":view-transition-old(target)");
+ if (style.backgroundColor == notMatchedColor && style.color == notMatchedColor)
+ resolve();
+ else
+ reject(style.backgroundColor + " and " + style.color);
+ });
+ });
+}, ":only-child should not match because ::view-transition-new is generated (element to element)");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/only-child-on-root-element-with-view-transition.html b/testing/web-platform/tests/css/css-view-transitions/only-child-on-root-element-with-view-transition.html
new file mode 100644
index 0000000000..8b81c35ff6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/only-child-on-root-element-with-view-transition.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html class="reftest-wait foo">
+<title>View transitions: ensure :only-child is supported on view-transition</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+::view-transition {
+ background-color: red;
+}
+
+html:only-child {
+ background-color: blue;
+}
+
+:root:only-child {
+ background-color: blue;
+}
+
+:only-child {
+ background-color: blue;
+}
+
+.foo:only-child {
+ background-color: blue;
+}
+</style>
+
+<script>
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ let transition = document.startViewTransition();
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, "::view-transition");
+ if (style.backgroundColor == "rgb(255, 0, 0)")
+ resolve();
+ else
+ reject(style.backgroundColor);
+ });
+ });
+}, ":only-child is not supported on view-transition");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/only-child-view-transition.html b/testing/web-platform/tests/css/css-view-transitions/only-child-view-transition.html
new file mode 100644
index 0000000000..2089e9225e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/only-child-view-transition.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: ensure :only-child is supported on view-transition</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+::view-transition {
+ background-color: red;
+}
+::view-transition:only-child {
+ background-color: blue;
+}
+</style>
+
+<script>
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ let transition = document.startViewTransition();
+ transition.ready.then(() => {
+ let style = getComputedStyle(
+ document.documentElement, "::view-transition");
+ if (style.backgroundColor == "rgb(255, 0, 0)")
+ resolve();
+ else
+ reject(style.backgroundColor);
+ });
+ });
+}, ":only-child is not supported on view-transition");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/parsing/pseudo-elements-invalid-with-classes.html b/testing/web-platform/tests/css/css-view-transitions/parsing/pseudo-elements-invalid-with-classes.html
new file mode 100644
index 0000000000..66443c5cd7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/parsing/pseudo-elements-invalid-with-classes.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Test pseudo elements parsing of invalid selectors with classes</title>
+<link rel="author" href="https://github.com/noamr">
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script>
+const functionPseudoElements = [
+ "::view-transition-group",
+ "::view-transition-image-pair",
+ "::view-transition-old",
+ "::view-transition-new",
+];
+
+function test_invalid_selector_combinations(pseudo) {
+ test_invalid_selector(`${pseudo}.a`);
+ test_invalid_selector(`${pseudo} div`);
+ test_invalid_selector(`${pseudo}:hover`);
+ test_invalid_selector(`:not(${pseudo})`);
+ test_invalid_selector(`:has(${pseudo})`);
+}
+
+for (const fn of functionPseudoElements) {
+ test_invalid_selector(`${fn}(*.*)`);
+ test_invalid_selector(`${fn}(*. cls)`);
+ test_invalid_selector(`${fn}(*.cls. c)`);
+ test_invalid_selector(`${fn}(*.cls>cls)`);
+ test_invalid_selector(`${fn}(*.cls.foo.*)`);
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/parsing/pseudo-elements-invalid.html b/testing/web-platform/tests/css/css-view-transitions/parsing/pseudo-elements-invalid.html
new file mode 100644
index 0000000000..5a2624d09d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/parsing/pseudo-elements-invalid.html
@@ -0,0 +1,69 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Test pseudo elements parsing of invalid selectors</title>
+<link rel="author" href="https://github.com/nt1m">
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script>
+const functionPseudoElements = [
+ "::view-transition-group",
+ "::view-transition-image-pair",
+ "::view-transition-old",
+ "::view-transition-new",
+];
+
+function test_invalid_selector_combinations(pseudo) {
+ test_invalid_selector(`${pseudo}.a`);
+ test_invalid_selector(`${pseudo} div`);
+ test_invalid_selector(`${pseudo}:hover`);
+ test_invalid_selector(`:not(${pseudo})`);
+ test_invalid_selector(`:has(${pseudo})`);
+}
+
+test_invalid_selector_combinations("::view-transition");
+test_invalid_selector("::view-transition(*)");
+test_invalid_selector("::view-transition(valid)");
+test_invalid_selector("::view-transition(root)");
+
+for (const fn of functionPseudoElements) {
+ for (const validArgument of ["*", "valid", "root"]) {
+ test_invalid_selector_combinations(`${fn}(${validArgument})`);
+ }
+
+ // Test function without argument.
+ test_invalid_selector(fn);
+ test_invalid_selector_combinations(fn);
+
+ // Test function with empty argument.
+ test_invalid_selector(`${fn}()`);
+ test_invalid_selector_combinations(`${fn}()`);
+
+ // Test function with keywords excluded from <custom-ident>.
+ test_invalid_selector(`${fn}(default)`);
+ test_invalid_selector_combinations(`${fn}(default)`);
+ test_invalid_selector(`${fn}(unset)`);
+ test_invalid_selector_combinations(`${fn}(unset)`);
+ test_invalid_selector(`${fn}(initial)`);
+ test_invalid_selector_combinations(`${fn}(initial)`);
+ test_invalid_selector(`${fn}(inherit)`);
+ test_invalid_selector_combinations(`${fn}(inherit)`);
+ test_invalid_selector(`${fn}(revert)`);
+ test_invalid_selector_combinations(`${fn}(revert)`);
+ test_invalid_selector(`${fn}(revert-layer)`);
+ test_invalid_selector_combinations(`${fn}(revert-layer)`);
+
+ // Test function with multiple arguments.
+ test_invalid_selector(`${fn}(foo, bar)`);
+ test_invalid_selector_combinations(`${fn}(foo, bar)`);
+ test_invalid_selector(`${fn}(foo bar)`);
+ test_invalid_selector_combinations(`${fn}(foo bar)`);
+
+ // Test function with selector arguments.
+ test_invalid_selector(`${fn}(.foo)`);
+ test_invalid_selector_combinations(`${fn}(.foo)`);
+ test_invalid_selector(`${fn}(#bar)`);
+ test_invalid_selector_combinations(`${fn}(#bar)`);
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/parsing/pseudo-elements-valid-with-classes.html b/testing/web-platform/tests/css/css-view-transitions/parsing/pseudo-elements-valid-with-classes.html
new file mode 100644
index 0000000000..8ddf2e28d6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/parsing/pseudo-elements-valid-with-classes.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Test pseudo elements parsing of valid selectors including classes</title>
+<link rel="author" href="https://github.com/nrosenthal">
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-2/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script>
+const functionPseudoElements = [
+ "::view-transition-group",
+ "::view-transition-image-pair",
+ "::view-transition-old",
+ "::view-transition-new",
+];
+
+function test_valid_selector_combinations(pseudo) {
+ test_valid_selector(pseudo);
+ test_valid_selector(`:root${pseudo}`);
+ test_valid_selector(`.a${pseudo}`);
+ test_valid_selector(`div ${pseudo}`);
+}
+
+test_valid_selector_combinations("::view-transition");
+
+for (const functionName of functionPseudoElements) {
+ for (const validArgument of
+ ["*.class", "*.class.class", "dashed-ident.someclass", "dash-id.dash-id", "foo.bar.baz"]) {
+ test_valid_selector_combinations(`${functionName}(${validArgument})`);
+ test_valid_selector_combinations(`${functionName}(${validArgument}):only-child`);
+ }
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/parsing/pseudo-elements-valid.html b/testing/web-platform/tests/css/css-view-transitions/parsing/pseudo-elements-valid.html
new file mode 100644
index 0000000000..1a0e5b82d3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/parsing/pseudo-elements-valid.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Test pseudo elements parsing of valid selectors</title>
+<link rel="author" href="https://github.com/nt1m">
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script>
+const functionPseudoElements = [
+ "::view-transition-group",
+ "::view-transition-image-pair",
+ "::view-transition-old",
+ "::view-transition-new",
+];
+
+function test_valid_selector_combinations(pseudo) {
+ test_valid_selector(pseudo);
+ test_valid_selector(`:root${pseudo}`);
+ test_valid_selector(`.a${pseudo}`);
+ test_valid_selector(`div ${pseudo}`);
+}
+
+test_valid_selector_combinations("::view-transition");
+
+for (const functionName of functionPseudoElements) {
+ for (const validArgument of ["*", "root", "dashed-ident"]) {
+ test_valid_selector_combinations(`${functionName}(${validArgument})`);
+ test_valid_selector_combinations(`${functionName}(${validArgument}):only-child`);
+ }
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-class-computed.html b/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-class-computed.html
new file mode 100644
index 0000000000..74151c46da
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-class-computed.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS View Transitions: view-transition-class with computed values</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<meta name="assert" content="view-transition-class supports custom keywords.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id=target></div>
+<script>
+test_computed_value("view-transition-class", "none");
+test_computed_value("view-transition-class", "foo");
+test_computed_value("view-transition-class", "bar");
+test_computed_value("view-transition-class", "baz");
+test_computed_value("view-transition-class", "foo bar");
+test_computed_value("view-transition-class", "foo bar baz");
+test_computed_value("view-transition-class", "unset", "none");
+test_computed_value("view-transition-class", "initial", "none");
+test_computed_value("view-transition-class", "inherit", "none");
+test_computed_value("view-transition-class", "revert", "none");
+test_computed_value("view-transition-class", "revert-layer", "none");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-class-invalid.html b/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-class-invalid.html
new file mode 100644
index 0000000000..9d41589bf2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-class-invalid.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS View Transitions Test: view-transition-class with invalid values</title>
+<link rel="author" title="Tim Nguyen" href="https://github.com/nt1m">
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<meta name="assert" content="view-transition-class does not support invalid values">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value("view-transition-class", "default"); // `default` isn't allowed by the `<custom-ident>` syntax.
+test_invalid_value("view-transition-class", "foo none");
+test_invalid_value("view-transition-class", "#fff");
+test_invalid_value("view-transition-class", "12px");
+test_invalid_value("view-transition-class", "foo 12px");
+test_invalid_value("view-transition-class", "12em");
+test_invalid_value("view-transition-class", "12%");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-class-valid.html b/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-class-valid.html
new file mode 100644
index 0000000000..480f40ca16
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-class-valid.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS View Transitions Test: view-transition-class with valid values</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<meta name="assert" content="view-transition-class supports custom tags">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value("view-transition-class", "none");
+test_valid_value("view-transition-class", "foo");
+test_valid_value("view-transition-class", "bar");
+test_valid_value("view-transition-class", "baz");
+test_valid_value("view-transition-class", "foo bar");
+test_valid_value("view-transition-class", "foo bar baz");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-name-computed.html b/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-name-computed.html
new file mode 100644
index 0000000000..5b05667f74
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-name-computed.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS View Transitions: view-transition-name with computed values</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<meta name="assert" content="view-transition-name supports custom keywords.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id=target></div>
+<script>
+test_computed_value("view-transition-name", "none");
+test_computed_value("view-transition-name", "foo");
+test_computed_value("view-transition-name", "bar");
+test_computed_value("view-transition-name", "baz");
+test_computed_value("view-transition-name", "unset", "none");
+test_computed_value("view-transition-name", "initial", "none");
+test_computed_value("view-transition-name", "inherit", "none");
+test_computed_value("view-transition-name", "revert", "none");
+test_computed_value("view-transition-name", "revert-layer", "none");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-name-invalid.html b/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-name-invalid.html
new file mode 100644
index 0000000000..00cd411d6a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-name-invalid.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS View Transitions Test: view-transition-name with invalid values</title>
+<link rel="author" title="Tim Nguyen" href="https://github.com/nt1m">
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<meta name="assert" content="view-transition-name does not support invalid values">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value("view-transition-name", "auto"); // `auto` is excluded.
+test_invalid_value("view-transition-name", "default"); // `default` isn't allowed by the `<custom-ident>` syntax.
+test_invalid_value("view-transition-name", "none none");
+test_invalid_value("view-transition-name", `"none"`);
+test_invalid_value("view-transition-name", `"foo"`);
+test_invalid_value("view-transition-name", "foo foo");
+test_invalid_value("view-transition-name", "bar bar");
+test_invalid_value("view-transition-name", "baz baz");
+test_invalid_value("view-transition-name", "#fff");
+test_invalid_value("view-transition-name", "12px");
+test_invalid_value("view-transition-name", "12em");
+test_invalid_value("view-transition-name", "12%");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-name-valid.html b/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-name-valid.html
new file mode 100644
index 0000000000..2fd384449f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/parsing/view-transition-name-valid.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS View Transitions Test: view-transition-name with valid values</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<meta name="assert" content="view-transition-name supports custom tags">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value("view-transition-name", "none");
+test_valid_value("view-transition-name", "foo");
+test_valid_value("view-transition-name", "bar");
+test_valid_value("view-transition-name", "baz");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/paused-animation-at-end.html b/testing/web-platform/tests/css/css-view-transitions/paused-animation-at-end.html
new file mode 100644
index 0000000000..ae9176ea26
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/paused-animation-at-end.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<title>View transitions: pause animation and set current time to the end</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+:root { view-transition-name: unset; }
+#target {
+ width: 100px;
+ height: 100px;
+ view-transition-name: target;
+}
+.one {
+ background: blue;
+}
+.two {
+ background: green;
+}
+</style>
+
+<div id=target class=one></div>
+
+<script>
+promise_test(async (t) => {
+ return new Promise((resolve, reject) => {
+ let transition = document.startViewTransition(() => {
+ target.classList.replace("one", "two");
+ });
+
+ transition.finished.then(() => reject("transition unexpectedly finished"));
+ transition.ready.then(() => {
+ document.getAnimations().forEach((animation) => {
+ animation.pause();
+ animation.currentTime = 1000;
+ });
+ step_timeout(resolve, 500);
+ });
+ });
+}, "view transition is not over if animations are paused");
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-computed-style-stays-in-sync-with-new-element.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-computed-style-stays-in-sync-with-new-element.html
new file mode 100644
index 0000000000..0a34a4b73f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-computed-style-stays-in-sync-with-new-element.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: computed style on pseudo-element stays in sync with the DOM element</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ view-transition-name: target;
+ contain: paint;
+}
+</style>
+
+<div id=first></div>
+
+<script>
+promise_test(async t => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ let transition = document.startViewTransition();
+ await transition.updateCallbackDone;
+ await transition.ready;
+
+ let viewbox = window.getComputedStyle(
+ document.documentElement, "::view-transition-new(target)").objectViewBox;
+ assert_equals(viewbox, "none", "incorrect viewbox " + viewbox);
+
+ first.style.filter = "blur(5px)";
+ viewbox = window.getComputedStyle(
+ document.documentElement, "::view-transition-new(target)").objectViewBox;
+ assert_equals(viewbox, "none", "incorrect viewbox " + viewbox);
+
+ transition.finished.then(resolve, reject);
+ });
+}, "computed style on pseudo-element stays in sync with the DOM element");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-get-computed-style.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-get-computed-style.html
new file mode 100644
index 0000000000..2481a71313
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-get-computed-style.html
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: check pseudo element's display property</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ contain: paint;
+ view-transition-name: target;
+ mix-blend-mode: multiply;
+ text-orientation: upright;
+ color-scheme: dark light;
+}
+::view-transition-image-pair(target) {
+ position: fixed;
+}
+</style>
+
+<div id=target></div>
+
+<script>
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ let transition = document.startViewTransition(() => {
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition").position, "fixed", ":view-transition");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(target)").position, "absolute", "container(target)");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(target)").mixBlendMode, "multiply", "container(target)");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(target)").textOrientation, "upright", "container(target)");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(target)").colorScheme, "dark light", "container(target)");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-image-pair(target)").position, "absolute", "wrapper(target)");
+
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-old(target)").position, "absolute", "outgoing(target)");
+
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(root)").position, "absolute", "container(root)");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(root)").mixBlendMode, "normal", "container(root)");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-image-pair(root)").position, "absolute", "wrapper(root)");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-old(root)").position, "absolute", "outgoing(root)");
+
+ requestAnimationFrame(() => {
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition").position, "fixed", "raf :view-transition");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(target)").position, "absolute", "raf container(target)");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(target)").mixBlendMode, "multiply", "raf container(target)");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(target)").textOrientation, "upright", "raf container(target)");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(target)").colorScheme, "dark light", "raf container(target)");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-image-pair(target)").position, "fixed", "raf wrapper(target)");
+
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-old(target)").position, "absolute", "raf outgoing(target)");
+
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(root)").position, "absolute", "raf container(root)");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(root)").mixBlendMode, "normal", "raf container(root)");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-image-pair(root)").position, "absolute", "raf wrapper(root)");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-old(root)").position, "absolute", "raf outgoing(root)");
+ });
+ });
+ await transition.finished;
+ resolve();
+ });
+}, "position property of pseudo elements");
+
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ let transition = document.startViewTransition(() => {
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition").position, "fixed");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(target)").position, "absolute");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-image-pair(target)").position, "absolute");
+
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-old(target)").position, "absolute");
+
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(root)").position, "absolute");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-image-pair(root)").position, "absolute");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-old(root)").position, "absolute");
+
+ target.remove();
+ });
+
+ await transition.ready;
+
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition").position, "fixed");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(target)").position, "absolute");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(target)").mixBlendMode, "multiply");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(target)").textOrientation, "upright");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(target)").colorScheme, "dark light");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-image-pair(target)").position, "fixed");
+
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-old(target)").position, "absolute");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-new(target)").position, "absolute");
+
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(root)").position, "absolute");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-image-pair(root)").position, "absolute");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-old(root)").position, "absolute");
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-new(root)").position, "absolute");
+
+ assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(target)").position, "absolute");
+
+ await transition.finished;
+
+ // With custom ua sheets not applying to non-existing pseudo, the value should be the default (not absolute)
+ assert_not_equals(getComputedStyle(document.documentElement, ":view-transition-group(target)").position, "absolute");
+
+ resolve();
+ });
+}, "properties of pseudo elements outside of transition");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-rendering-invalidation-ref.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-rendering-invalidation-ref.html
new file mode 100644
index 0000000000..f622f94b5f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-rendering-invalidation-ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: invalidating VT pseudo elements renders correctly (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:bokan@chromium.org">
+
+<style>
+:root {
+ background-color: limegreen;
+}
+
+div {
+ position: absolute;
+ left: 0px;
+ top: 600px;
+ width: 100px;
+ height: 100px;
+
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+
+ background: darkseagreen;
+}
+</style>
+
+<div style="left: 0px; top: 100px;">Group</div>
+<div style="left: 150px; top: 100px;">Image-Pair</div>
+<div style="left: 0px; top: 250px;">Old</div>
+<div style="left: 150px; top: 250px;">New</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-rendering-invalidation.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-rendering-invalidation.html
new file mode 100644
index 0000000000..55a9d5d373
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-rendering-invalidation.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: invalidating VT pseudo elements renders correctly</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:bokan@chromium.org">
+<link rel="match" href="pseudo-rendering-invalidation-ref.html">
+<meta name="fuzzy" content="pseudo-rendering-invalidation-ref.html:0-20;0-300">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root {
+ view-transition-name: none;
+ background-color: red;
+}
+
+div {
+ position: absolute;
+ left: 0px;
+ top: 600px;
+ width: 100px;
+ height: 100px;
+
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+
+ background: darkseagreen;
+}
+
+::view-transition-group(*) {
+ animation-duration: 50s;
+}
+
+::view-transition {
+ background-color: limegreen;
+}
+
+::view-transition-new(new) {
+ animation: none;
+ opacity: 1;
+}
+::view-transition-old(new) {
+ animation: none;
+ opacity: 0;
+}
+
+::view-transition-new(old) {
+ animation: none;
+ opacity: 0;
+}
+::view-transition-old(old) {
+ animation: none;
+ opacity: 1;
+}
+
+.invalidateRoot::view-transition {
+ /* Making view-transition `display: none` will abort the transition. Changing
+ it to position: static (at least in Chrome) will cause it to rebuild its
+ layout tree. */
+ position: static;
+}
+
+.invalidateGroup::view-transition-group(group) {
+ display: none;
+}
+
+.invalidateImagePair::view-transition-image-pair(imagepair) {
+ display: none;
+}
+
+.invalidateNew::view-transition-new(new) {
+ display: none;
+}
+
+.invalidateOld::view-transition-old(old) {
+ display: none;
+}
+
+</style>
+
+<div style="left: 0px; top: 100px; view-transition-name:group;">Group</div>
+<div style="left: 150px; top: 100px; view-transition-name:imagepair;">Image-Pair</div>
+<div style="left: 0px; top: 250px; view-transition-name:old;">Old</div>
+<div style="left: 150px; top: 250px; view-transition-name:new;">New</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function rAF() {
+ return new Promise(resolve => requestAnimationFrame(resolve));
+}
+
+async function performInvalidations() {
+ await rAF();
+ await rAF();
+
+ const docClassList = document.documentElement.classList;
+ const classNames = [
+ 'invalidateRoot', // Invalidates ::view-transition
+ 'invalidateGroup', // Invalidates ::view-transition-group
+ 'invalidateImagePair', // Invalidates ::view-transition-image-pair
+ 'invalidateOld', // Invalidates ::view-transition-old
+ 'invalidateNew' // Invalidates ::view-transition-new
+ ];
+
+ for (let className of classNames) {
+ document.documentElement.classList.add(className);
+ await rAF();
+ document.documentElement.classList.remove(className);
+ await rAF();
+ }
+}
+
+// This test ensures each of the view-transition pseudos is able to be
+// individually recreated after becoming display: none.
+async function runTest() {
+ let transition = document.startViewTransition();
+ await transition.ready;
+ await performInvalidations();
+ takeScreenshot();
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-entry.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-entry.html
new file mode 100644
index 0000000000..44f95dccbf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-entry.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transition classes: entry animation should consider view-transition-class from new state</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/">
+<link rel="author" href="mailto:nrosenthal@chromium.org">
+<link rel="match" href="pseudo-with-classes-ref.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ position: absolute;
+}
+
+#target {
+ background: green;
+}
+
+#target.new-state {
+ view-transition-class: cls;
+ view-transition-name: target;
+}
+
+@keyframes jump {
+ from { opacity: 1;}
+ to { opacity: 1;}
+}
+
+::view-transition-group(*),
+::view-transition-image-pair(*),
+::view-transition-new(*) {
+ animation-name: jump;
+ animation-timing-function: step-start;
+ animation-duration: 1s;
+}
+
+::view-transition-new(*.cls) {
+ left: 100px;
+}
+
+</style>
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+window.addEventListener("load", () => {
+ document.startViewTransition(() => {
+ document.getElementById("target").classList.add("new-state");
+ }).ready.then(takeScreenshot);
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-exit.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-exit.html
new file mode 100644
index 0000000000..c687461f18
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-exit.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transition classes: exit animation should consider view-transition-class from old state</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/">
+<link rel="author" href="mailto:nrosenthal@chromium.org">
+<link rel="match" href="pseudo-with-classes-ref.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ position: absolute;
+}
+
+#target {
+ background: green;
+}
+
+#target:not(.new-state) {
+ view-transition-class: cls;
+ view-transition-name: target;
+}
+
+@keyframes jump {
+ from { opacity: 1;}
+ to { opacity: 1;}
+}
+
+::view-transition-group(*),
+::view-transition-image-pair(*),
+::view-transition-old(*) {
+ animation-name: jump;
+ animation-timing-function: step-start;
+ animation-duration: 1s;
+}
+
+::view-transition-old(*.cls) {
+ left: 100px;
+}
+
+</style>
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+window.addEventListener("load", () => {
+ document.startViewTransition(() => {
+ document.getElementById("target").classList.add("new-state");
+ }).ready.then(takeScreenshot);
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-match-ident.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-match-ident.html
new file mode 100644
index 0000000000..1418a90bc4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-match-ident.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transition classes: selector should match ident.class</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/">
+<link rel="author" href="mailto:nrosenthal@chromium.org">
+<link rel="match" href="pseudo-with-classes-ref.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ position: absolute;
+}
+
+#target {
+ background: green;
+ view-transition-name: target;
+ view-transition-class: cls;
+}
+
+::view-transition-group(*) {
+ animation-duration: 1s;
+}
+
+::view-transition-new(target.cls),
+::view-transition-old(target.cls) {
+ left: 100px;
+}
+
+</style>
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+window.addEventListener("load", () => {
+ document.startViewTransition().ready.then(takeScreenshot);
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-match-multiple-wildcard.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-match-multiple-wildcard.html
new file mode 100644
index 0000000000..53eaacfe79
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-match-multiple-wildcard.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transition classes: selector should match with wildcard and multiple classes</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/">
+<link rel="author" href="mailto:nrosenthal@chromium.org">
+<link rel="match" href="pseudo-with-classes-ref.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ position: absolute;
+}
+
+#target {
+ background: green;
+ view-transition-name: target;
+ view-transition-class: cls some-div;
+}
+
+::view-transition-group(*) {
+ animation-duration: 1s;
+}
+
+::view-transition-new(*.cls.some-div),
+::view-transition-old(*.cls.some-div) {
+ left: 100px;
+}
+
+</style>
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+window.addEventListener("load", () => {
+ document.startViewTransition().ready.then(takeScreenshot);
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-match-multiple.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-match-multiple.html
new file mode 100644
index 0000000000..1ab69340b4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-match-multiple.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transition classes: selector should match with multiple classes</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/">
+<link rel="author" href="mailto:nrosenthal@chromium.org">
+<link rel="match" href="pseudo-with-classes-ref.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ view-transition-class: cls some-div;
+}
+
+#target {
+ background: green;
+ view-transition-name: target;
+}
+
+::view-transition-group(*) {
+ animation-duration: 1s;
+}
+
+::view-transition-new(target.cls.some-div),
+::view-transition-old(target.cls.some-div) {
+ left: 100px;
+}
+
+</style>
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+window.addEventListener("load", () => {
+ document.startViewTransition().ready.then(takeScreenshot);
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-match-wildard.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-match-wildard.html
new file mode 100644
index 0000000000..13490d5878
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-match-wildard.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transition classes: selector should match with wildcard</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/">
+<link rel="author" href="mailto:nrosenthal@chromium.org">
+<link rel="match" href="pseudo-with-classes-ref.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ position: absolute;
+}
+
+#target {
+ background: green;
+ view-transition-name: target;
+ view-transition-class: cls;
+}
+
+::view-transition-group(*) {
+ animation-duration: 1s;
+}
+
+::view-transition-new(*.cls),
+::view-transition-old(*.cls) {
+ left: 100px;
+}
+
+</style>
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+window.addEventListener("load", () => {
+ document.startViewTransition().ready.then(takeScreenshot);
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-mismatch-ident.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-mismatch-ident.html
new file mode 100644
index 0000000000..97db64fca2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-mismatch-ident.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transition classes: selector should not match different ident</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/">
+<link rel="author" href="mailto:nrosenthal@chromium.org">
+<link rel="match" href="pseudo-with-classes-ref.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ position: absolute;
+}
+
+#target {
+ background: green;
+ view-transition-name: target;
+ view-transition-class: cls;
+}
+
+::view-transition-group(*) {
+ animation-duration: 1s;
+}
+
+::view-transition-new(*),
+::view-transition-old(*) {
+ left: 100px;
+}
+
+::view-transition-new(target.other),
+::view-transition-old(target.other) {
+ left: 0;
+}
+
+</style>
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+window.addEventListener("load", () => {
+ document.startViewTransition().ready.then(takeScreenshot);
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-mismatch-partial.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-mismatch-partial.html
new file mode 100644
index 0000000000..9d9838036b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-mismatch-partial.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transition classes: selector should not match if only some classes match</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/">
+<link rel="author" href="mailto:nrosenthal@chromium.org">
+<link rel="match" href="pseudo-with-classes-ref.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ position: absolute;
+}
+
+#target {
+ background: green;
+ view-transition-name: target;
+ view-transition-class: cls;
+}
+
+::view-transition-group(*) {
+ animation-duration: 1s;
+}
+
+::view-transition-new(*),
+::view-transition-old(*) {
+ left: 100px;
+}
+::view-transition-new(target.cls.other),
+::view-transition-old(target.cls.other) {
+ left: 0;
+}
+
+</style>
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+window.addEventListener("load", () => {
+ document.startViewTransition().ready.then(takeScreenshot);
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-mismatch-wildcard.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-mismatch-wildcard.html
new file mode 100644
index 0000000000..722e413045
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-mismatch-wildcard.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transition classes: selector should not match if only some classes match (with *)</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/">
+<link rel="author" href="mailto:nrosenthal@chromium.org">
+<link rel="match" href="pseudo-with-classes-ref.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ position: absolute;
+}
+
+#target {
+ background: green;
+ view-transition-name: target;
+ view-transition-class: cls;
+}
+
+::view-transition-group(*) {
+ animation-duration: 1s;
+}
+
+::view-transition-new(*),
+::view-transition-old(*) {
+ left: 100px;
+}
+
+::view-transition-new(*.other),
+::view-transition-old(*.other) {
+ left: 0;
+}
+
+</style>
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+window.addEventListener("load", () => {
+ document.startViewTransition().ready.then(takeScreenshot);
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-multiple-vt-classes.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-multiple-vt-classes.html
new file mode 100644
index 0000000000..d7ca0a0493
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-multiple-vt-classes.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transition classes: selector should match when view-transition-class has multiple idents</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/">
+<link rel="author" href="mailto:nrosenthal@chromium.org">
+<link rel="match" href="pseudo-with-classes-ref.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ view-transition-class: cls some-div;
+}
+
+#target {
+ background: green;
+ view-transition-name: target;
+}
+
+::view-transition-group(*) {
+ animation-duration: 1s;
+}
+
+::view-transition-new(target.cls),
+::view-transition-old(target.cls) {
+ left: 100px;
+}
+
+</style>
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+window.addEventListener("load", () => {
+ document.startViewTransition().ready.then(takeScreenshot);
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-new-with-class-old-without.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-new-with-class-old-without.html
new file mode 100644
index 0000000000..5aedc33b3c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-new-with-class-old-without.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transition classes: view-transition-class should apply if applied only in new state</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/">
+<link rel="author" href="mailto:nrosenthal@chromium.org">
+<link rel="match" href="pseudo-with-classes-ref.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ position: absolute;
+}
+
+#target {
+ background: green;
+ view-transition-name: target;
+}
+
+#target.new-state {
+ view-transition-class: cls;
+}
+
+::view-transition-group(*) {
+ animation-duration: 1s;
+}
+
+::view-transition-new(*.cls),
+::view-transition-old(*.cls) {
+ left: 100px;
+}
+
+</style>
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+window.addEventListener("load", () => {
+ document.startViewTransition(() => {
+ document.getElementById("target").classList.add("new-state");
+ }).ready.then(takeScreenshot);
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-old-with-class-new-without.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-old-with-class-new-without.html
new file mode 100644
index 0000000000..6c153253e0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-old-with-class-new-without.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transition classes: view-transition-class should not apply if applied only in old state</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/">
+<link rel="author" href="mailto:nrosenthal@chromium.org">
+<link rel="match" href="pseudo-with-classes-ref.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ position: absolute;
+}
+
+#target {
+ background: green;
+ view-transition-name: target;
+}
+
+#target:not(.new-state) {
+ view-transition-class: cls;
+}
+
+::view-transition-group(*) {
+ animation-duration: 1s;
+}
+
+::view-transition-new(*),
+::view-transition-old(*) {
+ left: 100px;
+}
+
+::view-transition-new(*.cls),
+::view-transition-old(*.cls) {
+ left: 0;
+}
+
+</style>
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+window.addEventListener("load", () => {
+ document.startViewTransition(() => {
+ document.querySelector("#target").classList.add("new-state");
+ }).ready.then(takeScreenshot);
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-ref.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-ref.html
new file mode 100644
index 0000000000..89b3a8a78e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: reference expectation</title>
+<style>
+div {
+ position: relative;
+ left: 100px;
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+</style>
+<body>
+<div></div>
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-view-transition-group.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-view-transition-group.html
new file mode 100644
index 0000000000..3e4dbb303c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-view-transition-group.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transition classes: group selectors should respect classes</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/">
+<link rel="author" href="mailto:nrosenthal@chromium.org">
+<link rel="match" href="pseudo-with-classes-ref.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ background: green;
+ view-transition-name: target;
+ view-transition-class: cls;
+}
+
+:root::view-transition-group(*) {
+ animation-duration: 1s;
+}
+
+:root::view-transition-group(target.cls) {
+ left: 100px;
+}
+
+</style>
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+window.addEventListener("load", () => {
+ document.startViewTransition().ready.then(requestAnimationFrame(() => takeScreenshot()));
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-view-transition-image-pair.html b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-view-transition-image-pair.html
new file mode 100644
index 0000000000..8f0f2ef2a9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/pseudo-with-classes-view-transition-image-pair.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transition classes: group selectors should respect classes</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/">
+<link rel="author" href="mailto:nrosenthal@chromium.org">
+<link rel="match" href="pseudo-with-classes-ref.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ background: green;
+ view-transition-name: target;
+ view-transition-class: cls;
+}
+
+::view-transition-group(*) {
+ animation-duration: 1s;
+}
+
+::view-transition-image-pair(target.cls) {
+ transform: translateX(100px);
+}
+
+</style>
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+window.addEventListener("load", () => {
+ document.startViewTransition().ready.then(requestAnimationFrame(() => takeScreenshot()));
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/ready_resolves_after_dom_before_raf.html b/testing/web-platform/tests/css/css-view-transitions/ready_resolves_after_dom_before_raf.html
new file mode 100644
index 0000000000..adf3dc6c16
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/ready_resolves_after_dom_before_raf.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: promise resolution ordering</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ contain: paint;
+ view-transition-name: target;
+}
+.green {
+ background: green;
+}
+</style>
+
+<div id=target></div>
+
+<script>
+promise_test(async t => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise((resolve, reject) => {
+ let dom_change_ran = false;
+ let transition = document.startViewTransition(() => {
+ target.classList.add("green");
+ dom_change_ran = true;
+ });
+
+ let dom_updated_resolved = false;
+ transition.updateCallbackDone.then(() => {
+ if (!dom_change_ran)
+ reject();
+ // If there's a rAF before ready resolves, we fail.
+ requestAnimationFrame(reject);
+ dom_updated_resolved = true;
+ });
+
+ transition.ready.then(() => {
+ if (!dom_updated_resolved)
+ reject();
+ resolve();
+ });
+ });
+}, "updateCallbackDone resolves, then ready resolves with no rAF in between");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/root-captured-as-different-tag-ref.html b/testing/web-platform/tests/css/css-view-transitions/root-captured-as-different-tag-ref.html
new file mode 100644
index 0000000000..92bd70f6f4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/root-captured-as-different-tag-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>View transitions: capture root elements (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.box {
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ font-size: 30pt;
+}
+#e1 {
+ top: 20px;
+ left: 20px;
+}
+</style>
+<div id=e1 class=box></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/root-captured-as-different-tag.html b/testing/web-platform/tests/css/css-view-transitions/root-captured-as-different-tag.html
new file mode 100644
index 0000000000..4264db8169
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/root-captured-as-different-tag.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: capture root elements</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="old-content-captures-root-ref.html">
+<meta name="fuzzy" content="old-content-captures-root-ref.html:0-1;0-500">
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root { view-transition-name: another-root; }
+.box {
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ position: absolute;
+ font-size: 30pt;
+}
+#e1 {
+ top: 20px;
+ left: 20px;
+}
+#shared {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ background: red;
+ view-transition-name: shared;
+}
+
+div.dst { background: lightgreen; }
+/* We're verifying what we capture, so just display the old contents for 5 minutes. */
+html::view-transition { background: pink; }
+html::view-transition-group(shared) { animation-duration: 300s; }
+html::view-transition-image-pair(shared) { visibility: hidden }
+html::view-transition-old(another-root) { animation: unset; opacity: 1 }
+html::view-transition-new(another-root) { animation: unset; opacity: 0 }
+
+/* This shouldn't apply, so just make it red. */
+html::view-transition-group(root) { animation: unset; opacity: 1; background: red; }
+html::view-transition-image-pair(root) { visibility: hidden; }
+</style>
+<div id=e1 class=box></div>
+<div id=shared></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ e1.classList.add("dst");
+ document.body.style.background = "red";
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/root-element-cv-hidden-crash.html b/testing/web-platform/tests/css/css-view-transitions/root-element-cv-hidden-crash.html
new file mode 100644
index 0000000000..890194b7c1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/root-element-cv-hidden-crash.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<title>View transitions: content-visibility:hidden on root element crash</title>
+<link rel="help" href="https://crbug.com/1429947">
+<style>
+ html {
+ content-visibility: hidden;
+ }
+</style>
+<script>
+ document.startViewTransition();
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/root-element-display-none-crash.html b/testing/web-platform/tests/css/css-view-transitions/root-element-display-none-crash.html
new file mode 100644
index 0000000000..fc55719c7e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/root-element-display-none-crash.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: html display none</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+html {
+ display: none;
+}
+</style>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition().finished.then(takeScreenshot, takeScreenshot);
+
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/root-element-display-none-during-transition-crash.html b/testing/web-platform/tests/css/css-view-transitions/root-element-display-none-during-transition-crash.html
new file mode 100644
index 0000000000..19f4143aa6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/root-element-display-none-during-transition-crash.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: entry animation from root display none</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.hidden {
+ display: none;
+}
+::view-transition-group(*) {
+ animation-duration: 500s
+}
+</style>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ transition = document.startViewTransition();
+ transition.ready.then(
+ requestAnimationFrame(() => {
+ document.documentElement.classList.toggle("hidden");
+ }));
+ transition.finished.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/root-scrollbar-with-fixed-background-ref.html b/testing/web-platform/tests/css/css-view-transitions/root-scrollbar-with-fixed-background-ref.html
new file mode 100644
index 0000000000..a4010b5f2f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/root-scrollbar-with-fixed-background-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html >
+<title>View transitions: capture root element with scrollbar (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<style>
+#container {
+ background: lightblue;
+}
+#first {
+ width: 10px;
+ background: linear-gradient(green, blue);
+ height: 1000px;
+}
+body {
+ margin: 0px;
+ padding: 0px;
+ filter: invert(1);
+}
+</style>
+
+ <div id=container>
+ <div id=first></div>
+ </div>
+
+<script>
+ function scrollContainer() {
+ document.documentElement.scrollTop = 500;
+ }
+
+ onload = scrollContainer();
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/root-scrollbar-with-fixed-background.html b/testing/web-platform/tests/css/css-view-transitions/root-scrollbar-with-fixed-background.html
new file mode 100644
index 0000000000..c657fa19fb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/root-scrollbar-with-fixed-background.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html class=reftest-wait style="background: lightblue;">
+<title>When the root element has scrollbars, these should be excluded in snapshot</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="root-scrollbar-with-fixed-background-ref.html">
+
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#hide {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 10px;
+ height: 10px;
+ background: red;
+ contain: paint;
+ view-transition-name: hide;
+}
+#first {
+ width: 10px;
+ background: linear-gradient(green, blue);
+ height: 1000px;
+}
+body {
+ margin: 0px;
+ padding: 0px;
+}
+
+/* Set a no-op animation to screenshot the pseudo transition DOM. */
+html::view-transition-group(hide) {
+ animation-duration: 300s;
+ opacity: 0;
+}
+html::view-transition-new(*) {
+ animation: unset;
+ filter: invert(1);
+ height: 100%;
+}
+html::view-transition-old(*) {
+ animation: unset;
+ opacity: 0;
+ height: 100%;
+}
+</style>
+
+<div id=hide></div>
+<div id=first></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ await waitForAtLeastOneFrame();
+
+ document.documentElement.scrollTop = 500;
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+
+onload = () => requestAnimationFrame(runTest);
+</script>
+
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/root-style-change-during-animation-ref.html b/testing/web-platform/tests/css/css-view-transitions/root-style-change-during-animation-ref.html
new file mode 100644
index 0000000000..c180c384f4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/root-style-change-during-animation-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: root element style changes during transition</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ background: green;
+}
+
+body {
+ background: grey;
+}
+</style>
+
+<div id=target></div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/root-style-change-during-animation.html b/testing/web-platform/tests/css/css-view-transitions/root-style-change-during-animation.html
new file mode 100644
index 0000000000..d1d291124b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/root-style-change-during-animation.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: root element style changes during transition</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="root-style-change-during-animation-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ contain: paint;
+ background: blue;
+ view-transition-name: target;
+}
+
+#hidden {
+ background: pink;
+ width: 10px;
+ height: 10px;
+ view-transition-name: hidden;
+ contain: paint;
+}
+
+html::view-transition {
+ background: grey;
+}
+
+html::view-transition-group(hidden) {
+ animation-duration: 500s;
+ visibility: hidden;
+}
+
+html::view-transition-group(root) {
+ visibility: hidden;
+}
+
+.test::view-transition-group(target) {
+ background: green;
+}
+.test::view-transition-image-pair(target) {
+ visibility: hidden;
+}
+</style>
+
+<div id=target></div>
+<div id=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function flipClass() {
+ document.documentElement.classList.add("test");
+ requestAnimationFrame(takeScreenshot);
+}
+
+async function runTest() {
+ document.startViewTransition(() => {
+ hidden.style.width="20px";
+ requestAnimationFrame(() => requestAnimationFrame(flipClass));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-end-ref.html b/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-end-ref.html
new file mode 100644
index 0000000000..24b50fa65e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-end-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<title>Root to shared animation test (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+body, html { padding: 0; margin: 0 }
+body {
+ background: yellow;
+}
+.background {
+ background: lightgreen;
+ width: 400px;
+ height: 300px;
+}
+.item {
+ background: blue;
+ width: 200px;
+ height: 200px;
+}
+</style>
+
+<div class=background>
+ <div class=item></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-end.html b/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-end.html
new file mode 100644
index 0000000000..6ba07bd9e6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-end.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="root-to-shared-animation-end-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+body, html { padding: 0; margin: 0 }
+body {
+ background: lightgreen;
+}
+#box {
+ width: 400px;
+ height: 400px;
+ background: blue;
+ contain: paint;
+}
+.hidden {
+ contain: paint;
+ width: 10px;
+ height: 10px;
+ background: red;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { visibility: hidden; }
+
+html::view-transition-group(root) { animation-duration: 0s; }
+html::view-transition-new(*) { animation: unset; opacity: 0; }
+html::view-transition-old(*) { animation: unset; opacity: 1; }
+</style>
+
+<div id=box></div>
+<div class=hidden></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ document.documentElement.style.viewTransitionName = "none";
+ document.body.style.background = "yellow";
+ box.style.viewTransitionName = "root";
+
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-incoming-ref.html b/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-incoming-ref.html
new file mode 100644
index 0000000000..3075d2480c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-incoming-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<title>Root to shared animation test (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+body {
+ background: blue;
+ padding: 0;
+ margin: 0;
+}
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-incoming.html b/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-incoming.html
new file mode 100644
index 0000000000..0620e911cf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-incoming.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="root-to-shared-animation-incoming-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+body {
+ background: lightgreen;
+ padding: 0;
+ margin: 0;
+}
+#box {
+ width: 100px;
+ height: 120px;
+ background: blue;
+ contain: paint;
+}
+
+html::view-transition-group(*) { animation-delay: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 1; }
+html::view-transition-old(*) { animation: unset; opacity: 0; }
+</style>
+
+<div id=box></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ document.documentElement.style.viewTransitionName = "none";
+ box.style.viewTransitionName = "root";
+ // We should not see the "live" body at all.
+ document.body.style.background = "red";
+
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-start-ref.html b/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-start-ref.html
new file mode 100644
index 0000000000..d04ab3f767
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-start-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<title>Root to shared animation test (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+body {
+ background: lightgreen;
+ padding: 0;
+ margin: 0;
+}
+#box {
+ width: 100px;
+ height: 120px;
+ background: blue;
+ contain: paint;
+}
+</style>
+
+<div id=box></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-start.html b/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-start.html
new file mode 100644
index 0000000000..0a1cb9617e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/root-to-shared-animation-start.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="root-to-shared-animation-start-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+body {
+ background: lightgreen;
+ padding: 0;
+ margin: 0;
+}
+#box {
+ width: 100px;
+ height: 120px;
+ background: blue;
+ contain: paint;
+}
+
+html::view-transition-group(*) { animation-delay: 300s; }
+html::view-transition-new(*) { animation: unset; opacity: 0; }
+html::view-transition-old(*) { animation: unset; opacity: 1; }
+</style>
+
+<div id=box></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ document.documentElement.style.viewTransitionName = "none";
+ box.style.viewTransitionName = "root";
+ // We should not see the "live" body at all.
+ document.body.style.background = "red";
+
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/rotated-cat-off-top-edge-ref.html b/testing/web-platform/tests/css/css-view-transitions/rotated-cat-off-top-edge-ref.html
new file mode 100644
index 0000000000..8380b71fb8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/rotated-cat-off-top-edge-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: rotated img element with border radius off the top edge (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+.target {
+ transform: rotate(330deg) translate3d(110px, 10px, 10px);
+ border-radius: 0.375rem;
+ width: 400px;
+ height: 400px;
+}
+</style>
+<body>
+<img class="target" src="support/cat.png">
diff --git a/testing/web-platform/tests/css/css-view-transitions/rotated-cat-off-top-edge.html b/testing/web-platform/tests/css/css-view-transitions/rotated-cat-off-top-edge.html
new file mode 100644
index 0000000000..c7179b7a01
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/rotated-cat-off-top-edge.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>View transitions: rotated img element with border radius off the top edge</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="rotated-cat-off-top-edge-ref.html">
+<meta name="fuzzy" content="rotated-cat-off-top-edge-ref.html:0-5;0-1500">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ transform: rotate(330deg) translate3d(110px, 10px, 10px);
+ border-radius: 0.375rem;
+ width: 400px;
+ height: 400px;
+}
+::view-transition-group(root) {
+ animation-duration: 500s;
+}
+</style>
+<body>
+<img class="target" src="support/cat.png">
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ let transition = document.startViewTransition();
+ transition.ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/rtl-with-scrollbar-ref.html b/testing/web-platform/tests/css/css-view-transitions/rtl-with-scrollbar-ref.html
new file mode 100644
index 0000000000..c429136a2d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/rtl-with-scrollbar-ref.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html dir="rtl">
+<head>
+ <title>Transition is correctly positioned on RTL page (ref)</title>
+ <link rel="help" href="https://github.com/WICG/view-transitions">
+ <link rel="author" href="mailto:bokan@chromium.org">
+
+ <style>
+ #target {
+ position: absolute;
+ top: 100px;
+ left: 100px;
+ width: 100px;
+ height: 200px;
+ background: dodgerblue;
+ }
+
+ #inroot {
+ position: absolute;
+ top: 300px;
+ left: 200px;
+ width: 100px;
+ height: 200px;
+ background: rebeccapurple;
+ }
+
+ body {
+ margin: 0px;
+ padding: 0px;
+ /* add overflow for scrollbar */
+ height: 200vh;
+ }
+ </style>
+</head>
+
+</body>
+ <div id=target></div>
+ <div id="inroot"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/rtl-with-scrollbar.html b/testing/web-platform/tests/css/css-view-transitions/rtl-with-scrollbar.html
new file mode 100644
index 0000000000..de2570605a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/rtl-with-scrollbar.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html dir="rtl" class=reftest-wait>
+<title>Transition is correctly positioned on RTL page</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:bokan@chromium.org">
+<link rel="match" href="rtl-with-scrollbar-ref.html">
+
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#target {
+ position: absolute;
+ top: 100px;
+ left: 100px;
+ width: 100px;
+ height: 200px;
+ background: dodgerblue;
+ contain: paint;
+ view-transition-name: target;
+}
+
+#inroot {
+ position: absolute;
+ top: 300px;
+ left: 200px;
+ width: 100px;
+ height: 200px;
+ background: rebeccapurple;
+ contain: paint;
+}
+
+body {
+ margin: 0px;
+ padding: 0px;
+ /* add overflow for scrollbar */
+ height: 200vh;
+}
+
+/* Show the old snapshot for 300s */
+html::view-transition-group(*) {
+ animation-duration: 300s;
+ opacity: 1;
+}
+html::view-transition-new(*) {
+ animation: unset;
+ opacity: 0;
+}
+html::view-transition-old(*) {
+ animation: unset;
+ opacity: 1;
+}
+</style>
+
+<div id=target></div>
+<div id="inroot"></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ await waitForAtLeastOneFrame();
+
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+
+onload = () => requestAnimationFrame(runTest);
+</script>
+
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/scroller-child-abspos-ref.html b/testing/web-platform/tests/css/css-view-transitions/scroller-child-abspos-ref.html
new file mode 100644
index 0000000000..ed118e633f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/scroller-child-abspos-ref.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<title>View transitions: scroller child element (ref)</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+#target {
+ width: 200px;
+ height: 200px;
+ background: yellow;
+}
+#scroller {
+ overflow: scroll;
+ width: 100px;
+ height: 100px;
+ background: blue;
+ isolation: isolate;
+}
+
+#child {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background: green;
+ top: 200px;
+}
+</style>
+
+<div id="target">
+ <div id="scroller">
+ <div id="child"></div>
+ </div>
+</div>
+
+<script>
+onload = () => { scroller.scrollTop = 300; };
+</script>
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/scroller-child-abspos.html b/testing/web-platform/tests/css/css-view-transitions/scroller-child-abspos.html
new file mode 100644
index 0000000000..3b94ffa7bb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/scroller-child-abspos.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: scroller child element</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="scroller-child-abspos-ref.html">
+<meta name="fuzzy" content="scroller-child-abspos-ref.html:0-5;0-800">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#target {
+ view-transition-name: target;
+ width: 200px;
+ height: 200px;
+ background: yellow;
+}
+#scroller {
+ overflow: scroll;
+ width: 100px;
+ height: 100px;
+ background: blue;
+ isolation: isolate;
+}
+
+#child {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background: green;
+ top: 200px;
+}
+
+html::view-transition-group(root) { animation-duration: 300s; }
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 1;
+}
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 0;
+}
+</style>
+
+<div id="target">
+ <div id="scroller">
+ <div id="child"></div>
+ </div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ scroller.scrollTop = 300;
+
+ let transition = document.startViewTransition();
+ transition.ready.then(() => requestAnimationFrame(takeScreenshot));
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/scroller-child-ref.html b/testing/web-platform/tests/css/css-view-transitions/scroller-child-ref.html
new file mode 100644
index 0000000000..4ff2b2c5ae
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/scroller-child-ref.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>View transitions: scroller child element (ref)</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+#target {
+ width: 500px;
+ height: 500px;
+ background: yellow;
+}
+#scroller {
+ overflow: scroll;
+ width: 100px;
+ height: 100px;
+ background: blue;
+}
+
+#child {
+ position: relative;
+ width: 2000px;
+ height: 2000px;
+ background: green;
+}
+</style>
+
+<div id="target">
+ <div id="scroller">
+ <div id="child"></div>
+ </div>
+</div>
+
+<script>
+onload = () => { scroller.scrollTop = 300; };
+</script>
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/scroller-child.html b/testing/web-platform/tests/css/css-view-transitions/scroller-child.html
new file mode 100644
index 0000000000..5cb2f03e70
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/scroller-child.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: scroller child element</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="scroller-child-ref.html">
+<meta name="fuzzy" content="scroller-child-ref.html:0-5;0-800">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#target {
+ view-transition-name: target;
+ width: 500px;
+ height: 500px;
+ background: yellow;
+}
+#scroller {
+ overflow: scroll;
+ width: 100px;
+ height: 100px;
+ background: blue;
+}
+
+#child {
+ position: relative;
+ width: 2000px;
+ height: 2000px;
+ background: green;
+}
+
+html::view-transition-group(root) { animation-duration: 300s; }
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 1;
+}
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 0;
+}
+</style>
+
+<div id="target">
+ <div id="scroller">
+ <div id="child"></div>
+ </div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ scroller.scrollTop = 300;
+
+ let transition = document.startViewTransition();
+ transition.ready.then(() => requestAnimationFrame(takeScreenshot));
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/scroller-ref.html b/testing/web-platform/tests/css/css-view-transitions/scroller-ref.html
new file mode 100644
index 0000000000..27a2329ee0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/scroller-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>View transitions: scroller element (ref)</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+#scroller {
+ overflow: scroll;
+ width: 100px;
+ height: 100px;
+ background: blue;
+}
+
+#child {
+ position: relative;
+ width: 1000px;
+ height: 1000px;
+ background: green;
+}
+</style>
+
+<div id="scroller">
+ <div id="child"></div>
+</div>
+
+<script>
+onload = () => { scroller.scrollTop = 300; };
+</script>
+
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/scroller.html b/testing/web-platform/tests/css/css-view-transitions/scroller.html
new file mode 100644
index 0000000000..e61d13b316
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/scroller.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: scroller element</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="scroller-ref.html">
+<meta name="fuzzy" content="scroller-ref.html:0-5;0-10">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#scroller {
+ overflow: scroll;
+ width: 100px;
+ height: 100px;
+ background: blue;
+ view-transition-name: target;
+}
+
+#child {
+ position: relative;
+ width: 1000px;
+ height: 1000px;
+ background: green;
+}
+
+html::view-transition-group(root) { animation-duration: 300s; }
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 1;
+}
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 0;
+}
+</style>
+
+<div id="scroller">
+ <div id="child"></div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ scroller.scrollTop = 300;
+
+ let transition = document.startViewTransition();
+ transition.ready.then(() => requestAnimationFrame(takeScreenshot));
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/set-current-time-ref.html b/testing/web-platform/tests/css/css-view-transitions/set-current-time-ref.html
new file mode 100644
index 0000000000..9cf41ec116
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/set-current-time-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title>View transitions: set current time (reference)</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+.target {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ opacity: 0.5;
+}
+</style>
+
+<div class=target></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/set-current-time-transform-ref.html b/testing/web-platform/tests/css/css-view-transitions/set-current-time-transform-ref.html
new file mode 100644
index 0000000000..556d3f544e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/set-current-time-transform-ref.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: set current time</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<script src="/common/reftest-wait.js"></script>
+<style>
+@keyframes move {
+ from {
+ transform: translate(500px);
+ }
+}
+#target {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ view-transition-name: target;
+ position: relative;
+ left: 100px;
+
+ animation-name: move;
+ animation-duration: 1s;
+ animation-timing-function: linear;
+ animation-play-state: paused;
+}
+</style>
+
+<div id=target></div>
+
+<script>
+function runReference() {
+ document.getAnimations().forEach((animation) => {
+ animation.currentTime = 500;
+ });
+ takeScreenshot();
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runReference));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/set-current-time-transform.html b/testing/web-platform/tests/css/css-view-transitions/set-current-time-transform.html
new file mode 100644
index 0000000000..0c7ac64f1c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/set-current-time-transform.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: set current time</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="set-current-time-transform-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root { view-transition-name: unset; }
+#target {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ view-transition-name: target;
+ position: relative;
+}
+.left {
+ left: 0;
+}
+.right {
+ left: 100px;
+}
+
+html::view-transition-group(*) {
+ animation: unset;
+}
+html::view-transition-old(*) {
+ animation: unset;
+ opacity: 0;
+}
+@keyframes move {
+ from {
+ transform: translate(500px);
+ }
+}
+html::view-transition-new(target) {
+ animation-name: move;
+ animation-duration: 1s;
+ animation-timing-function: linear;
+ animation-play-state: paused;
+}
+</style>
+
+<div id=target class=left></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition(() => target.classList.replace("left", "right"));
+ transition.ready.then(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() => {
+ document.getAnimations().forEach((animation) => {
+ animation.currentTime = 500;
+ });
+ requestAnimationFrame(takeScreenshot);
+ }));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/set-current-time.html b/testing/web-platform/tests/css/css-view-transitions/set-current-time.html
new file mode 100644
index 0000000000..f7e802d79b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/set-current-time.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: set current time</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="set-current-time-ref.html">
+<meta name="fuzzy" content="set-current-time-ref.html:0-2;0-40000">
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root { view-transition-name: unset; }
+.target {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ view-transition-name: target;
+}
+
+html::view-transition-group(*) {
+ animation: unset;
+}
+html::view-transition-old(*) {
+ animation: unset;
+}
+html::view-transition-new(target) {
+ animation-duration: 1s;
+ animation-timing-function: linear;
+ animation-play-state: paused;
+}
+</style>
+
+<div id=target></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition(() => target.classList.add("target"));
+ transition.ready.then(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() => {
+ document.getAnimations().forEach((animation) => {
+ animation.currentTime = 500;
+ });
+ requestAnimationFrame(takeScreenshot);
+ }));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/set-universal-specificity-ref.html b/testing/web-platform/tests/css/css-view-transitions/set-universal-specificity-ref.html
new file mode 100644
index 0000000000..4bf2164c7a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/set-universal-specificity-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>View transitions: universal specificity (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+body {
+ background: pink;
+}
+div {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ background: blue;
+ border: 10px solid black;
+}
+</style>
+<div></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/set-universal-specificity.html b/testing/web-platform/tests/css/css-view-transitions/set-universal-specificity.html
new file mode 100644
index 0000000000..ec50b1e407
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/set-universal-specificity.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: universal specificity</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="set-universal-specificity-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+#shared {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ background: blue;
+ view-transition-name: shared;
+}
+
+/* We're verifying what we capture, so just display the old contents for 5 minutes. */
+html::view-transition { background: pink; }
+html::view-transition-group(shared) { animation-duration: 300s; }
+
+html::view-transition-old(shared) {
+ animation: unset;
+ opacity: 1;
+ border: 10px solid black;
+}
+html::view-transition-old(*) {
+ border: 10px solid red;
+}
+
+html::view-transition-new(shared) { animation: unset; opacity: 0; }
+
+html::view-transition-old(root) { animation: unset; opacity: 0; }
+html::view-transition-new(root) { animation: unset; opacity: 0 }
+</style>
+<div id=shared></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/shared-transition-author-style.manual.html b/testing/web-platform/tests/css/css-view-transitions/shared-transition-author-style.manual.html
new file mode 100644
index 0000000000..d757c8cf0d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/shared-transition-author-style.manual.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions of different elements and shapes</title>
+<link rel="help" href="https://github.com/vmpstr/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+body {
+ background: lightpink;
+ overflow: hidden;
+}
+
+input {
+ position: absolute;
+ left: 8px;
+ top: 8px;
+ z-index: 10;
+}
+
+.top {
+ top: 0px;
+ background: green;
+}
+.bottom {
+ bottom: 0px;
+ background: blue;
+}
+
+div {
+ position: absolute;
+ left: 0px;
+ right: 0px;
+ height: 40vh;
+ contain: paint;
+}
+</style>
+
+<input id=toggle type=button value="Toggle!"></input>
+<div id=target class=top>
+The div should alternate being at the bottom and at the top.
+The color at the top is green and bottom is blue.
+During the animation, the div has an (x, y) offset and its
+content is a blend of green and blue. There is also a grey
+background with a slight offset from the top.
+</div>
+
+<script>
+let classes = ["top", "bottom"]
+let i = 0;
+
+let transitionStyle =
+ `html::view-transition {
+ top: 50px;
+ }
+
+ html::view-transition-group(root) {
+ background-color: grey;
+ }
+
+ html::view-transition-group(target) {
+ left: 50px;
+ }
+
+ html::view-transition-old(target) {
+ opacity: 0.5;
+ animation-name: none;
+ }
+
+ html::view-transition-new(target) {
+ opacity: 0.5;
+ }
+ `
+
+let pseudoStyle = document.createElement('style');
+pseudoStyle.appendChild(document.createTextNode(transitionStyle));
+
+async function runAnimation() {
+ target.style.viewTransitionName = "target";
+ let t = document.startViewTransition(() => {
+ target.classList.remove(classes[i]);
+ i = (i + 1) % classes.length;
+ target.classList.add(classes[i]);
+
+ document.head.appendChild(pseudoStyle);
+ });
+ await t.finished;
+ document.head.removeChild(pseudoStyle)
+}
+
+function init() {
+ toggle.addEventListener("click", runAnimation);
+}
+onload = init;
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/shared-transition-half.manual.html b/testing/web-platform/tests/css/css-view-transitions/shared-transition-half.manual.html
new file mode 100644
index 0000000000..130348cc20
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/shared-transition-half.manual.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions of different elements and shapes</title>
+<link rel="help" href="https://github.com/vmpstr/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+body {
+ background: lightpink;
+ overflow: hidden;
+}
+
+input {
+ position: absolute;
+ left: 8px;
+ top: 8px;
+ z-index: 10;
+}
+
+.top {
+ top: 0px;
+}
+.bottom {
+ bottom: 0px;
+}
+
+div {
+ position: absolute;
+ left: 0px;
+ right: 0px;
+ height: 40vh;
+ background: green;
+ contain: paint;
+}
+</style>
+
+<input id=toggle type=button value="Toggle!"></input>
+<div id=target class=top>
+The green div should alternate being at the bottom and at the top.
+Other than green and pink background no other colors should appear.
+</div>
+
+<script>
+let classes = ["top", "bottom"]
+let i = 0;
+async function runAnimation() {
+ target.style.viewTransitionName = "target";
+ let t = document.startViewTransition(() => {
+ target.classList.remove(classes[i]);
+ i = (i + 1) % classes.length;
+ target.classList.add(classes[i]);
+ });
+ await t.finished;
+}
+
+function init() {
+ toggle.addEventListener("click", runAnimation);
+}
+onload = init;
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/shared-transition-shapes.manual.html b/testing/web-platform/tests/css/css-view-transitions/shared-transition-shapes.manual.html
new file mode 100644
index 0000000000..1f666cfe9f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/shared-transition-shapes.manual.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions of different elements and shapes</title>
+<link rel="help" href="https://github.com/vmpstr/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+body {
+ background: lightpink;
+}
+
+#container {
+ width: max-content;
+ position: relative;
+}
+
+.left {
+ left: 50px;
+}
+.right {
+ left: 550px;
+}
+
+div {
+ margin: 10px;
+ contain: paint;
+}
+
+.square {
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+.rounded {
+ width: 100px;
+ height: 100px;
+ background: green;
+ border-radius: 20%;
+}
+.translucent {
+ opacity: 0.5;
+}
+.text {
+ width: 100px;
+ height: 100px;
+}
+</style>
+
+<input id=toggle type=button value="Toggle!"></input>
+<span>Same shape should move right and left</span>
+<div id=container class=left>
+ <div id=e1 class=square></div>
+ <div id=e2 class=rounded></div>
+ <div id=e3 class="square translucent"></div>
+ <div id=e4 class="rounded translucent"></div>
+ <div id=e5 class=text>Lorem Ipsum</div>
+</div>
+
+<script>
+let classes = ["left", "right"]
+let i = 0;
+async function runAnimation() {
+ e1.style.viewTransitionName = "e1";
+ e2.style.viewTransitionName = "e2";
+ e3.style.viewTransitionName = "e3";
+ e4.style.viewTransitionName = "e4";
+ e5.style.viewTransitionName = "e5";
+ let t = document.startViewTransition(() => {
+ container.classList.remove(classes[i]);
+ i = (i + 1) % classes.length;
+ container.classList.add(classes[i]);
+ });
+ await t.finished;
+}
+
+function init() {
+ toggle.addEventListener("click", runAnimation);
+}
+onload = init;
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-absolute-ref.html b/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-absolute-ref.html
new file mode 100644
index 0000000000..3d307ce3c7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-absolute-ref.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: use snapshot containing block for absolute position (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:bokan@chromium.org">
+
+<style>
+:root {
+ background-color: red;
+}
+
+body {
+ height: 400vh;
+}
+
+#target {
+ position: absolute;
+ bottom: 0px;
+ right: 0px;
+ width: 100px;
+ height: 100px;
+
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+
+ background: darkseagreen;
+}
+
+#view-transition {
+ position: absolute;
+ left: 20px;
+ top: 640px;
+ width: 700px;
+ height: 500px;
+ background-color: limegreen;
+}
+
+</style>
+
+<div id="view-transition">
+ <div id="target">TARGET</div>
+</div>
+
+<script>
+onload = () => {
+ const scrollTargetY = 600;
+ window.scrollTo(0, scrollTargetY);
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-absolute.html b/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-absolute.html
new file mode 100644
index 0000000000..ef986cd75c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-absolute.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: use snapshot containing block for absolute position</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:bokan@chromium.org">
+<link rel="match" href="snapshot-containing-block-absolute-ref.html">
+<meta name="fuzzy" content="snapshot-containing-block-absolute-ref.html:0-20;0-100">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root {
+ view-transition-name: none;
+ background-color: red;
+}
+
+body {
+ height: 400vh;
+}
+
+#target {
+ position: absolute;
+ left: 0px;
+ top: 600px;
+ width: 100px;
+ height: 100px;
+
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+
+ background: darkseagreen;
+ view-transition-name: target;
+}
+
+::view-transition-group(target) {
+ animation-duration: 50s;
+ top: unset;
+ left: unset;
+ right: 0px;
+ bottom: 0px;
+}
+
+::view-transition {
+ position: absolute;
+ left: 20px;
+ top: 40px;
+ width: 700px;
+ height: 500px;
+ background-color: limegreen;
+}
+
+</style>
+
+<div id="target">TARGET</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ // Start the view transition at a scroll offset so that the snapshot
+ // containing block differs from the initial containing block. Scroll so that
+ // the target is at 0,0 so its transition group has an identity transform.
+ const scrollTargetY = document.getElementById('target').offsetTop;
+ window.scrollTo(0, scrollTargetY);
+ let transition = document.startViewTransition();
+ await transition.ready;
+ takeScreenshot();
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-includes-scrollbar-gutter-ref.html b/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-includes-scrollbar-gutter-ref.html
new file mode 100644
index 0000000000..8a74bd2164
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-includes-scrollbar-gutter-ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: snapshot containing block includes scrollbar gutters (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:bokan@chromium.org">
+<style>
+:root {
+ scrollbar-gutter: stable both-edges
+}
+#view-transition-mock {
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background-color: palegreen;
+}
+#target {
+ position: absolute;
+ top: 100px;
+ left: 0px;
+ width: 200px;
+ height: 200px;
+ background-color: limegreen;
+}
+</style>
+<div id="view-transition-mock">
+<!--
+ This box should be a scrollbar's width from the left edge and
+ exactly aligned with the light green background.
+-->
+ <div id="target">
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-includes-scrollbar-gutter.html b/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-includes-scrollbar-gutter.html
new file mode 100644
index 0000000000..6e9bf568f6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-includes-scrollbar-gutter.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: snapshot containing block includes scrollbar gutters</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:bokan@chromium.org">
+<link rel="match" href="snapshot-containing-block-includes-scrollbar-gutter-ref.html">
+<meta name="fuzzy" content="snapshot-containing-block-includes-scrollbar-gutter-ref.html:0-20;0-100">
+<script src="/common/reftest-wait.js"></script>
+<style>
+ :root {
+ scrollbar-gutter: stable both-edges;
+ /* unset so ::view-transition is visible. */
+ view-transition-name: none;
+ }
+ ::view-transition {
+ background-color: palegreen;
+ }
+ #target {
+ position: absolute;
+ top: 100px;
+ left: 0px;
+ width: 200px;
+ height: 200px;
+ background-color: limegreen;
+ view-transition-name: target;
+ }
+ ::view-transition-group(target) {
+ animation-duration: 300s;
+ }
+</style>
+<!--
+ This box should be a scrollbar's width from the left edge and
+ exactly aligned with the light green background.
+-->
+<div id="target">
+</div>
+<script>
+ failIfNot(document.startViewTransition,
+ "Missing document.startViewTransition");
+
+ async function runTest() {
+ let transition = document.startViewTransition();
+ await transition.ready;
+ takeScreenshot();
+ }
+
+ onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-static-ref.html b/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-static-ref.html
new file mode 100644
index 0000000000..8ed60934ca
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-static-ref.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: use snapshot containing block for static position (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:bokan@chromium.org">
+
+<style>
+body {
+ height: 400vh;
+ background-color: limegreen;
+}
+
+div {
+ position: absolute;
+ left: 200px;
+ top: 600px;
+ width: 100px;
+ height: 100px;
+
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+
+ background: darkseagreen;
+}
+
+</style>
+
+<div id="target">TARGET</div>
+
+<script>
+onload = () => {
+ const scrollTargetY = document.getElementById('target').offsetTop - 100;
+ window.scrollTo(0, scrollTargetY);
+};
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-static.html b/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-static.html
new file mode 100644
index 0000000000..5e03480c27
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/snapshot-containing-block-static.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: use snapshot containing block for static position</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:bokan@chromium.org">
+<link rel="match" href="snapshot-containing-block-static-ref.html">
+<meta name="fuzzy" content="snapshot-containing-block-static-ref.html:0-20;0-100">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root {
+ view-transition-name: none;
+ background-color: red;
+}
+
+body {
+ height: 400vh;
+}
+
+div {
+ position: absolute;
+ left: 200px;
+ top: 600px;
+ width: 100px;
+ height: 100px;
+
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+
+ background: darkseagreen;
+ view-transition-name: target;
+}
+
+::view-transition-group(target) {
+ animation-duration: 50s;
+}
+
+::view-transition {
+ position: static;
+ display: block;
+ height: 100%;
+ width: 100%;
+ background-color: limegreen;
+}
+
+</style>
+
+<div id="target">TARGET</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ // Start the view transition at a scroll offset so that the snapshot
+ // containing block differs from the initial containing block.
+ const scrollTargetY = document.getElementById('target').offsetTop - 100;
+ window.scrollTo(0, scrollTargetY);
+ let transition = document.startViewTransition();
+ await transition.ready;
+ takeScreenshot();
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-and-box-decorations-ref.html b/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-and-box-decorations-ref.html
new file mode 100644
index 0000000000..e0a75e730f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-and-box-decorations-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: span with overflowing text is rendered correctly (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<style>
+span {
+ text-shadow: red -2px -5px;
+ border: 2px solid black;
+ box-shadow: 3px 3px red, -1em 0 .4em olive;
+}
+
+body {
+ background: pink;
+}
+</style>
+
+<span>This text should render correctly</span>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-and-box-decorations.html b/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-and-box-decorations.html
new file mode 100644
index 0000000000..a2bf59ecb0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-and-box-decorations.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: span with overflowing text is rendered correctly</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="span-with-overflowing-text-and-box-decorations-ref.html">
+<meta name="fuzzy" content="span-with-overflowing-text-and-box-decorations-ref.html:maxDifference=0-3;totalPixels=0-4900">
+
+
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+<style>
+span {
+ text-shadow: red -2px -5px;
+ border: 2px solid black;
+ box-shadow: 3px 3px red, -1em 0 .4em olive;
+ view-transition-name: target;
+}
+
+.hidden {
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+html::view-transition-group(root) { visibility: hidden; }
+
+html::view-transition-group(target) {
+ animation: unset;
+}
+
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 0;
+}
+
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+}
+
+html::view-transition {
+ background: pink;
+}
+</style>
+
+<span>This text should render correctly</span>
+<div class="hidden"></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition();
+ transition.ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-hidden-ref.html b/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-hidden-ref.html
new file mode 100644
index 0000000000..1d27e470ac
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-hidden-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: span with overflowing text is rendered correctly (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<style>
+div {
+ background: grey;
+}
+span {
+ text-shadow: red 2px 5px;
+ visibility: hidden;
+}
+
+body {
+ background: pink;
+}
+</style>
+
+<div>
+ <span>This text should render correctly</span>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-hidden.html b/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-hidden.html
new file mode 100644
index 0000000000..65b1497c70
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-hidden.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: span with overflowing text is rendered correctly</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="span-with-overflowing-text-hidden-ref.html">
+
+
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+<style>
+#target {
+ view-transition-name: target;
+ background: grey;
+}
+.hidden {
+ view-transition-name: hidden;
+}
+span {
+ text-shadow: red 2px 5px;
+ visibility: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+html::view-transition-group(root) { visibility: hidden; }
+
+html::view-transition-group(target) {
+ animation: unset;
+}
+
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 0;
+}
+
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+}
+
+html::view-transition {
+ background: pink;
+}
+</style>
+
+<div id ="target">
+ <span>This text should render correctly</span>
+</div>
+<div class="hidden"></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition();
+ transition.ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-ref.html b/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-ref.html
new file mode 100644
index 0000000000..4ec4d4ccf8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: span with overflowing text is rendered correctly (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<style>
+span {
+ text-shadow: red -2px -5px;
+}
+
+body {
+ background: pink;
+}
+</style>
+
+<span>This text should render correctly</span>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text.html b/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text.html
new file mode 100644
index 0000000000..f3f0f534e9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/span-with-overflowing-text.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: span with overflowing text is rendered correctly</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="span-with-overflowing-text-ref.html">
+<meta name="fuzzy" content="span-with-overflowing-text-ref.html:maxDifference=0-3;totalPixels=0-1100">
+
+
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+<style>
+span {
+ text-shadow: red -2px -5px;
+ view-transition-name: target;
+}
+
+.hidden {
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+html::view-transition-group(root) { visibility: hidden; }
+
+html::view-transition-group(target) {
+ animation: unset;
+}
+
+html::view-transition-old(target) {
+ animation: unset;
+ opacity: 0;
+}
+
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+}
+
+html::view-transition {
+ background: pink;
+}
+</style>
+
+<span>This text should render correctly</span>
+<div class="hidden"></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition();
+ transition.ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/style-inheritance.html b/testing/web-platform/tests/css/css-view-transitions/style-inheritance.html
new file mode 100644
index 0000000000..d0cef9be63
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/style-inheritance.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: ensure correct style inheritance for pseudo tree</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+::view-transition {
+ background-color: red;
+}
+
+::view-transition-group(*) {
+ background-color: inherit;
+ color: blue;
+ animation-duration: 0.321s;
+}
+
+::view-transition-image-pair(*) {
+ color: inherit;
+ overflow-x: clip;
+}
+
+::view-transition-old(*), ::view-transition-new(*) {
+ overflow-x: inherit;
+}
+</style>
+
+<script>
+promise_test(() => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ let transition = document.startViewTransition();
+ transition.ready.then(() => {
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition").backgroundColor, "rgb(255, 0, 0)", "::view-transition");
+
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(root)").backgroundColor, "rgb(255, 0, 0)", "group");
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(root)").color, "rgb(0, 0, 255)", "group");
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(root)").animationDuration, "0.321s", "group");
+
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-image-pair(root)").color, "rgb(0, 0, 255)", "wrapper");
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-image-pair(root)").overflowX, "clip", "wrapper");
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-image-pair(root)").animationDuration, "0.321s", "wrapper");
+
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-old(root)").overflowX, "clip", "outgoing");
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-old(root)").animationDuration, "0.321s", "outgoing");
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-new(root)").overflowX, "clip", "incoming");
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-new(root)").animationDuration, "0.321s", "incoming");
+ });
+ await transition.finished;
+ resolve();
+ });
+}, "style inheritance of pseudo elements");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/support/cat.png b/testing/web-platform/tests/css/css-view-transitions/support/cat.png
new file mode 100644
index 0000000000..85dd732481
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/support/cat.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-view-transitions/support/dialog-in-rtl-iframe-child.html b/testing/web-platform/tests/css/css-view-transitions/support/dialog-in-rtl-iframe-child.html
new file mode 100644
index 0000000000..7b40a8fd5b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/support/dialog-in-rtl-iframe-child.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html dir="rtl">
+ <head>
+ <style>
+ body {
+ /* We need a background due to https://crbug.com/1414158. */
+ background-color: white;
+ height: 200vh;
+ }
+
+ ::view-transition-new(*) {
+ animation: unset;
+ opacity: 1;
+ }
+ ::view-transition-old(*) {
+ animation-duration: 30s;
+ opacity: 0;
+ }
+
+ dialog {
+ width: 50dvw;
+ height: 50dvh;
+ box-sizing: border-box;
+ background-color: limegreen;
+ border: 1px solid black;
+ }
+
+ </style>
+ <script>
+ function show() {
+ document.getElementById('dialog').showModal();
+ }
+ function startTransition() {
+ window.transition = document.startViewTransition(() => {
+ show();
+ });
+ }
+
+ const params = new URLSearchParams(window.location.search);
+ if (params.has('show')) {
+ addEventListener('load', show);
+ }
+ </script>
+ </head>
+ <body>
+ <dialog id="dialog">
+ </dialog>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/support/frame-helper.html b/testing/web-platform/tests/css/css-view-transitions/support/frame-helper.html
new file mode 100644
index 0000000000..3d2e7b52d0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/support/frame-helper.html
@@ -0,0 +1,25 @@
+<!doctype html>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+html { height: 50%; }
+::view-transition-group(*) { animation-duration: 500s }
+</style>
+
+<div></div>
+
+<script>
+function run() {
+ document.startViewTransition(() => {
+ requestAnimationFrame(() => requestAnimationFrame(() => {
+ window.parent.postMessage({}, "*");
+ }));
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(run));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/support/iframe-scrollbar-child.html b/testing/web-platform/tests/css/css-view-transitions/support/iframe-scrollbar-child.html
new file mode 100644
index 0000000000..dfd0fb40d9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/support/iframe-scrollbar-child.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+ body.scrollable {
+ width: 200lvw;
+ height: 200lvh;
+ }
+
+ div {
+ width: 200px;
+ height: 200px;
+ background-color: skyblue;
+ }
+
+ ::view-transition-new(*) {
+ animation-duration: 30s;
+ opacity: 0;
+ }
+ ::view-transition-old(*) {
+ animation: unset;
+ opacity: 1;
+ }
+ */
+ </style>
+ <script>
+ function startTransition() {
+ window.transition = document.startViewTransition(() => {
+ document.body.classList.toggle('scrollable');
+ });
+ }
+
+ onload = () => {
+ const params = new URLSearchParams(window.location.search);
+ if (params.has('scrollbar')) {
+ document.body.classList.add('scrollable');
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <div></div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/support/transition-in-empty-iframe-child.html b/testing/web-platform/tests/css/css-view-transitions/support/transition-in-empty-iframe-child.html
new file mode 100644
index 0000000000..4eca06a0a9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/support/transition-in-empty-iframe-child.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+ ::view-transition-new(*) {
+ animation: unset;
+ opacity: 1;
+ }
+ ::view-transition-old(*) {
+ animation-duration: 30s;
+ opacity: 0;
+ }
+
+ div {
+ width: 50vw;
+ height: 50vh;
+ background-color: limegreen;
+ border: 1px solid black;
+ }
+
+ .hidden {
+ display: none;
+ }
+
+ </style>
+ <script>
+ function newState() {
+ document.querySelector('.hidden').classList.remove('hidden');
+ }
+
+ function startTransition() {
+ window.transition = document.startViewTransition(newState);
+ }
+
+ const params = new URLSearchParams(window.location.search);
+ if (params.has('ref')) {
+ addEventListener('load', newState);
+ }
+ </script>
+ </head>
+ <body>
+ <div class="hidden">
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/synchronous-callback-skipped-before-run.html b/testing/web-platform/tests/css/css-view-transitions/synchronous-callback-skipped-before-run.html
new file mode 100644
index 0000000000..d6023a7fd2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/synchronous-callback-skipped-before-run.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: skipTransition() invoked before a synchronous updateDOM callback is invoked</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ contain: paint;
+}
+</style>
+
+<div id=first></div>
+
+<script>
+promise_test(async t => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ let transition = document.startViewTransition(() => {
+ first.style.viewTransitionName = "target";
+ });
+ transition.skipTransition();
+ await transition.finished;
+
+ if (window.getComputedStyle(first).viewTransitionName == "target")
+ resolve();
+ else
+ reject();
+ });
+}, "finished promise should be resolved if skipTransition() is invoked before a synchronous updateCallbackDone callback is dispatched");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/transform-origin-view-transition-group-ref.html b/testing/web-platform/tests/css/css-view-transitions/transform-origin-view-transition-group-ref.html
new file mode 100644
index 0000000000..e38cbb0ffe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/transform-origin-view-transition-group-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: validates that transform-origin value is default for view-transition-group (ref)</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<style>
+.target {
+ width: 100px;
+ height: 150px;
+ background: green;
+ position: fixed;
+ top: 200px;
+ left: 200px;
+ transform: rotate(90deg);
+ view-transition-name: target;
+ clip-path: inset(1px 1px 1px 1px);
+}
+</style>
+
+<div class="target"></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/transform-origin-view-transition-group.html b/testing/web-platform/tests/css/css-view-transitions/transform-origin-view-transition-group.html
new file mode 100644
index 0000000000..17a8218b76
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/transform-origin-view-transition-group.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: validates that transform-origin value is default for view-transition-group</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="transform-origin-view-transition-group-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ width: 100px;
+ height: 150px;
+ background: green;
+ view-transition-name: target;
+}
+
+.hidden {
+ contain: paint;
+ width: 10px;
+ height: 10px;
+ background: grey;
+ view-transition-name: hidden;
+}
+
+html::view-transition-group(hidden) { animation-duration: 300s; }
+html::view-transition-image-pair(hidden) { animation: unset; opacity: 0; }
+
+html::view-transition-group(target) {
+ animation: unset;
+ transform: rotate(90deg);
+ top: 200px;
+ left: 200px;
+ /* The edges have minor pixel differences due to blending in highdpi */
+ clip-path: inset(1px 1px 1px 1px);
+}
+
+html::view-transition-old(target) {
+ opacity: 1;
+ animation: unset;
+}
+html::view-transition-new(target) {
+ opacity: 0;
+ animation: unset;
+}
+</style>
+
+<div class="target"></div>
+<div class="hidden"></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition().ready.then(
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/transition-in-empty-iframe-ref.html b/testing/web-platform/tests/css/css-view-transitions/transition-in-empty-iframe-ref.html
new file mode 100644
index 0000000000..6747612285
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/transition-in-empty-iframe-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>View transitions: Transition from an empty iframe (ref)</title>
+ <link rel="help" href="https://github.com/WICG/view-transitions">
+ <link rel="author" href="mailto:bokan@chromium.org">
+ <style>
+ iframe {
+ position: absolute;
+ left: 25px;
+ top: 25px;
+ width: 50vw;
+ height: 50vh;
+ }
+ div {
+ background-color: skyblue;
+ width: 100px;
+ height: 100px;
+ }
+ </style>
+</head>
+
+<body>
+ <iframe src="support/transition-in-empty-iframe-child.html?ref">
+ </iframe>
+ <div></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/transition-in-empty-iframe.html b/testing/web-platform/tests/css/css-view-transitions/transition-in-empty-iframe.html
new file mode 100644
index 0000000000..869967a57e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/transition-in-empty-iframe.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<head>
+ <title>View transitions: Transition from an empty iframe</title>
+ <link rel="help" href="https://github.com/WICG/view-transitions">
+ <link rel="author" href="mailto:bokan@chromium.org">
+ <link rel="match" href="transition-in-empty-iframe-ref.html">
+ <meta name=fuzzy content="transition-in-empty-iframe-ref.html:0-80;0-1000">
+ <script src="/common/reftest-wait.js"></script>
+ <style>
+ iframe {
+ position: absolute;
+ left: 25px;
+ top: 25px;
+ width: 50vw;
+ height: 50vh;
+ }
+ /* This div overlaps with the iframe, because the iframe is empty it should
+ * be visible behind the iframe. */
+ div {
+ background-color: skyblue;
+ width: 100px;
+ height: 100px;
+ }
+ </style>
+ <script>
+ failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+ onload = () => {
+ requestAnimationFrame(()=>{requestAnimationFrame(()=> {
+ frames[0].window.startTransition();
+ frames[0].window.transition.ready.then(() => {
+ requestAnimationFrame(()=>{requestAnimationFrame(()=> {
+ takeScreenshot();
+ })});
+ });
+ })});
+ }
+ </script>
+</head>
+
+<body>
+ <iframe src="support/transition-in-empty-iframe-child.html">
+ </iframe>
+ <div></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/transition-skipped-after-animation-started.html b/testing/web-platform/tests/css/css-view-transitions/transition-skipped-after-animation-started.html
new file mode 100644
index 0000000000..56c477a55f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/transition-skipped-after-animation-started.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: skipTransition() after animations have started running should resolve finished promise</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ contain: paint;
+ view-transition-name: target;
+}
+
+::view-transition-group(target) {
+ animation-duration: 300s;
+}
+</style>
+
+<div id=first></div>
+
+<script>
+promise_test(async t => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ let transition = document.startViewTransition();
+ await transition.ready;
+ transition.skipTransition();
+ await transition.finished;
+ resolve();
+ });
+}, "skipTransition() after animations have started running should resolve finished promise");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/transition-skipped-from-invalid-callback.html b/testing/web-platform/tests/css/css-view-transitions/transition-skipped-from-invalid-callback.html
new file mode 100644
index 0000000000..cf3853cd57
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/transition-skipped-from-invalid-callback.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: transition skipped in animation phase</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ contain: paint;
+ view-transition-name: target;
+}
+
+::view-transition-group(target) {
+ animation-duration: 300s;
+}
+</style>
+
+<div id=first></div>
+
+<script>
+promise_test(async t => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ let transition = document.startViewTransition(() => {
+ let foo = bar;
+ });
+
+ let readyRejected = false;
+ transition.ready.then(reject, () => { readyRejected = true; });
+
+ let domUpdateRejected = false;
+ transition.updateCallbackDone.then(reject, () => { domUpdateRejected = true; });
+ transition.finished.then(reject, () => {
+ assert_true(readyRejected, "ready not rejected");
+ assert_true(domUpdateRejected, "dom update not rejected");
+ resolve();
+ });
+ });
+}, "transition skipped because callback has invalid syntax");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/unset-and-initial-view-transition-name.html b/testing/web-platform/tests/css/css-view-transitions/unset-and-initial-view-transition-name.html
new file mode 100644
index 0000000000..2715a5bb33
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/unset-and-initial-view-transition-name.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: validates that view-transition-name: unset or initial are ignored</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+#first {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ contain: paint;
+ view-transition-name: target;
+}
+#second {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ view-transition-name: unset;
+}
+#third {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ view-transition-name: initial;
+}
+</style>
+
+<div id=first></div>
+<div id=second></div>
+<div id=third></div>
+
+<script>
+promise_test(async t => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ let transition = document.startViewTransition();
+ await transition.updateCallbackDone;
+
+ // Elements with view-transition-name: initial and unset don't have
+ // containment. Because they are ignored they don't cause the transition to
+ // be skipped.
+ await transition.ready;
+ transition.finished.then(resolve, reject);
+ });
+}, "validates that view-transition-name: unset or initial are ignored");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/view-transition-name-is-backdrop-filter-root-ref.html b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-is-backdrop-filter-root-ref.html
new file mode 100644
index 0000000000..32aaf55412
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-is-backdrop-filter-root-ref.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: view-transition-name non-none value is a backdrop filter root (ref)</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+.background {
+ background: cyan;
+ width: 200px;
+ height: 200px;
+}
+.shared {
+ background: blue;
+ position: relative;
+ left: 50px;
+ top: 50px;
+ width: 100px;
+ height: 100px;
+ will-change: opacity;
+}
+.filter {
+ backdrop-filter: invert(1);
+ position: relative;
+ left: -50px;
+ top: 30px;
+ width: 200px;
+ height: 40px;
+}
+</style>
+
+<div class=background>
+ <div class=shared>
+ <div class=filter></div>
+ </div>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/view-transition-name-is-backdrop-filter-root.html b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-is-backdrop-filter-root.html
new file mode 100644
index 0000000000..c4f4d38313
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-is-backdrop-filter-root.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: view-transition-name non-none value is a backdrop filter root</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="view-transition-name-is-backdrop-filter-root-ref.html">
+
+<style>
+.background {
+ background: cyan;
+ width: 200px;
+ height: 200px;
+}
+.shared {
+ background: blue;
+ position: relative;
+ left: 50px;
+ top: 50px;
+ width: 100px;
+ height: 100px;
+ view-transition-name: shared;
+}
+.filter {
+ backdrop-filter: invert(1);
+ position: relative;
+ left: -50px;
+ top: 30px;
+ width: 200px;
+ height: 40px;
+}
+</style>
+
+<div class=background>
+ <div class=shared>
+ <div class=filter></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/view-transition-name-is-grouping-ref.html b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-is-grouping-ref.html
new file mode 100644
index 0000000000..add20600f8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-is-grouping-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: view-transition-name non-none value is a grouping value (ref)</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+.parent {
+ top: 0;
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ background: green;
+}
+body {
+ perspective: 1000px;
+ height: 500px;
+}
+</style>
+
+<div class=parent></div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/view-transition-name-is-grouping.html b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-is-grouping.html
new file mode 100644
index 0000000000..95739351f0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-is-grouping.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: view-transition-name non-none value is a grouping value</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="view-transition-name-is-grouping-ref.html">
+
+<style>
+.parent {
+ top: 0;
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ background: red;
+ transform-style: preserve-3d;
+ view-transition-name: target;
+}
+
+.child {
+ background: green;
+ width: 100px;
+ height: 100px;
+ top: 0;
+ left: 0;
+ position: absolute;
+ transform: translateZ(-500px);
+}
+
+body {
+ perspective: 1000px;
+ height: 500px;
+}
+</style>
+
+<div class=parent><div class=child></div></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/view-transition-name-on-document-root-ref.html b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-on-document-root-ref.html
new file mode 100644
index 0000000000..cc0250bc59
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-on-document-root-ref.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: view-transition-name is limited to document root (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<head>
+<style>
+html {
+ view-transition-name: none;
+}
+
+:root {
+ view-transition-name: root;
+}
+
+.foo {
+ position: fixed;
+ left: 0;
+ top: 0;
+ background: red;
+ width: 100px;
+ height: 100px;
+ z-index: 1000;
+}
+
+.bar {
+ position: fixed;
+ left: 50px;
+ top: 50px;
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+</style>
+</head>
+<body>
+<script>
+const extraHTML = document.createElement('html');
+
+const foo = document.createElement('div');
+foo.className = 'foo';
+
+const bar = document.createElement('div');
+bar.className = 'bar';
+
+extraHTML.append(foo);
+document.body.append(extraHTML, bar);
+</script>
+</body>
+</html>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/view-transition-name-on-document-root.html b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-on-document-root.html
new file mode 100644
index 0000000000..afd5d56f61
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-on-document-root.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: view-transition-name is limited to document root</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="view-transition-name-on-document-root-ref.html">
+<head>
+<style>
+.foo {
+ position: fixed;
+ left: 0;
+ top: 0;
+ background: red;
+ width: 100px;
+ height: 100px;
+ z-index: 1000;
+}
+
+.bar {
+ position: fixed;
+ left: 50px;
+ top: 50px;
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+</style>
+</head>
+<body>
+<script>
+const extraHTML = document.createElement('html');
+
+const foo = document.createElement('div');
+foo.className = 'foo';
+
+const bar = document.createElement('div');
+bar.className = 'bar';
+
+extraHTML.append(foo);
+document.body.append(extraHTML, bar);
+</script>
+</body>
+</html>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/view-transition-name-on-removed-element.html b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-on-removed-element.html
new file mode 100644
index 0000000000..36beb30828
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-on-removed-element.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: ensures view-transition-name is not tracked on element removed by script</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+#first {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ view-transition-name: first;
+}
+</style>
+<body>
+ <div>
+ <div id=first></div>
+ </div>
+</body>
+<script>
+promise_test(async t => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ // Remove an uncontained element. Because this element is not visited when
+ // discovering named elements, the transition is not skipped.
+ first.remove();
+
+ let transition = document.startViewTransition();
+ await transition.ready;
+ transition.finished.then(resolve, reject);
+ });
+}, "view-transition-name on an element removed by script should not be visited when discovering named elements");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/view-transition-name-removed-mid-transition-ref.html b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-removed-mid-transition-ref.html
new file mode 100644
index 0000000000..9ec14f60cd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-removed-mid-transition-ref.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: view-transition-name removed mid transition (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<style>
+.foo {
+ position: fixed;
+ left: 0;
+ top: 0;
+ background: red;
+ width: 100px;
+ height: 100px;
+ z-index: 1000;
+}
+
+.bar {
+ position: fixed;
+ left: 50px;
+ top: 50px;
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+</style>
+
+<div class="target" id="target">
+ <div class="foo"></div>
+</div>
+<div class="bar"></div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/view-transition-name-removed-mid-transition.html b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-removed-mid-transition.html
new file mode 100644
index 0000000000..b18df68511
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/view-transition-name-removed-mid-transition.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: view-transition-name removed mid transition</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="view-transition-name-removed-mid-transition-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+.target {
+ view-transition-name:foo;
+}
+
+.foo {
+ position: fixed;
+ left: 0;
+ top: 0;
+ background: red;
+ width: 100px;
+ height: 100px;
+ z-index: 1000;
+}
+
+.bar {
+ position: fixed;
+ left: 50px;
+ top: 50px;
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+</style>
+
+<div class="target" id="target">
+ <div class="foo"></div>
+</div>
+<div class="bar"></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ let transition = document.startViewTransition();
+ await transition.ready;
+ target.style.viewTransitionName = "none";
+ await transition.finished;
+ takeScreenshot();
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/web-animation-pseudo-incorrect-name.html b/testing/web-platform/tests/css/css-view-transitions/web-animation-pseudo-incorrect-name.html
new file mode 100644
index 0000000000..e8d14f1bb0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/web-animation-pseudo-incorrect-name.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: creating animation for non-existant view transition pseudo</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ view-transition-name: target;
+ contain: paint;
+}
+</style>
+
+<div id=first></div>
+
+<script>
+promise_test(async t => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+ return new Promise(async (resolve, reject) => {
+ let transition = document.startViewTransition();
+ await transition.ready;
+
+ let animation = document.documentElement.animate(
+ { transform: ['translate(100px)', 'translate(200px)'] },
+ {duration: 100, pseudoElement: '::view-transition-group(bad-target)', fill: "forwards"});
+
+ requestAnimationFrame(() => {
+ animation.currentTime = 200;
+ requestAnimationFrame(() => requestAnimationFrame(resolve));
+ });
+ });
+}, "animation created with incorrect name");
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/web-animations-api-ref.html b/testing/web-platform/tests/css/css-view-transitions/web-animations-api-ref.html
new file mode 100644
index 0000000000..ab66e7d16d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/web-animations-api-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>View transitions: one element captured for two tags (ref)</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<style>
+div {
+ position: fixed;
+ top: 0;
+ left: 0;
+}
+#first {
+ background: blue;
+ width: 100px;
+ height: 100px;
+ transform: translate(100px);
+}
+#second {
+ background: green;
+ width: 100px;
+ height: 100px;
+ transform: translate(150px);
+}
+</style>
+<div id=first></div>
+<div id=second></div>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/web-animations-api.html b/testing/web-platform/tests/css/css-view-transitions/web-animations-api.html
new file mode 100644
index 0000000000..6d8395ebb7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/web-animations-api.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: capture opacity elements</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="web-animations-api-ref.html">
+<meta name="fuzzy" content="web-animations-api-ref.html:0-2;0-500">
+
+<script src="/common/reftest-wait.js"></script>
+<style>
+#first {
+ background: blue;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+}
+#second {
+ background: green;
+ width: 100px;
+ height: 100px;
+ contain: paint;
+}
+
+/* Unset all animations since the test drives it using WA-API */
+html::view-transition-group(*),
+html::view-transition-image-pair(*),
+html::view-transition-new(*),
+html::view-transition-old(*) {
+ animation: unset;
+}
+
+html::view-transition-group(root){
+ opacity: 0;
+}
+
+</style>
+<div id=first></div>
+<div id=second></div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function setAnimation() {
+ document.documentElement.animate({ transform: ['translate(100px)', 'translate(100px)'] }, { duration: 10000, pseudoElement: '::view-transition-group(first)'});
+ document.documentElement.animate({ transform: ['translate(150px)', 'translate(150px)'] }, { duration: 10000, pseudoElement: '::view-transition-group(second)'});
+ requestAnimationFrame(takeScreenshot);
+}
+
+async function runTest() {
+ first.style.viewTransitionName = "first";
+ document.startViewTransition(() => {
+ first.style.viewTransitionName = "";
+ second.style.viewTransitionName = "second";
+ requestAnimationFrame(setAnimation);
+ });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/testing/web-platform/tests/css/css-view-transitions/window-resize-aborts-transition-before-ready.html b/testing/web-platform/tests/css/css-view-transitions/window-resize-aborts-transition-before-ready.html
new file mode 100644
index 0000000000..6caadeba89
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/window-resize-aborts-transition-before-ready.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<title>
+View transitions: Resizing viewport before animating rejects the ready promise.
+</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:bokan@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<script>
+function pollForResize(win) {
+ const initial_width = win.innerWidth;
+ return new Promise(resolve => {
+ const interval_id = win.setInterval(() => {
+ if (win.innerWidth != initial_width) {
+ win.clearInterval(interval_id);
+ resolve();
+ }
+ }, 100);
+ });
+}
+
+promise_test(async t => {
+ assert_implements(
+ document.startViewTransition, 'Missing document.startViewTransition');
+
+ let popup_win;
+
+ // Open a popup window that we'll use to start a transition
+ await test_driver.bless('Open a popup in a new window', () => {
+ popup_win = window.open('about:blank', 'popup', 'width=300,height=300');
+ });
+
+ // Resize the window while the update callback is running (i.e. before
+ // capturing the new state).
+ let transition = popup_win.document.startViewTransition(async () => {
+ // resizeTo is asynchonous so we want to wait until it takes effect
+ // before proceeding to capture the new state. Needs to poll for a
+ // changed size since rAFs are currently blocked (and thus, so is
+ // `resize` event).
+ const popup_resize = pollForResize(popup_win);
+ popup_win.resizeTo(popup_win.innerWidth/2, popup_win.innerHeight/2);
+ await popup_resize;
+ });
+
+ // Since the window was resized before capturing the new state, the
+ // transition must be skipped and the ready promise rejected.
+
+ let did_finish = false;
+ transition.finished.then(() => { did_finish = true; });
+
+ await promise_rejects_dom(t, 'InvalidStateError', popup_win.DOMException,
+ transition.ready, 'Resize must must reject `ready`.');
+
+ assert_true(did_finish, 'Transition must be skipped.');
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-view-transitions/window-resize-aborts-transition.html b/testing/web-platform/tests/css/css-view-transitions/window-resize-aborts-transition.html
new file mode 100644
index 0000000000..e2424cad8c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/window-resize-aborts-transition.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>View transitions: Resizing viewport skips the transition</title>
+<link rel="help" href="https://github.com/WICG/view-transitions">
+<link rel="author" href="mailto:bokan@chromium.org">
+
+<script src="/common/rendering-utils.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<script>
+function waitForAtLeastOneFrame(win) {
+ return new Promise(resolve => {
+ win.requestAnimationFrame(() => {
+ win.requestAnimationFrame(() => {
+ resolve();
+ });
+ });
+ });
+}
+
+let popupWin;
+promise_test(async t => {
+ assert_implements(document.startViewTransition, "Missing document.startViewTransition");
+
+ return new Promise(async (resolve, reject) => {
+ await waitForAtLeastOneFrame(window);
+
+ // Open a popup window that we'll use to start a transition
+ await test_driver.bless('Open a popup in a new window', () => {
+ popupWin = window.open('about:blank', 'popup', 'width=300,height=300');
+ });
+ let popupDoc = popupWin.document;
+ popupDoc.documentElement.innerHTML = `
+ <style>
+ html {background-color: red;}
+ html.new {background-color: limegreen;}
+
+ /* Set a no-op animation to show the old snapshot indefinitely. */
+ html::view-transition-group(*) {animation-duration: 10s;}
+ html::view-transition-new(*) {animation: unset;opacity: 0;}
+ html::view-transition-old(*) {animation-duration: 10s;opacity: 1;}
+ </style>`;
+
+ // Start a transition inside the popup.
+ let transition = popupDoc.startViewTransition(() => {
+ popupDoc.documentElement.classList.add('new');
+ });
+
+ let finishResolved = false;
+ transition.finished.then(() => {
+ finishResolved = true;
+ });
+
+ // Wait for the transition to start animating.
+ await transition.ready;
+ await waitForAtLeastOneFrame(popupWin);
+ await waitForAtLeastOneFrame(popupWin);
+
+ // Resize the popup window.
+ popupWin.resizeTo(popupWin.innerWidth/2, popupWin.innerHeight/2);
+
+ await waitForAtLeastOneFrame(popupWin);
+
+ // `finish` should have resolved as resizing the transition after capture
+ // should cause it to skip.
+ assert_true(finishResolved, "Transition must be finished by the window resize");
+ resolve();
+ });
+});
+</script>
+</head>
+</html>
diff --git a/testing/web-platform/tests/css/css-view-transitions/writing-mode-container-resize-ref.html b/testing/web-platform/tests/css/css-view-transitions/writing-mode-container-resize-ref.html
new file mode 100644
index 0000000000..3f8835ef94
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/writing-mode-container-resize-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: writing mode on a container (ref)</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+
+<style>
+#target {
+ background: lightblue;
+ height: 100%;
+ aspect-ratio: 1 / 1;
+}
+#container {
+ width: 100px;
+ height: 50px;
+ border: 1px solid black;
+}
+body {
+ writing-mode: vertical-lr;
+ background: pink;
+}
+</style>
+
+<div id=container><div id=target></div></div>
diff --git a/testing/web-platform/tests/css/css-view-transitions/writing-mode-container-resize.html b/testing/web-platform/tests/css/css-view-transitions/writing-mode-container-resize.html
new file mode 100644
index 0000000000..d440cf6eeb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-view-transitions/writing-mode-container-resize.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: writing mode on a container</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="writing-mode-container-resize-ref.html">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#target {
+ view-transition-name: target;
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+}
+.vertical {
+ writing-mode: vertical-lr;
+}
+::view-transition-group(root) {
+ visibility: hidden;
+ animation-duration: 500s;
+}
+::view-transition-old(target) {
+ animation: unset;
+ opacity: 1;
+}
+::view-transition-new(target) {
+ animation: unset;
+ opacity: 0;
+}
+::view-transition-group(target) {
+ height: 50px;
+ border: 1px solid black;
+ animation: unset;
+}
+::view-transition {
+ background: pink;
+}
+</style>
+
+<div id=target class=vertical></div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+function runTest() {
+ const transition = document.startViewTransition(() => target.remove());
+ transition.ready.then(takeScreenshot);
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>