summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-contain/content-visibility
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/css/css-contain/content-visibility')
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/animation-display-lock.html188
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/container-focus-ref.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/container-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/container-with-child-ref.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/container-with-pos-children-ref.html56
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-001.html45
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-002.html42
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-003-ref.html22
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-003.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-004-ref.html11
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-004.html22
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-005.html42
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-006.html43
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-007.html43
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-008.html44
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-009.html47
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-010.html47
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-011.html47
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-012.html43
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-013.html43
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-014.html44
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-015.html50
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-016.html51
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-017.html51
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-018.html52
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-019-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-019.sub.https.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-020-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-020.html46
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-021-ref.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-021.html46
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-022-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-022.html53
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-023-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-023.html45
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-024-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-024.html46
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-025-ref.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-025.html53
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-026.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-027-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-027.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-028.html64
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-029.html27
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-030.html183
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-031.html76
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-032-ref.html11
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-032.html27
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-033-ref.html11
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-033.sub.https.html27
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-034-ref.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-034.html44
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-035.html59
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-036.html61
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-037.html39
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-038.html107
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-039.html79
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-040.html45
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-041.html43
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-042-ref.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-042.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-043.html41
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-044.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-045.html52
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-046.html45
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-047.html48
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-048.html46
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-049-ref.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-049.html43
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-050.html39
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-051.html44
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-052.html73
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-053.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-054.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-055.html42
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-056.html42
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-057.html52
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-058-ref.html61
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-058.html65
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-060.html57
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-061.html57
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-062.html57
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-063.html57
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-064-ref.html57
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-064.html64
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-065.html57
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-066.html57
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-067.html55
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-068.html103
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-069.html53
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-070.html112
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-071.html185
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-072.html86
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-073.html44
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-074-ref.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-074.html69
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-075-ref.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-075.html41
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-076.html41
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-077.html27
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-078-ref.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-078.html43
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-079-ref.html9
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-079.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-080.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-081.html55
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-082.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-083.html42
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-084.html50
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-applied-to-th-crash.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-in-iframe-ref.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-in-iframe.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-intrinsic-width.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-selection-crash.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-state-changed-first-observation.html65
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-state-changed.html98
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-canvas-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-canvas.html43
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-continuations-crash.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-fieldset-size-ref.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-fieldset-size.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-forced-layout-client-rects.html105
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-form-controls-crash.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-hit-test-contents-crash.html27
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-img.html48
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-in-svg-000-crash.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-input-image.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-output-crash.html11
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-resize-observer-no-error-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-resize-observer-no-error.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-svg.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-video-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-video.html41
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-000.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-001.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-002.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-003.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-004.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-005.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-006.html39
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-hide-after-addition.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-with-top-layer-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/contentvisibility-nestedslot-crash.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/crashtests/first-line-and-inline-block.html13
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/detach-locked-slot-children-crash.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/document-element-computed-style.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/dynamic-change-paint-fully-obscuring-child-001.html44
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/element-reassigned-to-skipped-slot.html68
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/element-reassigned-to-slot-in-skipped-subtree.html70
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/hidden-execcommand-crash.html10
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/hidden-pseudo-element-removed-crash.html20
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/inheritance.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/inline-container-with-child-ref.html27
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/meter-selection-crash.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/parsing/content-visibility-computed.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/parsing/content-visibility-invalid.html22
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/parsing/content-visibility-valid.html20
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/positioned-container-ref.html22
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/resources/circles.svg37
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/resources/dice.pngbin0 -> 43058 bytes
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/resources/frame.html8
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/resources/slot-content-visibility.html8
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/resources/text-fragment-target-auto.html64
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/scrollIntoView-target-with-contents-hidden-ref.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/scrollIntoView-target-with-contents-hidden.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/scrollIntoView-with-focus-target-with-contents-hidden-ref.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/scrollIntoView-with-focus-target-with-contents-hidden.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-1-crash.html13
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-10-crash.html16
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-11-crash.html16
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-12-crash.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-13-crash.html20
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-14-crash.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-15-crash.html13
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-16-crash.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-17-crash.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-18-crash.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-19-crash.html12
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-2-crash.html13
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-20-crash.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-21-crash.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-22-crash.html9
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-3-crash.html15
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-4-crash.html13
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-5-crash.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-6-crash.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-7-crash.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-8-crash.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-9-crash.html16
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/spacer-and-container-ref.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/spacer-and-container-scrolled-ref.html27
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/spacer-with-top-layer-ref.html18
192 files changed, 7448 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/animation-display-lock.html b/testing/web-platform/tests/css/css-contain/content-visibility/animation-display-lock.html
new file mode 100644
index 0000000000..7960ba0f59
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/animation-display-lock.html
@@ -0,0 +1,188 @@
+<!DOCTYPE html>
+<meta charset=utf8>
+<title>Test getComputedStyle on a CSS animation in a display locked subtree</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/">
+<script src="/web-animations/testcommon.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ #container {
+ content-visibility: visible;
+ contain: style layout paint;
+ contain-intrinsic-size: 0 100px;
+ }
+ @keyframes fade {
+ from { opacity: 1; }
+ to { opacity: 0; }
+ }
+ #target {
+ background: 'green';
+ height: 100px;
+ width: 100px;
+ }
+ .animate {
+ animation: fade 1s linear 2 alternate;
+ }
+ .transition {
+ transition: opacity 1s linear;
+ }
+</style>
+<body>
+ <div id="container"></div>
+</body>
+<script>
+"use strict";
+
+function reset() {
+ const container = document.getElementById('container');
+ const target = document.getElementById('target');
+ container.style = '';
+ container.removeChild(target);
+}
+
+function createAnimatingElement(test, name) {
+ const container = document.getElementById('container');
+ const target = document.createElement('div');
+ container.appendChild(target);
+ target.id = 'target';
+ target.className = name;
+ test.add_cleanup(() => {
+ reset();
+ });
+ return target;
+}
+
+promise_test(async t => {
+ const container = document.getElementById('container');
+ const target = createAnimatingElement(t, 'animate');
+ let animationIterationEvent = false;
+ target.addEventListener('animationiteration', () => {
+ animationIterationEvent = true;
+ });
+ const animation = target.getAnimations()[0];
+ await animation.ready;
+ await waitForAnimationFrames(1);
+ container.style.contentVisibility = 'hidden';
+ animation.currentTime = 1500;
+ assert_approx_equals(
+ parseFloat(getComputedStyle(target).opacity), 0.5, 1e-6,
+ 'Computed style is updated even when the animation is running in a ' +
+ 'display locked subtree');
+ await waitForAnimationFrames(2);
+ assert_false(animationIterationEvent,
+ 'Animation events do not fire while the animation is ' +
+ 'running in a display locked subtree');
+ container.style.contentVisibility = 'visible';
+ await waitForAnimationFrames(2);
+ assert_true(animationIterationEvent,
+ 'The animationiteration event fires once the animation is ' +
+ 'no longer display locked');
+}, 'Animation events do not fire for a CSS animation running in a display ' +
+ 'locked subtree');
+
+promise_test(async t => {
+ const container = document.getElementById('container');
+ const target = createAnimatingElement(t, 'animate');
+ const animation = target.getAnimations()[0];
+ await animation.ready;
+ let finishedWhileDisplayLocked = false;
+ animation.finished.then(() => {
+ finishedWhileDisplayLocked =
+ getComputedStyle(container).contentVisibility == 'hidden';
+ });
+ await waitForAnimationFrames(1);
+ container.style.contentVisibility = 'hidden';
+ // Advance to just shy of the effect end.
+ animation.currentTime = 1999;
+ assert_approx_equals(
+ parseFloat(getComputedStyle(target).opacity), 0.999, 1e-6,
+ 'Computed style is updated even when the animation is ' +
+ 'running in a display locked subtree');
+ // Advancing frames should not resolve the finished promise.
+ await waitForAnimationFrames(3);
+ container.style.contentVisibility = 'visible';
+ // Now we can resolve the finished promise.
+ await animation.finished;
+ assert_equals(finishedWhileDisplayLocked, false);
+}, 'The finished promise does not resolve due to the normal passage of time ' +
+ 'for a CSS animation in a display locked subtree');
+
+promise_test(async t => {
+ const container = document.getElementById('container');
+ await waitForAnimationFrames(1);
+ const target = createAnimatingElement(t, 'transition');
+ await waitForAnimationFrames(1);
+ target.style.opacity = 0;
+ const animation = target.getAnimations()[0];
+ await animation.ready;
+ let finishedWhileDisplayLocked = false;
+ animation.finished.then(() => {
+ finishedWhileDisplayLocked =
+ getComputedStyle(container).contentVisibility == 'hidden';
+ });
+ await waitForAnimationFrames(1);
+ container.style.contentVisibility = 'hidden';
+ // Advance to just shy of the effect end.
+ animation.currentTime = 999;
+ assert_approx_equals(
+ parseFloat(getComputedStyle(target).opacity), 0.001, 1e-6,
+ 'Computed style is updated even when the animation is ' +
+ 'running in a display locked subtree');
+ // Advancing frames should not resolve the finished promise.
+ await waitForAnimationFrames(3);
+ container.style.contentVisibility = 'visible';
+ // Now we can resolve the finished promise.
+ await animation.finished;
+ assert_equals(finishedWhileDisplayLocked, false);
+}, 'The finished promise does not resolve due to the normal passage of time ' +
+ 'for a CSS transition in a display locked subtree');
+
+promise_test(async t => {
+ const container = document.getElementById('container');
+ const target = createAnimatingElement(t, 'animate');
+ const animation = target.getAnimations()[0];
+ target.className = '';
+ container.style.contentVisibility = 'hidden';
+ assert_equals(target.getAnimations().length, 0);
+
+ // Though originally a CSS animation, it is no longer associated with
+ // CSS rules and no longer has an owning element. It now behaves like a
+ // programmatic web animation. Animation playback events (but not CSS
+ // animation events) should be dispatched and promises resolved despite
+ // being in a display locked subtree.
+
+ let cssAnimationEndEvent = false;
+ target.addEventListener('animationend', () => {
+ cssAnimationEndEvent = true;
+ });
+
+ let animationFinishEvent = false;
+ animation.addEventListener('finish', () => {
+ animationFinishEvent = true;
+ });
+
+ let animationFinished = false;
+ animation.finished.then(() => {
+ animationFinished = true;
+ });
+
+ animation.play();
+ assert_equals(target.getAnimations().length, 1);
+
+ animation.currentTime = 1999;
+ await animation.ready;
+ await waitForAnimationFrames(2);
+
+ assert_true(animationFinishEvent,
+ 'Animation event not blocked on display locked subtree if ' +
+ 'no owning element');
+ assert_true(animationFinished,
+ 'Finished promise not blocked on display locked subtrtee if ' +
+ 'no owning element');
+ assert_false(cssAnimationEndEvent,
+ 'CSS animation events should not be dispatched if there is no ' +
+ 'owning element');
+}, 'Events and promises are handled normally for animations without an ' +
+ 'owning element');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/container-focus-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/container-focus-ref.html
new file mode 100644
index 0000000000..402b689010
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/container-focus-ref.html
@@ -0,0 +1,21 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: container (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+</style>
+
+<p>Test passes if the light blue box below has focus.
+<div id=container tabindex=0></div>
+
+<script>
+onload = () => container.focus();
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/container-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/container-ref.html
new file mode 100644
index 0000000000..e3e8b279ef
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/container-ref.html
@@ -0,0 +1,17 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: container (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+</style>
+
+<div id=container></div>
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/container-with-child-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/container-with-child-ref.html
new file mode 100644
index 0000000000..d9d6ad1943
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/container-with-child-ref.html
@@ -0,0 +1,25 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: container with child and text (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: green;
+}
+</style>
+
+<div id=container>
+ Test passes if you can see this text and a green box.
+ <div id=child></div>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/container-with-pos-children-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/container-with-pos-children-ref.html
new file mode 100644
index 0000000000..1a84feca0b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/container-with-pos-children-ref.html
@@ -0,0 +1,56 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: container with child and text (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+.container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+ contain: layout;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: lightgreen;
+}
+.abspos { position: absolute; }
+.relpos { position: relative; }
+.fixedpos { position: fixed; }
+.start { top: 0; left: 0; }
+.mid { top: 10px; left: 10px; }
+.end { bottom: 0; right: 0; }
+.zindex { z-index: 1; }
+.small { width: 10px; height: 10px; background: blue; }
+.medium { width: 20px; height: 20px; background: green; }
+.large { width: 30px; height: 30px; background: pink; }
+</style>
+
+<p>This test passes if the two light blue boxes below have the same content.
+
+<div class=container>
+ Text.
+ <div id=child></div>
+ <span>inline child</span>
+ <div class="abspos start small"></div>
+ <div class="relpos mid medium"></div>
+ <div class="fixedpos end large"></div>
+ <div class=relpos>
+ <div class="abspos mid small zindex"></div>
+ </div>
+</div>
+<br>
+<div class=container>
+ Text.
+ <div id=child></div>
+ <span>inline child</span>
+ <div class="abspos start small"></div>
+ <div class="relpos mid medium"></div>
+ <div class="fixedpos end large"></div>
+ <div class=relpos>
+ <div class="abspos mid small zindex"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-001.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-001.html
new file mode 100644
index 0000000000..b6b10164e8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-001.html
@@ -0,0 +1,45 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden does not paint</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="content-visibility hidden subtrees are not painted">
+
+<style>
+#container {
+ content-visibility: hidden;
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: lightgreen;
+}
+.abspos { position: absolute; }
+.relpos { position: relative; }
+.fixedpos { position: fixed; }
+.start { top: 0; left: 0; }
+.mid { top: 10px; left: 10px; }
+.end { bottom: 0; right: 0; }
+.zindex { z-index: 1; }
+.small { width: 10px; height: 10px; background: blue; }
+.medium { width: 20px; height: 20px; background: green; }
+.large { width: 30px; height: 30px; background: pink; }
+</style>
+
+<div id=container>
+ Text.
+ <div id=child></div>
+ <span>inline child</span>
+ <div class="abspos start small"></div>
+ <div class="relpos mid medium"></div>
+ <div class="fixedpos end large"></div>
+ <div class=relpos>
+ <div class="abspos mid small zindex"></div>
+ </div>
+</div>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-002.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-002.html
new file mode 100644
index 0000000000..4d83821839
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-002.html
@@ -0,0 +1,42 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden starts painting when removed</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-with-child-ref.html">
+<meta name="assert" content="content-visibility hidden subtrees start painting when hidden is removed">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+.hidden {
+ content-visibility: hidden;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: green;
+}
+</style>
+
+<div id=container class=hidden>
+ Test passes if you can see this text and a green box.
+ <div id=child></div>
+</div>
+
+<script>
+function runTest() {
+ const container = document.getElementById("container");
+ container.classList.remove("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = runTest;
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-003-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-003-ref.html
new file mode 100644
index 0000000000..c5dd2eab6c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-003-ref.html
@@ -0,0 +1,22 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden container is not breakable (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+#parent {
+ width: 100px;
+}
+#container {
+ border-top: solid green 50px;
+ border-bottom: solid green 50px;
+}
+</style>
+
+<p>Test passes if there is a solid green square below.
+
+<div id="parent">
+ <div id="container"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-003.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-003.html
new file mode 100644
index 0000000000..d3cc902b90
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-003.html
@@ -0,0 +1,29 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden container is not breakable</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-003-ref.html">
+<meta name="assert" content="content-visibility hidden container is not breakable">
+
+<style>
+#container {
+ border-top: solid green 50px;
+ border-bottom: solid green 50px;
+ content-visibility: hidden;
+}
+#parent {
+ columns: 2;
+ height: 0px;
+ width: 200px;
+ column-gap: 0;
+}
+</style>
+
+<p>Test passes if there is a solid green square below.
+
+<div id="parent">
+ <div id="container">Text</div>
+</div>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-004-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-004-ref.html
new file mode 100644
index 0000000000..ac48a2a0f0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-004-ref.html
@@ -0,0 +1,11 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden container in an iframe (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<p>Test passes if the word “Fail” does not appear in the box below.</p>
+
+<iframe></iframe>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-004.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-004.html
new file mode 100644
index 0000000000..7091dd930d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-004.html
@@ -0,0 +1,22 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden container in an iframe</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-004-ref.html">
+<meta name="assert" content="content-visibility hidden makes iframe contents hidden">
+
+<p>Test passes if the word “Fail” does not appear in the box below.</p>
+
+<iframe id="frame" srcdoc='
+ <style>
+ #container {
+ width: 100px;
+ height: 100px;
+ content-visibility: hidden;
+ }
+ </style>
+ <div id="container">Fail</div>
+'></iframe>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-005.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-005.html
new file mode 100644
index 0000000000..7b4a791cc7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-005.html
@@ -0,0 +1,42 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden stops painting when added</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="content-visibility subtrees stop painting when hidden is added">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+.hidden {
+ content-visibility: hidden;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: red;
+}
+</style>
+
+<div id=container>
+ Test fails if you can see this text or a red box.
+ <div id=child></div>
+</div>
+
+<script>
+function runTest() {
+ const container = document.getElementById("container");
+ container.classList.add("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = runTest;
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-006.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-006.html
new file mode 100644
index 0000000000..8a0a3db0d1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-006.html
@@ -0,0 +1,43 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden stops painting when added (composited)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="content-visibility subtrees stop painting when hidden is added">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+ will-change: transform;
+}
+.hidden {
+ content-visibility: hidden;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: red;
+}
+</style>
+
+<div id=container>
+ Test fails if you can see this text or a red box.
+ <div id=child></div>
+</div>
+
+<script>
+function runTest() {
+ const container = document.getElementById("container");
+ container.classList.add("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = runTest;
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-007.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-007.html
new file mode 100644
index 0000000000..eec9b1d900
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-007.html
@@ -0,0 +1,43 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden stops painting when added (composited child)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="content-visibility subtrees stop painting when hidden is added">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+.hidden {
+ content-visibility: hidden;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: red;
+ will-change: transform;
+}
+</style>
+
+<div id=container>
+ Test fails if you can see this text or a red box.
+ <div id=child></div>
+</div>
+
+<script>
+function runTest() {
+ const container = document.getElementById("container");
+ container.classList.add("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = runTest;
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-008.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-008.html
new file mode 100644
index 0000000000..fec8549879
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-008.html
@@ -0,0 +1,44 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden stops painting when added (composited with composited child)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="content-visibility subtrees stop painting when hidden is added">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+ will-change: transform;
+}
+.hidden {
+ content-visibility: hidden;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: red;
+ will-change: transform;
+}
+</style>
+
+<div id=container>
+ Test fails if you can see this text or a red box.
+ <div id=child></div>
+</div>
+
+<script>
+function runTest() {
+ const container = document.getElementById("container");
+ container.classList.add("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = runTest;
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-009.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-009.html
new file mode 100644
index 0000000000..d65a475233
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-009.html
@@ -0,0 +1,47 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden stops painting when added (positioned)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="positioned-container-ref.html">
+<meta name="assert" content="content-visibility subtrees stop painting when hidden is added">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+.positioned {
+ position: absolute;
+ top: 0;
+ left: 0;
+}
+.hidden {
+ content-visibility: hidden;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: red;
+}
+</style>
+
+<div id=container class=positioned>
+ Test fails if you can see this text or a red box.
+ <div id=child></div>
+</div>
+
+<script>
+function runTest() {
+ const container = document.getElementById("container");
+ container.classList.add("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = runTest;
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-010.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-010.html
new file mode 100644
index 0000000000..a613bf2754
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-010.html
@@ -0,0 +1,47 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden stops painting when added (positioned child)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="content-visibility subtrees stop painting when hidden is added">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+.positioned {
+ position: absolute;
+ top: 0;
+ left: 0;
+}
+.hidden {
+ content-visibility: hidden;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: red;
+}
+</style>
+
+<div id=container>
+ Test fails if you can see this text or a red box.
+ <div id=child class=positioned></div>
+</div>
+
+<script>
+function runTest() {
+ const container = document.getElementById("container");
+ container.classList.add("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = runTest;
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-011.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-011.html
new file mode 100644
index 0000000000..c69c36900f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-011.html
@@ -0,0 +1,47 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden stops painting when added (positioned with a positioned child)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="positioned-container-ref.html">
+<meta name="assert" content="content-visibility subtrees stop painting when hidden is added">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+.positioned {
+ position: absolute;
+ top: 0;
+ left: 0;
+}
+.hidden {
+ content-visibility: hidden;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: red;
+}
+</style>
+
+<div id=container class=positioned>
+ Test fails if you can see this text or a red box below.
+ <div id=child class=positioned></div>
+</div>
+
+<script>
+function runTest() {
+ const container = document.getElementById("container");
+ container.classList.add("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = runTest;
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-012.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-012.html
new file mode 100644
index 0000000000..6a52890256
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-012.html
@@ -0,0 +1,43 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden starts painting when removed (composited)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-with-child-ref.html">
+<meta name="assert" content="content-visibility hidden subtrees start painting when hidden is removed">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+ will-change: transform;
+}
+.hidden {
+ content-visibility: hidden;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: green;
+}
+</style>
+
+<div id=container class=hidden>
+ Test passes if you can see this text and a green box.
+ <div id=child></div>
+</div>
+
+<script>
+function runTest() {
+ const container = document.getElementById("container");
+ container.classList.remove("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = runTest;
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-013.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-013.html
new file mode 100644
index 0000000000..18c8b9dfee
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-013.html
@@ -0,0 +1,43 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden starts painting when removed (composited child)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-with-child-ref.html">
+<meta name="assert" content="content-visibility hidden subtrees start painting when hidden is removed">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+.hidden {
+ content-visibility: hidden;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: green;
+ will-change: transform;
+}
+</style>
+
+<div id=container class=hidden>
+ Test passes if you can see this text and a green box.
+ <div id=child></div>
+</div>
+
+<script>
+function runTest() {
+ const container = document.getElementById("container");
+ container.classList.remove("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = runTest;
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-014.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-014.html
new file mode 100644
index 0000000000..e3ee8af087
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-014.html
@@ -0,0 +1,44 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden starts painting when removed (composited with a composited child)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-with-child-ref.html">
+<meta name="assert" content="content-visibility hidden subtrees start painting when hidden is removed">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+ will-change: transform;
+}
+.hidden {
+ content-visibility: hidden;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: green;
+ will-change: transform;
+}
+</style>
+
+<div id=container class=hidden>
+ Test passes if you can see this text and a green box.
+ <div id=child></div>
+</div>
+
+<script>
+function runTest() {
+ const container = document.getElementById("container");
+ container.classList.remove("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = runTest;
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-015.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-015.html
new file mode 100644
index 0000000000..6099054ebd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-015.html
@@ -0,0 +1,50 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hit testing</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility hidden prevents hit-testing in the subtree">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body {
+ margin: 0;
+ padding: 0;
+}
+#outer {
+ width: 100px;
+ height: 100px;
+ background: lightblue;
+
+ content-visibility: hidden;
+}
+#inner {
+ margin: 25px;
+ width: 50px;
+ height: 50px;
+ background lightgreen;
+}
+</style>
+
+<body id="body">
+<div id="outer"><div id="inner"></div></div>
+</body>
+
+<script>
+async_test((t) => {
+ const container = document.getElementById("outer");
+
+ let target = document.elementFromPoint(50, 50);
+ t.step(() => assert_equals(target.id, "outer", "center hits outer"));
+ target = document.elementFromPoint(10, 50);
+ t.step(() => assert_equals(target.id, "outer", "edge hits outer"));
+ target = document.elementFromPoint(100, 50);
+ t.step(() => assert_equals(target.id, "body", "elsewhere hits body"));
+ t.done();
+});
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-016.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-016.html
new file mode 100644
index 0000000000..db3599e243
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-016.html
@@ -0,0 +1,51 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hit testing (composited)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility hidden prevents hit-testing in the subtree">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body {
+ margin: 0;
+ padding: 0;
+}
+#outer {
+ width: 100px;
+ height: 100px;
+ background: lightblue;
+
+ content-visibility: hidden;
+ will-change: transform;
+}
+#inner {
+ margin: 25px;
+ width: 50px;
+ height: 50px;
+ background lightgreen;
+}
+</style>
+
+<body id="body">
+<div id="outer"><div id="inner"></div></div>
+</body>
+
+<script>
+async_test((t) => {
+ const container = document.getElementById("outer");
+
+ let target = document.elementFromPoint(50, 50);
+ t.step(() => assert_equals(target.id, "outer", "center hits outer"));
+ target = document.elementFromPoint(10, 50);
+ t.step(() => assert_equals(target.id, "outer", "edge hits outer"));
+ target = document.elementFromPoint(100, 50);
+ t.step(() => assert_equals(target.id, "body", "elsewhere hits body"));
+ t.done();
+});
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-017.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-017.html
new file mode 100644
index 0000000000..a9c0e03009
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-017.html
@@ -0,0 +1,51 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hit testing (composited child)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility hidden prevents hit-testing in the subtree">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body {
+ margin: 0;
+ padding: 0;
+}
+#outer {
+ width: 100px;
+ height: 100px;
+ background: lightblue;
+
+ content-visibility: hidden;
+}
+#inner {
+ margin: 25px;
+ width: 50px;
+ height: 50px;
+ background lightgreen;
+ will-change: transform;
+}
+</style>
+
+<body id="body">
+<div id="outer"><div id="inner"></div></div>
+</body>
+
+<script>
+async_test((t) => {
+ const container = document.getElementById("outer");
+
+ let target = document.elementFromPoint(50, 50);
+ t.step(() => assert_equals(target.id, "outer", "center hits outer"));
+ target = document.elementFromPoint(10, 50);
+ t.step(() => assert_equals(target.id, "outer", "edge hits outer"));
+ target = document.elementFromPoint(100, 50);
+ t.step(() => assert_equals(target.id, "body", "elsewhere hits body"));
+ t.done();
+});
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-018.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-018.html
new file mode 100644
index 0000000000..15fe7f769d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-018.html
@@ -0,0 +1,52 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hit testing (composited with a composited child)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility hidden prevents hit-testing in the subtree">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body {
+ margin: 0;
+ padding: 0;
+}
+#outer {
+ width: 100px;
+ height: 100px;
+ background: lightblue;
+
+ content-visibility: hidden;
+ will-change: transform;
+}
+#inner {
+ margin: 25px;
+ width: 50px;
+ height: 50px;
+ background lightgreen;
+ will-change: transform;
+}
+</style>
+
+<body id="body">
+<div id="outer"><div id="inner"></div></div>
+</body>
+
+<script>
+async_test((t) => {
+ const container = document.getElementById("outer");
+
+ let target = document.elementFromPoint(50, 50);
+ t.step(() => assert_equals(target.id, "outer", "center hits outer"));
+ target = document.elementFromPoint(10, 50);
+ t.step(() => assert_equals(target.id, "outer", "edge hits outer"));
+ target = document.elementFromPoint(100, 50);
+ t.step(() => assert_equals(target.id, "body", "elsewhere hits body"));
+ t.done();
+});
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-019-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-019-ref.html
new file mode 100644
index 0000000000..09356a3b61
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-019-ref.html
@@ -0,0 +1,17 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Display Locking: iframe locking (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+div {
+ background: blue;
+ color: white;
+}
+</style>
+
+<div>Test passes if there is a box with no text below.</div>
+<iframe id="frame" width=400 height=200 srcdoc=''></iframe>
+<div>Test passes if there is a box with no text above.</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-019.sub.https.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-019.sub.https.html
new file mode 100644
index 0000000000..19497af007
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-019.sub.https.html
@@ -0,0 +1,37 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: cross-origin iframe locking</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-019-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<script src="../resources/utils.js"></script>
+
+<style>
+div {
+ background: blue;
+ color: white;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<div>Test passes if there is a box with no text below.</div>
+<iframe id="frame" width=400 height=200 src='https://{{domains[www]}}:{{ports[https][0]}}/wpt_internal/display-lock/css-content-visibility/resources/frame.html'></iframe>
+<div>Test passes if there is a box with no text above.</div>
+
+<script>
+async function runTest() {
+ document.getElementById("frame").classList.add("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(runTest);
+ });
+};
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-020-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-020-ref.html
new file mode 100644
index 0000000000..7e0140365d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-020-ref.html
@@ -0,0 +1,17 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hidden iframe (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+div {
+ background: blue;
+ color: white;
+}
+</style>
+
+<div>Test passes if the word “FAIL” does not appear below and if there is no red.</div>
+<iframe id="frame" width=400 height=200 srcdoc=''></iframe>
+<div>Test passes if the word “FAIL” does not appear above and if there is no red.</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-020.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-020.html
new file mode 100644
index 0000000000..4b4873073e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-020.html
@@ -0,0 +1,46 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: hidden iframe</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-020-ref.html">
+<meta name="assert" content="content-visibility hidden iframe does not paint">
+
+<script src="/common/reftest-wait.js"></script>
+<script src="../resources/utils.js"></script>
+
+<style>
+div {
+ background: blue;
+ color: white;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<div>Test passes if the word “FAIL” does not appear below and if there is no red.</div>
+<iframe id="frame" width=400 height=200 srcdoc='
+ <style>
+ div {
+ background: red;
+ }
+ </style>
+ <div>FAIL</div>
+'></iframe>
+<div>Test passes if the word “FAIL” does not appear above and if there is no red.</div>
+
+<script>
+async function runTest() {
+ document.getElementById("frame").classList.add("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(runTest);
+ });
+};
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-021-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-021-ref.html
new file mode 100644
index 0000000000..be71e10eb3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-021-ref.html
@@ -0,0 +1,25 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hidden image (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+div {
+ background: blue;
+ color: white;
+}
+.myimg {
+ display: inline-block;
+ width: 400px;
+ height: 200px;
+ background: lightblue;
+ border: 1px solid black;
+}
+</style>
+
+<div>Test passes if there are two identical light blue boxes below and no image in them.</div>
+<div class="myimg"></div>
+<div class="myimg"></div>
+<div>Test passes if there are two identical light blue boxes above and no image in them.</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-021.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-021.html
new file mode 100644
index 0000000000..f9e597cd55
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-021.html
@@ -0,0 +1,46 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: hidden image</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-021-ref.html">
+<meta name="assert" content="content-visibility hidden img element does not paint replaced content">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ background: blue;
+ color: white;
+}
+img {
+ width: 400px;
+ height: 200px;
+ background: lightblue;
+ border: 1px solid black;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<div>Test passes if there are two identical light blue boxes below and no image in them.</div>
+<img id="img1" src="resources/dice.png"></img>
+<img id="img2" src="resources/circles.svg"></img>
+<div>Test passes if there are two identical light blue boxes above and no image in them.</div>
+
+<script>
+async function runTest() {
+ document.getElementById("img1").classList.add("hidden");
+ document.getElementById("img2").classList.add("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(runTest);
+ });
+};
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-022-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-022-ref.html
new file mode 100644
index 0000000000..f85727489a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-022-ref.html
@@ -0,0 +1,24 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hidden svg (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+div {
+ background: blue;
+ color: white;
+}
+.mysvg {
+ display: inline-block;
+ width: 400px;
+ height: 300px;
+ background: lightblue;
+ border: 1px solid black;
+}
+</style>
+
+<div>Test passes if there is a plain light blue box below with no circles in it.</div>
+<div class="mysvg"></div>
+<div>Lorem ipsum consectetur adipiscing elit</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-022.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-022.html
new file mode 100644
index 0000000000..8912d70ed4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-022.html
@@ -0,0 +1,53 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: hidden svg</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-022-ref.html">
+<meta name="assert" content="content-visibility hidden svg does not paint">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ background: blue;
+ color: white;
+}
+svg {
+ border: 1px solid black;
+ background: lightblue;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<div>Test passes if there is a plain light blue box below with no circles in it.</div>
+<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300" viewBox="0 0 400 300" id="svg">
+ <g stroke-width="10" transform="translate(-30)">
+ <circle cx="80" cy="50" r="35" fill="#084" stroke="none"/>
+ <circle cx="80" cy="50" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="120" r="35" fill="#004" stroke="none"/>
+ <circle cx="80" cy="120" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="190" r="35" fill="#088" stroke="none"/>
+ <circle cx="80" cy="190" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="260" r="35" fill="#008" stroke="none"/>
+ <circle cx="80" cy="260" r="20" fill="#080" stroke="#FF0"/>
+ </g>
+</svg>
+<div>Lorem ipsum consectetur adipiscing elit</div>
+
+<script>
+async function runTest() {
+ document.getElementById("svg").classList.add("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(runTest);
+ });
+};
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-023-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-023-ref.html
new file mode 100644
index 0000000000..713c2df706
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-023-ref.html
@@ -0,0 +1,24 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hidden iframe (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+div {
+ background: blue;
+ color: white;
+}
+</style>
+
+<div>Test passes if the word “PASS” and a green box can been seen below.</div>
+<iframe width=400 height=200 srcdoc='
+ <style>
+ div {
+ background: green;
+ }
+ </style>
+ <div>PASS</div>
+'></iframe>
+<div>Lorem ipsum consectetur adipiscing elit</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-023.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-023.html
new file mode 100644
index 0000000000..b561a8b0cd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-023.html
@@ -0,0 +1,45 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: hidden iframe</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-023-ref.html">
+<meta name="assert" content="content-visibility hidden iframe paints when hidden is removed">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ background: blue;
+ color: white;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<div>Test passes if the word “PASS” and a green box can been seen below.</div>
+<iframe id="frame" class=hidden width=400 height=200 srcdoc='
+ <style>
+ div {
+ background: green;
+ }
+ </style>
+ <div>PASS</div>
+'></iframe>
+<div>Lorem ipsum consectetur adipiscing elit</div>
+
+<script>
+async function runTest() {
+ document.getElementById("frame").classList.remove("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(runTest);
+ });
+};
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-024-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-024-ref.html
new file mode 100644
index 0000000000..a9c68285a7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-024-ref.html
@@ -0,0 +1,24 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hidden image (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+div {
+ background: blue;
+ color: white;
+}
+img {
+ width: 400px;
+ height: 200px;
+ background: lightblue;
+ border: 1px solid black;
+}
+</style>
+
+<div>Test passes if there are two pictures below: one of colored dices over a checkered background, and one of a bunch of circles.</div>
+<img src="resources/dice.png"></img>
+<img src="resources/circles.svg"></img>
+<div>Lorem ipsum consectetur adipiscing elit</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-024.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-024.html
new file mode 100644
index 0000000000..cf2faca345
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-024.html
@@ -0,0 +1,46 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: hidden image</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-024-ref.html">
+<meta name="assert" content="content-visibility hidden img element paints when hidden is removed">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ background: blue;
+ color: white;
+}
+img {
+ width: 400px;
+ height: 200px;
+ background: lightblue;
+ border: 1px solid black;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<div>Test passes if there are two pictures below: one of colored dices over a checkered background, and one of a bunch of circles.</div>
+<img id="img1" class=hidden src="resources/dice.png"></img>
+<img id="img2" class=hidden src="resources/circles.svg"></img>
+<div>Lorem ipsum consectetur adipiscing elit</div>
+
+<script>
+async function runTest() {
+ document.getElementById("img1").classList.remove("hidden");
+ document.getElementById("img2").classList.remove("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(runTest);
+ });
+};
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-025-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-025-ref.html
new file mode 100644
index 0000000000..df156cee72
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-025-ref.html
@@ -0,0 +1,32 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hidden svg (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+div {
+ background: blue;
+ color: white;
+}
+svg {
+ border: 1px solid black;
+ background: lightblue;
+}
+</style>
+
+<div>Test passes if there are circles in the light blue box below.</div>
+<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300" viewBox="0 0 400 300">
+ <g stroke-width="10" transform="translate(-30)">
+ <circle cx="80" cy="50" r="35" fill="#084" stroke="none"/>
+ <circle cx="80" cy="50" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="120" r="35" fill="#004" stroke="none"/>
+ <circle cx="80" cy="120" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="190" r="35" fill="#088" stroke="none"/>
+ <circle cx="80" cy="190" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="260" r="35" fill="#008" stroke="none"/>
+ <circle cx="80" cy="260" r="20" fill="#080" stroke="#FF0"/>
+ </g>
+</svg>
+<div>Lorem ipsum consectetur adipiscing elit</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-025.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-025.html
new file mode 100644
index 0000000000..019cd1cc83
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-025.html
@@ -0,0 +1,53 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: hidden svg</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-025-ref.html">
+<meta name="assert" content="content-visibility hidden svg paints when hidden is removed">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ background: blue;
+ color: white;
+}
+svg {
+ border: 1px solid black;
+ background: lightblue;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<div>Test passes if there are circles in the light blue box below.</div>
+<svg class=hidden xmlns="http://www.w3.org/2000/svg" width="400" height="300" viewBox="0 0 400 300" id="svg">
+ <g stroke-width="10" transform="translate(-30)">
+ <circle cx="80" cy="50" r="35" fill="#084" stroke="none"/>
+ <circle cx="80" cy="50" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="120" r="35" fill="#004" stroke="none"/>
+ <circle cx="80" cy="120" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="190" r="35" fill="#088" stroke="none"/>
+ <circle cx="80" cy="190" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="260" r="35" fill="#008" stroke="none"/>
+ <circle cx="80" cy="260" r="20" fill="#080" stroke="#FF0"/>
+ </g>
+</svg>
+<div>Lorem ipsum consectetur adipiscing elit</div>
+
+<script>
+async function runTest() {
+ document.getElementById("svg").classList.remove("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(runTest);
+ });
+};
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-026.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-026.html
new file mode 100644
index 0000000000..17ec9a21d5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-026.html
@@ -0,0 +1,31 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: Computed Values</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility:hidden does not affect computed value of 'contain'">
+<meta name="assert" content="content-visibility:auto does not affect computed value of 'contain'">
+
+<div id="container"></div>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+
+test(() => {
+ assert_equals(getComputedStyle(container).contain, "none");
+ container.style = "content-visibility:hidden";
+ assert_equals(getComputedStyle(container).contentVisibility, "hidden");
+ assert_equals(getComputedStyle(container).contain, "none");
+}, "content-visibility:hidden does not affect computed value of 'contain'");
+
+test(() => {
+ assert_equals(getComputedStyle(container).contain, "none");
+ container.style = "content-visibility:auto;contain:layout;";
+ assert_equals(getComputedStyle(container).contentVisibility, "auto");
+ assert_equals(getComputedStyle(container).contain, "layout");
+}, "content-visibility:auto does not affect computed value of 'contain'");
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-027-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-027-ref.html
new file mode 100644
index 0000000000..ce40d52998
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-027-ref.html
@@ -0,0 +1,17 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: auto in the viewport (reference).</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+.border {
+ border: 1px solid black;
+}
+</style>
+
+<div class=border>
+ Test passes if there is a border around this text.
+</div>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-027.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-027.html
new file mode 100644
index 0000000000..912cefd815
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-027.html
@@ -0,0 +1,37 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: auto in the viewport.</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-027-ref.html">
+<meta name="assert" content="content-visibility auto element in the viewport paints">
+<meta name="assert" content="content-visibility auto element in the viewport does not have size containment">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ content-visibility: auto;
+ border: 1px solid black;
+}
+</style>
+
+<div class=locked>
+ Test passes if there is a border around this text.
+</div>
+
+<script>
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ takeScreenshot();
+ });
+ });
+});
+
+</script>
+</html>
+
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-028.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-028.html
new file mode 100644
index 0000000000..db13543f29
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-028.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>Content Visibility: shadow dom</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-with-child-ref.html">
+<meta name="assert" content="content-visibility hidden can be used in a shadow DOM">
+
+<script src="/common/reftest-wait.js"></script>
+<script src="resources/utils.js"></script>
+
+<style>
+.hidden {
+ content-visibility: hidden;
+}
+.child {
+ width: 50px;
+ height: 50px;
+ background: green;
+}
+</style>
+<div id="host">
+ <div id="slotted">
+ Test passes if you can see this text and a green box.
+ <div class=child></div>
+ </div>
+</div>
+
+<script>
+async function runTest() {
+ // Set up hidden element within shadow root.
+ let shadowRoot = host.attachShadow({ mode: "open" });
+ let hidden = document.createElement("div");
+ shadowRoot.innerHTML = `
+ <style>
+ .container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+ }
+ </style>`;
+ shadowRoot.appendChild(hidden);
+ hidden.innerHTML = "<slot></slot>";
+ hidden.getBoundingClientRect();
+ hidden.classList.add("container");
+ hidden.classList.add("hidden");
+ requestAnimationFrame(() => {
+ slotted.style = "display: none";
+ // Do a forced layout outside the hidden subtree.
+ host.getBoundingClientRect();
+
+ hidden.classList.remove("hidden");
+ slotted.style = "";
+ requestAnimationFrame(() => {
+ // Check that everything is painted as we expect.
+ takeScreenshot();
+ });
+ });
+}
+
+window.onload = runTest;
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-029.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-029.html
new file mode 100644
index 0000000000..7598634678
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-029.html
@@ -0,0 +1,27 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: innerText</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="innerText skips content-visibility hidden elements">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/utils.js"></script>
+
+This text should be visible.
+<div id="container" style="content-visibility: hidden">
+ This text should not be visible.
+ <div id="inner">
+ This text is also not visible.
+ </div>
+</div>
+
+<script>
+test(() => {
+ assert_equals(document.body.innerText, "This text should be visible.");
+ assert_equals(document.getElementById("inner").innerText, "");
+}, "innerText on locked element.");
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-030.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-030.html
new file mode 100644
index 0000000000..397f8de519
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-030.html
@@ -0,0 +1,183 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: intersection observer interactions</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility hidden is not intersecting from IO perspective">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+}
+#spacer {
+ height: 3000px;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<div id="target1">
+ <div id="target2"></div>
+</div>
+<div id="target3">
+ <div id="target4"></div>
+</div>
+<div id="spacer"></div>
+<div id="find_me"></div>
+
+<script>
+async_test((t) => {
+ let target1, target2, target3, target4;
+ let observer;
+ let entries = [];
+
+ // Set everything up.
+ function enqueueStep1() {
+ target1 = document.getElementById("target1");
+ target2 = document.getElementById("target2");
+ target3 = document.getElementById("target3");
+ target4 = document.getElementById("target4");
+
+ observer = new IntersectionObserver((new_entries) => {
+ entries = entries.concat(new_entries);
+ });
+ observer.observe(target1);
+ observer.observe(target2);
+ observer.observe(target3);
+ observer.observe(target4);
+
+ entries = entries.concat(observer.takeRecords());
+ t.step(() => { assert_equals(entries.length, 0, "No initial notifications") });
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runStep1();
+ });
+ });
+ }
+
+ // Verify that all elements are visible at the start, with intersection events.
+ function runStep1() {
+ const step = arguments.callee.name;
+ t.step(() => {
+ assert_equals(entries.length, 4, step);
+ // Clear the observed visible targets.
+ for (let i = 0; i < entries.length; ++i) {
+ assert_true(entries[i].isIntersecting);
+ assert_true(entries[i].target === target1 ||
+ entries[i].target === target2 ||
+ entries[i].target === target3 ||
+ entries[i].target === target4, step);
+ }
+ });
+
+ entries = [];
+ enqueueStep2();
+ }
+
+ // Lock target3.
+ async function enqueueStep2() {
+ target3.classList.add("hidden");
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runStep2();
+ });
+ });
+ }
+
+ // Verify that the hidden element received a not-intersecting event.
+ function runStep2() {
+ const step = arguments.callee.name;
+ t.step(() => {
+ assert_equals(entries.length, 1, step);
+ assert_false(entries[0].isIntersecting, step);
+ assert_equals(entries[0].target, target4, step);
+ });
+
+ entries = [];
+ enqueueStep3();
+ }
+
+ // Scroll all elements off screen.
+ function enqueueStep3() {
+ document.getElementById("find_me").scrollIntoView();
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runStep3();
+ });
+ });
+ }
+
+ // Verify that all elements received not intersecting event, except
+ // target4, which was already not intersecting due to being hidden.
+ function runStep3() {
+ const step = arguments.callee.name;
+ t.step(() => {
+ assert_equals(entries.length, 3, step);
+ for (let i = 0; i < entries.length; ++i) {
+ assert_false(entries[i].isIntersecting, step);
+ assert_not_equals(entries[i].target, target4, step);
+ }
+ });
+
+ entries = [];
+ enqueueStep4();
+ }
+
+ // Scroll the elements back on screen.
+ function enqueueStep4() {
+ target1.scrollIntoView();
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runStep4();
+ });
+ });
+ }
+
+ // Verify that all elements received not intersecting event, except
+ // target4, which remains not intersecting.
+ function runStep4() {
+ const step = arguments.callee.name;
+ t.step(() => {
+ assert_equals(entries.length, 3, step);
+ for (let i = 0; i < entries.length; ++i) {
+ assert_true(entries[i].isIntersecting);
+ assert_not_equals(entries[i].target, target4, step);
+ }
+ });
+
+ entries = [];
+ enqueueStep5();
+ }
+
+ // Unlock target3.
+ async function enqueueStep5() {
+ target3.classList.remove("hidden");
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runStep5();
+ });
+ });
+ }
+
+ function runStep5() {
+ const step = arguments.callee.name;
+ t.step(() => {
+ assert_equals(entries.length, 1, step);
+ assert_true(entries[0].isIntersecting, step);
+ assert_equals(entries[0].target, target4, step);
+ });
+ t.done();
+ }
+
+
+ window.onload = () => {
+ requestAnimationFrame(enqueueStep1);
+ };
+}, "IntersectionObserver interactions");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-031.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-031.html
new file mode 100644
index 0000000000..134b1c18f7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-031.html
@@ -0,0 +1,76 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: resize observer interactions</title>
+<link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility hidden subtrees do not trigger resize observer">
+
+<style>
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+<div id="container">
+ <div id="resize" style="width: 50px; height: 50px">
+ </div>
+</div>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+async_test((t) => {
+ let didCallback = false;
+
+ async function runTest() {
+ let resizeCallback = function (entries) {
+ didCallback = true;
+ }
+ let resizeObserver = new ResizeObserver(resizeCallback);
+
+ resizeObserver.observe(resize);
+
+ requestAnimationFrame(step2);
+ }
+
+ async function step2() {
+ assert_equals(true, didCallback, 'Resize observation should happen in first frame after registering');
+ didCallback = false;
+
+ const container = document.getElementById("container");
+ container.classList.add("hidden");
+
+ // Change the size of #resize. This should cause a resize observation, but
+ // only when the element becomes unhidden.
+ resize.style.width = '100px';
+
+ requestAnimationFrame(step3);
+ }
+
+ async function step3() {
+ assert_equals(false, didCallback,
+ 'ResizeObsever should not run during while unrendered');
+ requestAnimationFrame(step4);
+ }
+
+ async function step4() {
+ assert_equals(false, didCallback,
+ 'ResizeObsever should not run while unrendered');
+ const container = document.getElementById("container");
+ container.classList.remove("hidden");
+ requestAnimationFrame(step5);
+ }
+
+ async function step5() {
+ assert_equals(true, didCallback,
+ 'ResizeObsevers should now run once becoming visible');
+ t.done();
+ }
+
+ window.onload = function() {
+ requestAnimationFrame(() => requestAnimationFrame(runTest));
+ };
+}, "ResizeObserver skipped while hidden");
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-032-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-032-ref.html
new file mode 100644
index 0000000000..0ab1a659f8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-032-ref.html
@@ -0,0 +1,11 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hidden iframe, size changes (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<p>Test fails if the box below is square.</p>
+<iframe width=200 height=300></iframe>
+</html>
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-032.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-032.html
new file mode 100644
index 0000000000..0a8894f75e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-032.html
@@ -0,0 +1,27 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: hidden iframe, size changes</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-032-ref.html">
+<meta name="assert" content="content-visibility hidden iframes can change size.">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+<p>Test fails if the box below is square.</p>
+<iframe class=hidden id=frame width=200 height=200 srcdoc='Lorem ipsum'></iframe>
+
+<script>
+async function runTest() {
+ document.getElementById("frame").height = 300;
+ requestAnimationFrame(takeScreenshot);
+}
+
+onload = () => { requestAnimationFrame(runTest); };
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-033-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-033-ref.html
new file mode 100644
index 0000000000..0ab1a659f8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-033-ref.html
@@ -0,0 +1,11 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hidden iframe, size changes (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<p>Test fails if the box below is square.</p>
+<iframe width=200 height=300></iframe>
+</html>
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-033.sub.https.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-033.sub.https.html
new file mode 100644
index 0000000000..59bad85af9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-033.sub.https.html
@@ -0,0 +1,27 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Display Locking: locks an iframe, and changes its size</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-033-ref.html">
+<meta name="assert" content="content-visibility hidden cross origin iframe can change size">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+<p>Test fails if the box below is square.</p>
+<iframe id="frame" class=hidden width=200 height=200 src='https://{{domains[www]}}:{{ports[https][0]}}/wpt_internal/display-lock/css-content-visibility/resources/frame.html'></iframe>
+
+<script>
+async function runTest() {
+ document.getElementById("frame").height = 300;
+ requestAnimationFrame(takeScreenshot);
+}
+
+onload = () => { requestAnimationFrame(runTest); };
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-034-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-034-ref.html
new file mode 100644
index 0000000000..f1a2cf57b9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-034-ref.html
@@ -0,0 +1,30 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hidden element shifted down (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ border: 1px solid blue;
+}
+#spacer {
+ width: 100px;
+ height: 100px;
+ background: orange;
+}
+#checker {
+ width: 100px;
+ height: 50px;
+ background: blue;
+}
+</style>
+
+<p>There should be a square blank box (with a blue border) between an orange square and a blue rectangle.
+<div id="spacer"></div>
+<div id="container"></div>
+<div id="checker"></div>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-034.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-034.html
new file mode 100644
index 0000000000..d45200611b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-034.html
@@ -0,0 +1,44 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: hidden element shifted down</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-034-ref.html">
+<meta name="assert" content="content-visibility hidden element participates in layout">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ border: 1px solid blue;
+ content-visibility: hidden;
+}
+#spacer {
+ width: 100px;
+ height: 50px;
+ background: orange;
+}
+#checker {
+ width: 100px;
+ height: 50px;
+ background: blue;
+}
+</style>
+
+<p>There should be a square blank box (with a blue border) between an orange square and a blue rectangle.
+<div id="spacer"></div>
+<div id="container">Fail</div>
+<div id="checker"></div>
+
+<script>
+function runTest() {
+ document.getElementById("spacer").style.height = "100px";
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-035.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-035.html
new file mode 100644
index 0000000000..bc84c28d4a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-035.html
@@ -0,0 +1,59 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Display Locking: hidden shadow descendant</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility hidden element's subtree cannot be focused">
+<meta name="assert" content="content-visibility hidden element's subtree can access layout values">
+
+<body style="margin: 0">
+
+<div id="host">
+ <input id="slotted" type="text">
+</div>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+let container = document.createElement("div");
+container.innerHTML = "<slot></slot>";
+
+let shadowRoot = host.attachShadow({ mode: "open" });
+shadowRoot.innerHTML = "<style>.hidden { content-visibility: hidden; }</style>";
+shadowRoot.appendChild(container);
+
+async_test((t) => {
+ async function focusTest() {
+ t.step(() => assert_not_equals(document.activeElement, slotted));
+ t.step(() => assert_not_equals(shadowRoot.activeElement, slotted));
+
+ container.classList.add("hidden");
+ requestAnimationFrame(() => {
+ t.step(() => assert_not_equals(document.activeElement, slotted));
+ t.step(() => assert_not_equals(shadowRoot.activeElement, slotted));
+
+ slotted.focus();
+ t.step(() => assert_not_equals(document.activeElement, slotted));
+ t.step(() => assert_not_equals(shadowRoot.activeElement, slotted));
+
+ forceLayoutTest();
+ });
+ }
+
+ async function forceLayoutTest() {
+ t.step(() => assert_equals(slotted.offsetTop, 0));
+ // Add a 20px div above the slotted div.
+ container.innerHTML = "<div style='height: 20px;'></div><slot></slot>";
+ t.step(() => assert_equals(slotted.offsetTop, 20));
+ t.done();
+ }
+
+ window.onload = function() {
+ requestAnimationFrame(() => requestAnimationFrame(focusTest));
+ };
+}, "Testing focus and force layout on element with hidden flat-tree ancestor");
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-036.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-036.html
new file mode 100644
index 0000000000..8dc56e9145
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-036.html
@@ -0,0 +1,61 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Display Locking: style on hidden element & child</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="style is available for content-visibility hidden elements">
+
+<style>
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+<div id="container" class=hidden>
+ <div id="child">
+ <div id="grandchild"></div>
+ </div>
+</div>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+async_test((t) => {
+ async function runTest() {
+ let container = document.getElementById("container");
+ container.style = "color: blue;";
+ t.step(() => assert_equals(getComputedStyle(container).color, "rgb(0, 0, 255)", "container color changed to blue"));
+ t.step(() => assert_equals(getComputedStyle(child).color, "rgb(0, 0, 255)", "child inherits blue color"));
+ t.step(() => assert_equals(getComputedStyle(grandchild).color, "rgb(0, 0, 255)", "grandchild inherits blue color"));
+
+ child.style = "color: green;";
+ t.step(() => assert_equals(getComputedStyle(container).color, "rgb(0, 0, 255)", "container color is still blue"));
+ t.step(() => assert_equals(getComputedStyle(child).color, "rgb(0, 128, 0)", "child color changed to green"));
+ t.step(() => assert_equals(getComputedStyle(grandchild).color, "rgb(0, 128, 0)", "grandchild inherits green color"));
+
+ child.style = "";
+
+ // Commit container, lock child.
+ container.classList.remove("hidden");
+ child.classList.add("hidden");
+ requestAnimationFrame(() => {
+ // Update style outside of the hidden subtree.
+ container.style = "color: red;";
+ container.offsetTop;
+
+ // Inheritance works as usual through hidden boundaries.
+ t.step(() => assert_equals(getComputedStyle(grandchild).color, "rgb(255, 0, 0)", "grandchild inherits red color"));
+ t.step(() => assert_equals(getComputedStyle(child).color, "rgb(255, 0, 0)", "child inherits red color"));
+ t.step(() => assert_equals(getComputedStyle(container).color, "rgb(255, 0, 0)", "container color changed to red"));
+
+ t.done();
+ });
+ }
+
+ window.onload = function() {
+ requestAnimationFrame(() => requestAnimationFrame(runTest));
+ };
+}, "getComputedStyle gets up-to-date style");
+</script>
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-037.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-037.html
new file mode 100644
index 0000000000..c40b22026b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-037.html
@@ -0,0 +1,39 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: hidden grid with positioned child</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="content-visibility hidden grid does not paint the subtree">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#grid {
+ display: grid;
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+#positioned {
+ position: absolute;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<div id=grid>
+ <div id=positioned>Test fails if this text is visible.</div>
+</div>
+
+<script>
+function runTest() {
+ document.getElementById("grid").classList.add("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => requestAnimationFrame(runTest);
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-038.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-038.html
new file mode 100644
index 0000000000..638a336c91
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-038.html
@@ -0,0 +1,107 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: measure layout</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility hidden element layout is correct">
+<meta name="assert" content="content-visibility hidden element's subtree layout is correct">
+
+<style>
+#container {
+ background: lightgreen;
+ contain: layout;
+}
+.hidden {
+ content-visibility: hidden;
+}
+#sizer {
+ width: 100px;
+ height: 100px;
+}
+.child {
+ width: 20px;
+ height: 20%;
+ background: cyan;
+}
+#spacer {
+ width: 150px;
+ height: 150px;
+ background: green;
+}
+</style>
+
+<div id="parent"></div>
+<div id="spacer"></div>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+async_test((t) => {
+ function createChild(id) {
+ const child = document.createElement("div");
+ child.classList = "child";
+ child.id = id;
+ return child;
+ }
+
+ function measureForced() {
+ t.step(() => {
+ // Ensure children are laid out; this forces a layout if it wasn't done.
+ assert_equals(document.getElementById("0").offsetTop, 0, "0 forced");
+ assert_equals(document.getElementById("1").offsetTop, 20, "1 forced");
+ assert_equals(document.getElementById("2").offsetTop, 40, "2 forced");
+ // Both parent should be 0 height, since it's hidden. Both parent and spacers
+ // should have 8 offsetTop.
+ assert_equals(document.getElementById("parent").offsetTop, 8, "parent forced");
+ assert_equals(document.getElementById("spacer").offsetTop, 8, "spacer forced");
+ });
+ }
+
+ function measureWhenVisible() {
+ t.step(() => {
+ // Ensure children are still laid out.
+ assert_equals(document.getElementById("0").offsetTop, 0, "0 when visible");
+ assert_equals(document.getElementById("1").offsetTop, 20, "1 when visible");
+ assert_equals(document.getElementById("2").offsetTop, 40, "2 when visible");
+ // Now the parent should encompass a container, so spacer is pushed down.
+ assert_equals(document.getElementById("parent").offsetTop, 8, "parent when visible");
+ assert_equals(document.getElementById("spacer").offsetTop, 108, "spacer when visible");
+ });
+ }
+
+ function construct(container) {
+ const sizer = document.createElement("div");
+ sizer.id = "sizer";
+ container.appendChild(sizer);
+ sizer.appendChild(createChild("0"));
+ sizer.appendChild(createChild("1"));
+ sizer.appendChild(createChild("2"));
+ }
+
+ async function runTest() {
+ const container = document.createElement("div");
+ container.id = "container";
+
+ document.getElementById("parent").appendChild(container);
+ container.classList.add("hidden");
+ requestAnimationFrame(() => {
+ construct(container);
+ measureForced();
+
+ container.classList.remove("hidden");
+ requestAnimationFrame(() => requestAnimationFrame(() => {
+ measureWhenVisible();
+ t.done();
+ }));
+ });
+ }
+
+ window.onload = function() {
+ requestAnimationFrame(() => requestAnimationFrame(runTest));
+ };
+}, "Measure Forced Layout");
+</script>
+
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-039.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-039.html
new file mode 100644
index 0000000000..481dcc4583
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-039.html
@@ -0,0 +1,79 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Display Locking: measure forced SVG text</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility hidden svg descendant has correct layout">
+
+<style>
+#container {
+ width: 100px;
+ height: 100px;
+ background: lightgreen;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<div id="parent"></div>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+async_test((t) => {
+ let length;
+ function measureForced() {
+ t.step(() => {
+ length = document.getElementById("text").getComputedTextLength();
+ assert_not_equals(length, 0, "forced");
+
+ });
+ }
+
+ function measureWhenVisible() {
+ t.step(() => {
+ const visible_length = document.getElementById("text").getComputedTextLength();
+ assert_not_equals(visible_length, 0, "when visible");
+ assert_equals(visible_length, length, "when visible");
+ });
+ }
+
+ function construct(container) {
+ container.innerHTML = `
+ <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
+ <style>
+ .t { font: 10px sans-serif; }
+ </style>
+ <text id="text" x="10" y="10" class="t">This is text</text>
+ </svg>
+ `;
+ }
+
+ async function runTest() {
+ const container = document.createElement("div");
+ container.id = "container";
+
+ document.getElementById("parent").appendChild(container);
+ container.classList.add("hidden");
+ requestAnimationFrame(() => {
+ construct(container);
+ measureForced();
+
+ container.classList.remove("hidden");
+ requestAnimationFrame(() => {
+ measureWhenVisible();
+ t.done();
+ });
+ });
+ }
+
+ window.onload = function() {
+ requestAnimationFrame(() => requestAnimationFrame(runTest));
+ };
+}, "Measure Forced SVG Text");
+</script>
+
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-040.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-040.html
new file mode 100644
index 0000000000..cf2e214e1a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-040.html
@@ -0,0 +1,45 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Display Locking: absolute positioned in flex, which is in a hidden div.</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="content-visibility hidden flex and abspos descendants don't paint">
+
+<script src="/common/reftest-wait.js"></script>
+<script src="resources/utils.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+ position: relative;
+}
+div > div {
+ width: 100px;
+ height: 100px;
+ background: red;
+}
+.hidden {
+ content-visibility: hidden;
+}
+.flex { display: flex; }
+.abspos { position: absolute; }
+</style>
+
+<div id=container>
+ <div class=flex>
+ <div class=abspos></div>
+ </div>
+</div>
+
+<script>
+async function runTest() {
+ document.getElementById("container").classList.add("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-041.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-041.html
new file mode 100644
index 0000000000..82c4feb131
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-041.html
@@ -0,0 +1,43 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: pseudo elements</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="subtree-visiblity hidden doesn't paint ::before or ::after">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+#container::before {
+ content: "FAIL! ";
+ color: red;
+}
+.hasAfter::after {
+ content: "FAIL!";
+ background: red;
+ color: white;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+<div id="log"></div>
+<div id="container" style="display:none;"></div>
+
+<script>
+async function runTest() {
+ container.classList.add("hasAfter");
+ container.classList.add("hidden");
+ container.style = "";
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = runTest;
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-042-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-042-ref.html
new file mode 100644
index 0000000000..a76d5397c3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-042-ref.html
@@ -0,0 +1,21 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: pseudo elements</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+#container::before {
+ content: "This test ";
+ color: green;
+}
+#container::after {
+ content: "PASSES.";
+ background: green;
+ color: white;
+}
+</style>
+<div id="container"></div>
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-042.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-042.html
new file mode 100644
index 0000000000..381af12dc5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-042.html
@@ -0,0 +1,38 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: pseudo elements</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-042-ref.html">
+<meta name="assert" content="content-visibility elements paints ::before and ::after when hidden is removed">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container::before {
+ content: "This test ";
+ color: green;
+}
+.hasAfter::after {
+ content: "PASSES.";
+ background: green;
+ color: white;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+<div id="container" class=hidden style="display:none;"></div>
+
+<script>
+async function runTest() {
+ container.classList.add("hasAfter");
+ container.classList.remove("hidden");
+ container.style = "";
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = runTest;
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-043.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-043.html
new file mode 100644
index 0000000000..a230315e69
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-043.html
@@ -0,0 +1,41 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: scroll child into view, and adopt to a document</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="scrollIntoView on a hidden subtree is a no-op">
+<meta name="assert" content="adopting an element in a hidden subtree works (no asserts / crashes)">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+ color: red;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+<div id=container class=hidden>
+ FAIL.
+ <div id=child></div>
+</div>
+
+<script>
+function moveChild() {
+ child.scrollIntoView();
+ document.implementation.createDocument( "", null).adoptNode(child);
+ requestAnimationFrame(takeScreenshot);
+}
+
+async function runTest() {
+ requestAnimationFrame(moveChild);
+}
+
+window.onload = requestAnimationFrame(runTest);
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-044.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-044.html
new file mode 100644
index 0000000000..f8b9463447
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-044.html
@@ -0,0 +1,34 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: slot moved after container is hidden</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="ensure that hidden slotted element can be updated">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body style="margin: 0">
+
+<div id=host>
+<input id=slotted style="margin: 0">
+<script>
+
+async_test((t) => {
+ let container = document.createElement("div");
+ container.innerHTML = "<slot></slot>";
+ let shadowRoot = host.attachShadow({ mode: "open" });
+ shadowRoot.innerHTML = "<style>.hidden { content-visibility: hidden }</style>";
+ shadowRoot.appendChild(container);
+
+ t.step(async () => {
+ container.classList.add("hidden");
+ requestAnimationFrame(() => {
+ assert_equals(slotted.offsetTop, 0);
+ container.innerHTML = "<div style='height: 20px;'></div><slot></slot>";
+ t.done();
+ });
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-045.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-045.html
new file mode 100644
index 0000000000..b965d4d1a0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-045.html
@@ -0,0 +1,52 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: auto subtree becomes hidden in the viewport</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="content-visibility:auto subtree becomes hidden and so stops painting">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: red;
+}
+.auto { content-visibility: auto; }
+.hidden { content-visibility: hidden; }
+
+</style>
+
+<div id=container class=auto>
+ Test fails if you see this text or a red box.
+ <div id=child></div>
+</div>
+
+<script>
+
+function runTest() {
+ document.getElementById("container").classList.remove("auto");
+ document.getElementById("container").classList.add("hidden");
+
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runTest();
+ });
+ });
+});
+
+</script>
+</html>
+
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-046.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-046.html
new file mode 100644
index 0000000000..6f1cd28e39
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-046.html
@@ -0,0 +1,45 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: viewport auto painting.</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-with-child-ref.html">
+<meta name="assert" content="viewport intersection paints the content-visibility auto element">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: green;
+}
+.auto {
+ content-visibility: auto;
+}
+</style>
+
+<div id=container class=auto>
+ Test passes if you can see this text and a green box.
+ <div id=child></div>
+</div>
+
+<script>
+
+function runTest() {
+ document.getElementById("target").classList.add("auto");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(
+ () => requestAnimationFrame(takeScreenshot));
+
+</script>
+</html>
+
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-047.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-047.html
new file mode 100644
index 0000000000..bb5399280d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-047.html
@@ -0,0 +1,48 @@
+<!doctype HTML>
+<meta charset="utf8">
+<title>Content Visibility: tab order navigation ignores hidden subtrees</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="tab order navigation ignores hidden subtrees.">
+
+<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>
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<input id=one type=text></input>
+<div class=hidden>
+ <input id=two type=text></input>
+ <input id=three type=text></input>
+ <input id=four type=text></input>
+</div>
+<input id=five type=text></input>
+
+<script>
+async_test((t) => {
+ const tab = "\uE004";
+
+ async function runTest() {
+ await test_driver.send_keys(document.body, tab);
+ t.step(() => {
+ assert_equals(document.activeElement, document.getElementById("one"));
+ });
+
+ await test_driver.send_keys(document.body, tab);
+ t.step(() => {
+ assert_equals(document.activeElement, document.getElementById("five"));
+ });
+
+ t.done();
+ }
+
+ window.onload = () => { requestAnimationFrame(runTest); };
+}, "Tab order navigation skips hidden subtrees");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-048.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-048.html
new file mode 100644
index 0000000000..2b8679b5dd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-048.html
@@ -0,0 +1,46 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: navigating to a text fragment.</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="timeout" content="long">
+<meta name="assert" content="content-visibility: auto subtrees are 'searchable' by text fragment links">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/scroll-to-text-fragment/stash.js"></script>
+
+<script>
+promise_test(t => new Promise((resolve, reject) => {
+ const fragment = '#:~:text=hiddentext';
+ const key = token();
+ test_driver.bless("Open a URL with a text fragment directive", () => {
+ window.open(`resources/text-fragment-target-auto.html?key=${key}${fragment}`,
+ '_blank',
+ 'noopener');
+ });
+ fetchResults(key, resolve, reject);
+}).then(data => {
+ assert_equals(data.scrollPosition, "text");
+ assert_equals(data.target, "text");
+}), "Fragment navigation with content-visibility; single text");
+
+promise_test(t => new Promise((resolve, reject) => {
+ const fragment = '#:~:text=start,end';
+ const key = token();
+ test_driver.bless("Open a URL with a text fragment directive", () => {
+ window.open(`resources/text-fragment-target-auto.html?key=${key}${fragment}`,
+ '_blank',
+ 'noopener');
+ });
+ fetchResults(key, resolve, reject);
+}).then(data => {
+ assert_equals(data.scrollPosition, "text2");
+ assert_equals(data.target, "text2and3ancestor");
+}), "Fragment navigation with content-visibility; range across blocks");
+</script>
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-049-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-049-ref.html
new file mode 100644
index 0000000000..be5fd78a34
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-049-ref.html
@@ -0,0 +1,33 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: anchor links paint subtrees (reference)</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#container {
+ contain: style layout;
+ width: 150px;
+ height: 150px;
+ background: lightgreen;
+}
+#target {
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+</style>
+
+<div class="spacer"></div>
+<div id="container"><div id="target"></div></div>
+
+<script>
+target.scrollIntoView();
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-049.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-049.html
new file mode 100644
index 0000000000..f130d77b66
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-049.html
@@ -0,0 +1,43 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: anchor links paint subtrees</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-049-ref.html">
+<meta name="assert" content="content-visibility auto subtrees respond to anchor links">
+
+<script src="/common/reftest-wait.js"></script>
+<script src="../resources/utils.js"></script>
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightgreen;
+ content-visibility: auto;
+}
+#target {
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+</style>
+
+<div class="spacer"></div>
+<div id="container"><div id="target"></div></div>
+
+<script>
+function runTest() {
+ location.href += "#target";
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-050.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-050.html
new file mode 100644
index 0000000000..bcc4f5e430
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-050.html
@@ -0,0 +1,39 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: focus on new element</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="focus can target content-visibility: auto subtrees created while hidden">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+.auto {
+ content-visibility: auto;
+}
+.spacer {
+ height: 3000px;
+}
+</style>
+
+<div class=spacer></div>
+<div id=container class=auto></div>
+
+<script>
+async_test((t) => {
+ function runTest() {
+ const focusable = document.createElement("div");
+ focusable.tabIndex = 0;
+ container.appendChild(focusable);
+ focusable.focus();
+ requestAnimationFrame(() => {
+ t.step(() => assert_greater_than(document.scrollingElement.scrollTop, 500));
+ t.done();
+ });
+ }
+ onload = requestAnimationFrame(() => requestAnimationFrame(runTest));
+}, "Using tabindex to focus an newly constructed element in an auto subtree focuses element");
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-051.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-051.html
new file mode 100644
index 0000000000..15718cad32
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-051.html
@@ -0,0 +1,44 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: switching to block stop painting</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="content-visibility has no effect on non-atomic inlines, but switching to block stop painting">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ content-visibility: hidden;
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+.inline {
+ display: inline;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: red;
+}
+</style>
+
+<div id=container class=inline>
+ Test fails if you see this text or a red box.
+ <div id=child></div>
+ <span>Fail.</span>
+</div>
+
+<script>
+function runTest() {
+ const container = document.getElementById("container");
+ container.classList.remove("inline");
+ takeScreenshot();
+}
+
+window.onload = () => requestAnimationFrame(runTest);
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-052.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-052.html
new file mode 100644
index 0000000000..2df45ae149
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-052.html
@@ -0,0 +1,73 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden starts painting when removed</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-with-pos-children-ref.html">
+<meta name="assert" content="content-visibility subtrees start painting when hidden is removed">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+ contain: layout;
+}
+.hidden {
+ content-visibility: hidden;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: lightgreen;
+}
+.abspos { position: absolute; }
+.relpos { position: relative; }
+.fixedpos { position: fixed; }
+.start { top: 0; left: 0; }
+.mid { top: 10px; left: 10px; }
+.end { bottom: 0; right: 0; }
+.zindex { z-index: 1; }
+.small { width: 10px; height: 10px; background: blue; }
+.medium { width: 20px; height: 20px; background: green; }
+.large { width: 30px; height: 30px; background: pink; }
+</style>
+
+<p>This test passes if the two light blue boxes below have the same content.
+<div id=container class="container hidden">
+ Text.
+ <div id=child></div>
+ <span>inline child</span>
+ <div class="abspos start small"></div>
+ <div class="relpos mid medium"></div>
+ <div class="fixedpos end large"></div>
+ <div class=relpos>
+ <div class="abspos mid small zindex"></div>
+ </div>
+</div>
+<br>
+<div class="container">
+ Text.
+ <div id=child></div>
+ <span>inline child</span>
+ <div class="abspos start small"></div>
+ <div class="relpos mid medium"></div>
+ <div class="fixedpos end large"></div>
+ <div class=relpos>
+ <div class="abspos mid small zindex"></div>
+ </div>
+</div>
+
+<script>
+function runTest() {
+ const container = document.getElementById("container");
+ container.classList.remove("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = runTest;
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-053.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-053.html
new file mode 100644
index 0000000000..ebdaecbc62
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-053.html
@@ -0,0 +1,30 @@
+<html>
+<meta charset="utf8">
+<title>Content Visibility: focus on display none element</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="tab navigation skips display none elements in an auto subtree">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id=spacer style="height: 3000px"></div>
+<div id="host">
+ <input id="slotted" type="text">
+</div>
+
+<script>
+test(() => {
+ const container = document.createElement("div");
+ container.innerHTML = "<slot></slot>";
+ container.style = "content-visibility: auto";
+
+ const shadowRoot = host.attachShadow({ mode: "open" });
+ shadowRoot.appendChild(container);
+
+ assert_not_equals(document.activeElement, slotted);
+ slotted.focus();
+ assert_equals(document.activeElement, slotted);
+}, "Targetting a slotted auto-hidden element with focus makes it the active element");
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-054.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-054.html
new file mode 100644
index 0000000000..232dc0d7b1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-054.html
@@ -0,0 +1,34 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Display Locking: focus on styled element</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="focus does not target display-none but hidden elements">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="container" style="content-visibility: auto">
+ <div id="focusable1" tabIndex="0">
+ focusable thing
+ </div>
+ <div id="displayNoneParent">
+ <div id="focusable2" tabIndex="0">
+ focusable thing
+ </div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ focusable1.style.display = "none";
+ focusable1.focus();
+ assert_not_equals(document.activeElement, focusable1);
+
+ displayNoneParent.style.display = "none";
+ focusable2.focus();
+ assert_not_equals(document.activeElement, focusable2);
+}, "Trying to focus on an element in a hidden subtree with display none will not work");
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-055.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-055.html
new file mode 100644
index 0000000000..3dae93a504
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-055.html
@@ -0,0 +1,42 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: anchor links prevented</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="spacer-and-container-scrolled-ref.html">
+<meta name="assert" content="anchor link scroll not prevented when the target is hidden and activatable">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ width: 150px;
+ height: 300vh;
+ background: lightblue;
+}
+#container {
+ width: 150px;
+ height: 150px;
+ background: green;
+ content-visibility: auto;
+}
+
+#target {
+ width: 150px;
+ height: 100px;
+}
+</style>
+
+<div class="spacer"></div>
+<div id="container"><div id="target">Test passes if this is on screen.</div></div>
+
+<script>
+function runTest() {
+ location.href += "#target";
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-056.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-056.html
new file mode 100644
index 0000000000..dae94aa095
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-056.html
@@ -0,0 +1,42 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: scrollIntoView prevented</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="spacer-and-container-ref.html">
+<meta name="assert" content="scrollIntoView is prevented when the target is hidden">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#container {
+ width: 150px;
+ height: 150px;
+ background: red;
+ content-visibility: hidden;
+}
+#target {
+ width: 100px;
+ height: 100px;
+ background: pink;
+}
+</style>
+
+<div class="spacer">Test passes if there is no red.</div>
+<div id="container"><div id="target">FAIL</div></div>
+
+<script>
+function runTest() {
+ document.getElementById("target").scrollIntoView();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-057.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-057.html
new file mode 100644
index 0000000000..d6a0d4f697
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-057.html
@@ -0,0 +1,52 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: hidden subtree becomes auto in the viewport</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-with-child-ref.html">
+<meta name="assert" content="hidden subtree becomes auto and then paints">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: green;
+}
+.auto { content-visibility: auto; }
+.hidden { content-visibility: hidden; }
+
+</style>
+
+<div id=container class=hidden>
+ Test passes if you can see this text and a green box.
+ <div id=child></div>
+</div>
+
+<script>
+
+function runTest() {
+ document.getElementById("container").classList.remove("hidden");
+ document.getElementById("container").classList.add("auto");
+
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runTest();
+ });
+ });
+});
+
+</script>
+</html>
+
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-058-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-058-ref.html
new file mode 100644
index 0000000000..a98e4a856a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-058-ref.html
@@ -0,0 +1,61 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: auto, scrollIntoView() (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ height: 10000px;
+}
+.container {
+ position: relative;
+ width: 150px;
+ background: lightblue;
+ contain-intrinsic-size: 50px 250px;
+}
+.size_contained {
+ contain: size;
+}
+.child {
+ width: 50px;
+ height: 300px;
+ background: lightgreen;
+}
+#target {
+ position: absolute;
+ bottom: 0;
+
+ width: 10px;
+ height: 10px;
+ background: blue;
+}
+</style>
+
+<p>Test FAILS if this sentence is at the top of the screen.
+<div class=spacer></div>
+<div id=container class="container">
+ <div class=child></div>
+ <div id=target></div>
+</div>
+<p>Test PASSES if this sentence is near the top of the screen, after a thin band of three colors.
+<div class=spacer></div>
+
+<script>
+
+function runReference() {
+ document.getElementById("target").scrollIntoView(true /* alignToTop */);
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runReference();
+ });
+ });
+});
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-058.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-058.html
new file mode 100644
index 0000000000..fe9d70b60f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-058.html
@@ -0,0 +1,65 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: auto, scrollIntoView()</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-058-ref.html">
+<meta name="assert" content="scrollIntoView() uses contain:size information to find target offset">
+<meta name="assert" content="viewport intersection removes contain:size thus moving target">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ height: 10000px;
+}
+.container {
+ width: 150px;
+ background: lightblue;
+ contain-intrinsic-size: 50px 250px;
+}
+.child {
+ width: 50px;
+ height: 300px;
+ background: lightgreen;
+}
+#target {
+ position: absolute;
+ bottom: 0;
+
+ width: 10px;
+ height: 10px;
+ background: blue;
+}
+.auto { content-visibility: auto; }
+
+</style>
+
+<p>Test FAILS if this sentence is at the top of the screen.
+<div class=spacer></div>
+<div class="container auto">
+ <div class=child></div>
+ <div id=target></div>
+</div>
+<p>Test PASSES if this sentence is near the top of the screen, after a thin band of three colors.
+<div class=spacer></div>
+
+<script>
+
+function runTest() {
+ document.getElementById("target").scrollIntoView(true /* alignToTop */);
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runTest();
+ });
+ });
+});
+
+</script>
+</html>
+
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-060.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-060.html
new file mode 100644
index 0000000000..84b7bc9c14
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-060.html
@@ -0,0 +1,57 @@
+<!doctype HTML>
+
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden + scrollIntoView on display:none</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="spacer-and-container-ref.html">
+<meta name="assert" content="scrollIntoView ignores display:none element in a hidden subtree">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#container {
+ width: 150px;
+ height: 150px;
+ background: red;
+}
+#target {
+ display: none;
+
+ position: relative;
+ top: 75px;
+
+ width: 50px;
+ height: 50px;
+ background: red;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<div class=spacer>Test passes if there is no red.</div>
+<div id=container class=hidden>
+ <div id=target></div>
+</div>
+
+<script>
+function runTest() {
+ document.getElementById("target").scrollIntoView();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runTest();
+ });
+ });
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-061.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-061.html
new file mode 100644
index 0000000000..2181799a29
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-061.html
@@ -0,0 +1,57 @@
+<!doctype HTML>
+
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden + scrollIntoView on display:contents</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="spacer-and-container-ref.html">
+<meta name="assert" content="scrollIntoView ignores display:contents element in a hidden subtree">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#container {
+ width: 150px;
+ height: 150px;
+ background: red;
+}
+#target {
+ display: contents;
+
+ position: relative;
+ top: 75px;
+
+ width: 50px;
+ height: 50px;
+ background: pink;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<div class=spacer>Test passes if there is no red.</div>
+<div id=container class=hidden>
+ <div id=target>FAIL</div>
+</div>
+
+<script>
+function runTest() {
+ document.getElementById("target").scrollIntoView();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runTest();
+ });
+ });
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-062.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-062.html
new file mode 100644
index 0000000000..ab99e82014
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-062.html
@@ -0,0 +1,57 @@
+<!doctype HTML>
+
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: auto + scrollIntoView on display:none</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="spacer-and-container-ref.html">
+<meta name="assert" content="scrollIntoView ignores display:none element in an auto subtree">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#container {
+ width: 150px;
+ height: 150px;
+ background: red;
+}
+#target {
+ display: none;
+
+ position: relative;
+ top: 75px;
+
+ width: 50px;
+ height: 50px;
+ background: pink;
+}
+.auto {
+ content-visibility: auto;
+}
+</style>
+
+<div class=spacer>Test passes if there is no red.</div>
+<div id=container class=auto>
+ <div id=target>FAIL</div>
+</div>
+
+<script>
+function runTest() {
+ document.getElementById("target").scrollIntoView();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runTest();
+ });
+ });
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-063.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-063.html
new file mode 100644
index 0000000000..e8a0146019
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-063.html
@@ -0,0 +1,57 @@
+<!doctype HTML>
+
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: auto + scrollIntoView on display:contents</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="spacer-and-container-ref.html">
+<meta name="assert" content="scrollIntoView ignores display:contents element in an auto subtree">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#container {
+ width: 150px;
+ height: 150px;
+ background: red;
+}
+#target {
+ display: contents;
+
+ position: relative;
+ top: 75px;
+
+ width: 50px;
+ height: 50px;
+ background: pink;
+}
+.auto {
+ content-visibility: auto;
+}
+</style>
+
+<div class=spacer>Test passes if there is no red.</div>
+<div id=container class=auto>
+ <div id=target>FAIL</div>
+</div>
+
+<script>
+function runTest() {
+ document.getElementById("target").scrollIntoView();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runTest();
+ });
+ });
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-064-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-064-ref.html
new file mode 100644
index 0000000000..814c8fba6a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-064-ref.html
@@ -0,0 +1,57 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden + scrollIntoView (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ height: 1000px;
+ background: lightblue;
+}
+#container {
+ position: relative;
+ width: 150px;
+ background: lightblue;
+ contain: paint;
+}
+#child {
+ width: 150px;
+ height: 300px;
+}
+#target {
+ position: absolute;
+ bottom: 0;
+
+ width: 50px;
+ height: 50px;
+ background: green;
+}
+</style>
+
+<div>top of the page</div>
+<div class=spacer></div>
+<div id=container>
+ <div id=child></div>
+ <div id=target tabindex=0>PASS</div>
+</div>
+<div class=spacer></div>
+<div>bottom of the page</div>
+
+<script>
+function runReference() {
+ document.getElementById("target").focus();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runReference();
+ });
+ });
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-064.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-064.html
new file mode 100644
index 0000000000..1098e75957
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-064.html
@@ -0,0 +1,64 @@
+<!doctype HTML>
+
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: auto + focus</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-064-ref.html">
+<meta name="assert" content="focus() can focus auto skipped subtree elements">
+<meta name="assert" content="focus() scrolls after removing contain:size">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ height: 1000px;
+ background: lightblue;
+}
+#container {
+ width: 150px;
+ background: lightblue;
+ contain-intrinsic-size: 50px 150px;
+ contain: paint;
+}
+#child {
+ width: 150px;
+ height: 300px;
+}
+#target {
+ position: absolute;
+ bottom: 0;
+
+ width: 50px;
+ height: 50px;
+ background: green;
+}
+.auto {
+ content-visibility: auto;
+}
+</style>
+
+<div>top of the page</div>
+<div class=spacer></div>
+<div id=container class=auto>
+ <div id=child></div>
+ <div id=target tabindex=0>PASS</div>
+</div>
+<div class=spacer></div>
+<div>bottom of the page</div>
+
+<script>
+function runTest() {
+ document.getElementById("target").focus();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runTest();
+ });
+ });
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-065.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-065.html
new file mode 100644
index 0000000000..341f259b4c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-065.html
@@ -0,0 +1,57 @@
+<!doctype HTML>
+
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: auto + focus on display:none</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="spacer-and-container-ref.html">
+<meta name="assert" content="focus ignores display:none element in an auto subtree">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#container {
+ width: 150px;
+ height: 150px;
+ background: red;
+}
+#target {
+ display: none;
+
+ position: relative;
+ top: 75px;
+
+ width: 50px;
+ height: 50px;
+ background: red;
+}
+.auto {
+ content-visibility: auto;
+}
+</style>
+
+<div class=spacer>Test passes if there is no red.</div>
+<div id=container class=auto>
+ <div id=target tabindex=0></div>
+</div>
+
+<script>
+function runTest() {
+ document.getElementById("target").focus();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runTest();
+ });
+ });
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-066.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-066.html
new file mode 100644
index 0000000000..d608d301f4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-066.html
@@ -0,0 +1,57 @@
+<!doctype HTML>
+
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: auto + focus on display:contents</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="spacer-and-container-ref.html">
+<meta name="assert" content="focus ignores display:contents element in an auto subtree">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#container {
+ width: 150px;
+ height: 150px;
+ background: red;
+}
+#target {
+ display: contents;
+
+ position: relative;
+ top: 75px;
+
+ width: 50px;
+ height: 50px;
+ background: red;
+}
+.auto {
+ content-visibility: auto;
+}
+</style>
+
+<div class=spacer>Test passes if there is no red.</div>
+<div id=container class=auto>
+ <div id=target tabindex=0>FAIL</div>
+</div>
+
+<script>
+function runTest() {
+ document.getElementById("target").focus();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runTest();
+ });
+ });
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-067.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-067.html
new file mode 100644
index 0000000000..843a3bb6a9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-067.html
@@ -0,0 +1,55 @@
+<!doctype HTML>
+
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: hidden + focus</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="spacer-and-container-ref.html">
+<meta name="assert" content="focus ignores element in a hidden subtree">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#container {
+ width: 150px;
+ height: 150px;
+ background: red;
+}
+#target {
+ position: relative;
+ top: 75px;
+
+ width: 50px;
+ height: 50px;
+ background: red;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<div class=spacer>Test passes if there is no red.</div>
+<div id=container class=hidden>
+ <div id=target tabindex=0>FAIL</div>
+</div>
+
+<script>
+function runTest() {
+ document.getElementById("target").focus();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runTest();
+ });
+ });
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-068.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-068.html
new file mode 100644
index 0000000000..90762f3345
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-068.html
@@ -0,0 +1,103 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: off-screen focus</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility auto element remains non-skipped when elements in its subtree have focus.">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body, html {
+ padding: 0;
+ margin: 0;
+}
+
+.spacer {
+ height: 3000px;
+ background: lightblue;
+}
+#container {
+ background: lightgreen;
+ contain-intrinsic-size: 50px 100px;
+ content-visibility: auto;
+}
+#focusable {
+ width: 10px;
+ height: 10px;
+}
+</style>
+
+<div id=end tabindex=1></div>
+<div class=spacer></div>
+<div id=container>
+ <div id=focusable tabindex=0></div>
+</div>
+<div class=spacer></div>
+
+<script>
+async_test((t) => {
+ // Initially container should be 3000px offscreen with contained height 100px.
+ function step1() {
+ const r = container.getBoundingClientRect();
+ t.step(() => {
+ assert_equals(r.y, 3000, "step1 offset");
+ assert_equals(r.height, 100, "step1 height");
+ });
+
+ focusable.focus();
+ requestAnimationFrame(step2);
+ }
+ // After focusing the subtree, the container should be somewhere closer than
+ // 3000px (scrolled into view) and the height should be 10px, since it no
+ // longer has containment.
+ function step2() {
+ const r = container.getBoundingClientRect();
+ t.step(() => {
+ assert_less_than(r.y, 3000, "step2 offset");
+ assert_equals(r.height, 10, "step2 height");
+ });
+ document.scrollingElement.scrollTop = 0;
+ requestAnimationFrame(step3);
+ }
+ // After scrolling the document back to the top, the container should be back
+ // at 3000px but because its subtree is still focused, it should have height
+ // 10px.
+ function step3() {
+ const r = container.getBoundingClientRect();
+ t.step(() => {
+ assert_equals(r.y, 3000, "step3 offset");
+ assert_equals(r.height, 10, "step3 height");
+ });
+ requestAnimationFrame(step4);
+ }
+ // This is a repeat of step3, to ensure that this is a stable state.
+ function step4() {
+ const r = container.getBoundingClientRect();
+ t.step(() => {
+ assert_equals(r.y, 3000, "step4 offset");
+ assert_equals(r.height, 10, "step4 height");
+ });
+
+ // We don't use `blur()` here because in Gecko this leaves the selection
+ // on _focusable_ which means that its content is still relevant. Focusing
+ // another element will move both focus and selection.
+ end.focus();
+ requestAnimationFrame(step5);
+ }
+ // After blurring the focused element, we should go back to the contained
+ // height of 100px.
+ function step5() {
+ const r = container.getBoundingClientRect();
+ t.step(() => {
+ assert_equals(r.y, 3000, "step5 offset");
+ assert_equals(r.height, 100, "step5 height");
+ });
+ t.done();
+ }
+ step1();
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-069.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-069.html
new file mode 100644
index 0000000000..89cbd1dc93
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-069.html
@@ -0,0 +1,53 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: pending visibility changes</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="disconnecting elements while visibility state adjustments are pending does not crash">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body {
+ margin: 0;
+ padding: 0;
+}
+.spacer {
+ height: 3000px;
+}
+.auto {
+ content-visibility: auto;
+ width: 5px;
+ height: 5px;
+}
+</style>
+
+<body id="body">
+<div id=one class=auto>text</div>
+<div class=spacer></div>
+<div id=two class=auto>text</div>
+<div class=spacer></div>
+</body>
+
+<script>
+async_test((t) => {
+ function runTest() {
+ document.scrollingElement.scrollTop = 2990;
+
+ const range = document.createRange();
+ range.selectNodeContents(one);
+ window.getSelection().addRange(range);
+
+ requestAnimationFrame(() => {
+ one.remove();
+ two.remove();
+ t.done();
+ });
+ }
+ onload = requestAnimationFrame(() => requestAnimationFrame(runTest));
+});
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-070.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-070.html
new file mode 100644
index 0000000000..a41b513e62
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-070.html
@@ -0,0 +1,112 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: off-screen selection</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility auto element remains non-skipped when elements in its subtree have selection.">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body, html {
+ padding: 0;
+ margin: 0;
+}
+
+.spacer {
+ height: 3000px;
+ background: lightblue;
+}
+#container {
+ background: lightgreen;
+ contain-intrinsic-size: 50px 100px;
+ content-visibility: auto;
+}
+#selectable {
+ width: 10px;
+ height: 10px;
+}
+</style>
+
+<div class=spacer></div>
+<div id=container>
+ <div id=selectable>hello</div>
+</div>
+<div class=spacer></div>
+
+<script>
+async_test((t) => {
+ const selection = window.getSelection();
+ const range = document.createRange();
+ range.selectNodeContents(selectable);
+
+ // Initially container should be 3000px offscreen with contained height 100px.
+ function step1() {
+ const r = container.getBoundingClientRect();
+ t.step(() => {
+ assert_equals(r.y, 3000, "step1 offset");
+ assert_equals(r.height, 100, "step1 height");
+ });
+
+ selection.removeAllRanges();
+ selection.addRange(range);
+
+ requestAnimationFrame(step2);
+ }
+ // The container has a selection so it should be smaller now, height 10px.
+ function step2() {
+ const r = container.getBoundingClientRect();
+ t.step(() => {
+ assert_equals(r.y, 3000, "step2 offset");
+ assert_equals(r.height, 10, "step2 height");
+ });
+ document.scrollingElement.scrollTop = 3000;
+ requestAnimationFrame(step3);
+ }
+ // After scrolling the container should be closer and still height 10px.
+ function step3() {
+ const r = container.getBoundingClientRect();
+ t.step(() => {
+ assert_less_than(r.y, 3000, "step3 offset");
+ assert_equals(r.height, 10, "step3 height");
+ });
+ document.scrollingElement.scrollTop = 0;
+ requestAnimationFrame(step4);
+ }
+ // Scrolling back to the top we should remain at height 10px.
+ function step4() {
+ const r = container.getBoundingClientRect();
+ t.step(() => {
+ assert_equals(r.y, 3000, "step4 offset");
+ assert_equals(r.height, 10, "step4 height");
+ });
+ requestAnimationFrame(step5);
+ }
+ // Repeat step4 to ensure we're in a stable situation.
+ function step5() {
+ const r = container.getBoundingClientRect();
+ t.step(() => {
+ assert_equals(r.y, 3000, "step5 offset");
+ assert_equals(r.height, 10, "step5 height");
+ });
+
+ selection.removeAllRanges();
+
+ requestAnimationFrame(step6);
+ }
+ // After removing the selection we should go back to the contained
+ // height of 100px.
+ function step6() {
+ const r = container.getBoundingClientRect();
+ t.step(() => {
+ assert_equals(r.y, 3000, "step5 offset");
+ assert_equals(r.height, 100, "step5 height");
+ });
+ t.done();
+ }
+ step1();
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-071.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-071.html
new file mode 100644
index 0000000000..6f267b27c7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-071.html
@@ -0,0 +1,185 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: off-screen selection</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility auto element remains non-skipped when elements in its subtree have selection.">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body, html {
+ padding: 0;
+ margin: 0;
+}
+
+.spacer {
+ height: 3000px;
+}
+.container {
+ width: 10px;
+ contain-intrinsic-size: 10px 20px;
+ content-visibility: auto;
+}
+.child {
+ width: 10px;
+ height: 10px;
+}
+</style>
+
+<div class=spacer></div>
+<div id=container_1 class=container><div id=child_1 class=child>hello</div></div>
+<div id=container_2 class=container><div id=child_2 class=child>hello</div></div>
+<div id=container_3 class=container><div id=child_3 class=child>hello</div></div>
+<div id=container_4 class=container><div id=child_4 class=child>hello</div></div>
+<div id=container_5 class=container><div id=child_5 class=child>hello</div></div>
+
+<script>
+function isLocked(container) {
+ const height = container.getBoundingClientRect().height;
+ assert_true(height == 20 || height == 10);
+ return container.getBoundingClientRect().height == 20;
+}
+
+const selection = window.getSelection();
+function resetSelection() {
+ selection.removeAllRanges();
+ assert_true(isLocked(container_1));
+ assert_true(isLocked(container_2));
+ assert_true(isLocked(container_3));
+ assert_true(isLocked(container_4));
+ assert_true(isLocked(container_5));
+}
+
+test(() => {
+ resetSelection();
+ const range = document.createRange();
+ range.selectNodeContents(child_2);
+ selection.addRange(range);
+
+ assert_true(isLocked(container_1), "1");
+ assert_false(isLocked(container_2), "2");
+ assert_true(isLocked(container_3), "3");
+ assert_true(isLocked(container_4), "4");
+ assert_true(isLocked(container_5), "5");
+}, "One elements selected: ");
+
+test(() => {
+ resetSelection();
+ const range = document.createRange();
+ range.selectNodeContents(child_2);
+ selection.addRange(range);
+
+ assert_true(isLocked(container_1), "1");
+ assert_false(isLocked(container_2), "2");
+ assert_true(isLocked(container_3), "3");
+ assert_true(isLocked(container_4), "4");
+ assert_true(isLocked(container_5), "5");
+
+ selection.extend(child_4, 0);
+
+ assert_true(isLocked(container_1), "1");
+ assert_false(isLocked(container_2), "2");
+ assert_false(isLocked(container_3), "3");
+ assert_false(isLocked(container_4), "4");
+ assert_true(isLocked(container_5), "5");
+}, "Range extended to cover more elements: ");
+
+test(() => {
+ resetSelection();
+ const range = document.createRange();
+ range.setStart(child_2, 0);
+ range.setEnd(child_4, 0);
+ selection.addRange(range);
+
+ assert_true(isLocked(container_1), "1");
+ assert_false(isLocked(container_2), "2");
+ assert_false(isLocked(container_3), "3");
+ assert_false(isLocked(container_4), "4");
+ assert_true(isLocked(container_5), "5");
+
+ selection.extend(child_2, 1);
+
+ assert_true(isLocked(container_1), "1");
+ assert_false(isLocked(container_2), "2");
+ assert_true(isLocked(container_3), "3");
+ assert_true(isLocked(container_4), "4");
+ assert_true(isLocked(container_5), "5");
+}, "Range shrunk to cover fewer elements: ");
+
+test(() => {
+ resetSelection();
+ const range = document.createRange();
+ range.setStart(child_3, 0);
+ range.setEnd(child_3, 0);
+ selection.addRange(range);
+ selection.extend(child_2, 0);
+
+ assert_true(isLocked(container_1), "1");
+ assert_false(isLocked(container_2), "2");
+ assert_false(isLocked(container_3), "3");
+ assert_true(isLocked(container_4), "4");
+ assert_true(isLocked(container_5), "5");
+
+ selection.extend(child_4, 0);
+
+ assert_true(isLocked(container_1), "1");
+ assert_true(isLocked(container_2), "2");
+ assert_false(isLocked(container_3), "3");
+ assert_false(isLocked(container_4), "4");
+ assert_true(isLocked(container_5), "5");
+}, "Range flipped from back to front: ");
+
+test(() => {
+ resetSelection();
+ const range = document.createRange();
+ range.setStart(child_3, 0);
+ range.setEnd(child_4, 0);
+ selection.addRange(range);
+
+ assert_true(isLocked(container_1), "1");
+ assert_true(isLocked(container_2), "2");
+ assert_false(isLocked(container_3), "3");
+ assert_false(isLocked(container_4), "4");
+ assert_true(isLocked(container_5), "5");
+
+ selection.extend(child_2, 0);
+
+ assert_true(isLocked(container_1), "1");
+ assert_false(isLocked(container_2), "2");
+ assert_false(isLocked(container_3), "3");
+ assert_true(isLocked(container_4), "4");
+ assert_true(isLocked(container_5), "5");
+}, "Range flipped from front to back: ");
+
+test(() => {
+ resetSelection();
+ const range = document.createRange();
+ range.setStart(child_1, 0);
+ range.setEnd(child_1, 0);
+ selection.addRange(range);
+
+ let state = 0;
+ const states = [2, 4, 3, 5, 1];
+ for (let i = 0; i < 10; ++i) {
+ const id = states[state];
+ selection.extend(document.getElementById(`child_${id}`), 1);
+
+ for (let check_id = 1; check_id <= 5; ++check_id) {
+ if (check_id <= id) {
+ assert_false(
+ isLocked(document.getElementById(`container_${check_id}`)),
+ `test_${i}, container_${check_id}`);
+ } else {
+ assert_true(
+ isLocked(document.getElementById(`container_${check_id}`)),
+ `test_${i}, container_${check_id}`);
+ }
+ }
+ state = (state + 1) % states.length;
+ }
+}, "Range goes back and forth: ");
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-072.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-072.html
new file mode 100644
index 0000000000..9fc8b11ceb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-072.html
@@ -0,0 +1,86 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: nested forced layouts</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="nested content-visibility items are all processed when layout is forced">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body, html {
+ padding: 0;
+ margin: 0;
+}
+.spacer {
+ height: 3000px;
+}
+.target {
+ width: 12px;
+ height: 34px;
+
+ position: relative;
+ left: 5px;
+ top: 7px;
+}
+
+.auto {
+ content-visibility: auto;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<div class=spacer></div>
+<div class=auto>
+ <div class=auto>
+ <div class=target id=one></div>
+ </div>
+</div>
+
+<div class=auto>
+ <div class=hidden>
+ <div class=target id=two></div>
+ </div>
+</div>
+
+<div class=hidden>
+ <div class=auto>
+ <div class=target id=three></div>
+ </div>
+</div>
+
+<div class=hidden>
+ <div class=hidden>
+ <div class=target id=four></div>
+ </div>
+</div>
+
+<div class=hidden>
+ <div class=hidden>
+ <div class=hidden>
+ <div class=hidden>
+ <div class=hidden>
+ <div class=target id=five></div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<script>
+const ids = ["one", "two", "three", "four", "five"];
+for (let i = 0; i < ids.length; ++i) {
+ test(() => {
+ const r = document.getElementById(ids[i]).getBoundingClientRect();
+ assert_equals(r.x, 5, "x");
+ assert_equals(r.y, 3007, "y");
+ assert_equals(r.width, 12, "width");
+ assert_equals(r.height, 34, "y");
+ }, `${ids[i]}.getBoundingClientRect(): `);
+}
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-073.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-073.html
new file mode 100644
index 0000000000..555479b880
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-073.html
@@ -0,0 +1,44 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: switching to inline starts painting</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="inline-container-with-child-ref.html">
+<meta name="assert" content="content-visibility has no effect on non-atomic inlines">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ content-visibility: hidden;
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+.inline {
+ display: inline;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: green;
+}
+</style>
+
+<p>Test passes if you can see PASS and a green box below.
+<div id=container>
+ PASS
+ <div id=child></div>
+</div>
+
+<script>
+function runTest() {
+ const container = document.getElementById("container");
+ container.classList.add("inline");
+ takeScreenshot();
+}
+
+window.onload = () => requestAnimationFrame(runTest);
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-074-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-074-ref.html
new file mode 100644
index 0000000000..82a6c263fa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-074-ref.html
@@ -0,0 +1,35 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: toggling auto with composited descedant (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+#a { will-change: transform; }
+#b { height: 15000px; }
+#c {
+ width: 800px;
+ height: 600px;
+}
+#d {
+ will-change: transform;
+ top: 0px;
+ width: 500px;
+ height: 500px;
+ background: green;
+}
+.contain {
+ contain: layout style paint;
+}
+
+</style>
+
+<div id="a">
+</div>
+<div id="b">
+ <div id="c" class=contain>
+ <div id="d"></div>
+ </div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-074.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-074.html
new file mode 100644
index 0000000000..ff6381ce3d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-074.html
@@ -0,0 +1,69 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: toggling auto with composited descedant</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-074-ref.html">
+<meta name="assert" content="after toggling content-visibility auto a few times, composited descedant is visible.">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#a { will-change: transform; }
+#b { height: 15000px; }
+#c {
+ width: 800px;
+ height: 600px;
+}
+#d {
+ will-change: transform;
+ top: 0px;
+ width: 500px;
+ height: 500px;
+ background: green;
+}
+.auto {
+ content-visibility: auto;
+}
+
+</style>
+
+<div id="a">
+</div>
+<div id="b">
+ <div id="c" class=auto>
+ <div id="d"></div>
+ </div>
+ </div>
+</div>
+
+<script>
+function runTest(step) {
+ if (step % 2 == 0) {
+ requestAnimationFrame(() => runTest(step + 1));
+ return;
+ }
+
+ switch(step) {
+ case 1:
+ document.getElementById("c").classList.remove("auto");
+ break;
+ case 3:
+ document.getElementById("c").classList.add("auto");
+ break;
+ case 5:
+ document.getElementById("c").classList.remove("auto");
+ break;
+ case 7:
+ document.getElementById("c").classList.add("auto");
+ break;
+ case 9:
+ takeScreenshot();
+ return;
+ }
+ requestAnimationFrame(() => runTest(step + 1));
+}
+
+window.onload = () => requestAnimationFrame(() => runTest(0));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-075-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-075-ref.html
new file mode 100644
index 0000000000..11fbd76252
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-075-ref.html
@@ -0,0 +1,37 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: auto + scrollIntoView/fragment nav when size estimate is off (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.small_child {
+ height: 1000px;
+}
+.large_child {
+ height: 20000px;
+ position: relative;
+}
+#target {
+ position: absolute;
+ bottom: 0;
+}
+</style>
+
+<div class=auto><div class=small_child></div></div>
+<div class=auto><div class=small_child></div></div>
+<div class=auto><div class=large_child><div id=target>PASS</div></div></div>
+<div class=auto><div class=large_child></div></div>
+<div class=auto><div class=small_child></div></div>
+
+<script>
+function runReference() {
+ target.scrollIntoView();
+ takeScreenshot();
+}
+
+window.onload = () => requestAnimationFrame(() => requestAnimationFrame(runReference));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-075.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-075.html
new file mode 100644
index 0000000000..665cb92305
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-075.html
@@ -0,0 +1,41 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: auto + scrollIntoView when size estimate is off</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-075-ref.html">
+<meta name="assert" content="With content-visibility: auto, scrollIntoView targets the right element">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.auto {
+ content-visibility: auto;
+ contain-intrinsic-size: 1px 1000px;
+}
+.child {
+ height: 20000px;
+ position: relative;
+}
+#target {
+ position: absolute;
+ bottom: 0;
+}
+</style>
+
+<div class=auto><div class=child></div></div>
+<div class=auto><div class=child></div></div>
+<div class=auto><div class=child><div id=target>PASS</div></div></div>
+<div class=auto><div class=child></div></div>
+<div class=auto><div class=child></div></div>
+
+<script>
+function runTest() {
+ target.scrollIntoView();
+ // Double rAF to ensure that rendering has "settled".
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+}
+
+window.onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-076.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-076.html
new file mode 100644
index 0000000000..4ceff631b4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-076.html
@@ -0,0 +1,41 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: auto + fragment nav when size estimate is off</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-075-ref.html">
+<meta name="assert" content="With content-visibility: auto, fragment navigation targets the right element">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.auto {
+ content-visibility: auto;
+ contain-intrinsic-size: 1px 1000px;
+}
+.child {
+ height: 20000px;
+ position: relative;
+}
+#target {
+ position: absolute;
+ bottom: 0;
+}
+</style>
+
+<div class=auto><div class=child></div></div>
+<div class=auto><div class=child></div></div>
+<div class=auto><div class=child><div id=target>PASS</div></div></div>
+<div class=auto><div class=child></div></div>
+<div class=auto><div class=child></div></div>
+
+<script>
+function runTest() {
+ window.location.href += "#target";
+ // Double rAF to ensure that rendering has "settled".
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+}
+
+window.onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-077.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-077.html
new file mode 100644
index 0000000000..7cc9a33503
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-077.html
@@ -0,0 +1,27 @@
+<!doctype HTML>
+<meta charset="utf8">
+<title>CSS Content Visibility: content-visibility is not animatable.</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility is not animatable">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+@keyframes cv {
+ from { content-visibility: auto }
+ to { content-visibility: hidden }
+}
+
+#container { animation: cv 1s; }
+</style>
+
+<div id=container></div>
+
+<script>
+test(() => {
+ const computedStyle = getComputedStyle(container);
+ assert_equals(computedStyle.contentVisibility, "visible");
+}, "Content-visibility is not animatable");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-078-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-078-ref.html
new file mode 100644
index 0000000000..1aed12f92e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-078-ref.html
@@ -0,0 +1,29 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: positioned movement update moves hidden container (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+#target {
+ top: 50px;
+ left: 100px;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background: blue;
+}
+#t2 {
+ top: 150px;
+ left: 100px;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background: orange;
+}
+</style>
+
+<p>Test passes if the blue and orange boxes are vertically aligned with each other.
+<div id=target></div>
+<div id=t2></div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-078.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-078.html
new file mode 100644
index 0000000000..27e300cf11
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-078.html
@@ -0,0 +1,43 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: positioned movement update moves hidden container</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-078-ref.html">
+<meta name="assert" content="when locked, position updates still apply">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.hidden { content-visibility: hidden; }
+#target {
+ top: 50px;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background: blue;
+}
+#t2 {
+ top: 150px;
+ left: 100px;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background: orange;
+}
+</style>
+
+<p>Test passes if the blue and orange boxes are vertically aligned with each other.
+<div id=target class=hidden>FAIL</div>
+<div id=t2 class=hidden>FAIL</div>
+
+<script>
+function runTest() {
+ target.style = "left: 100px;";
+ takeScreenshot();
+}
+
+window.onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-079-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-079-ref.html
new file mode 100644
index 0000000000..83a2206be2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-079-ref.html
@@ -0,0 +1,9 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: auto in overflow hidden paints (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<p>Test passes if you see the word “PASS” below.
+<div>PASS</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-079.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-079.html
new file mode 100644
index 0000000000..2fef671f0e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-079.html
@@ -0,0 +1,17 @@
+<!doctype HTML>
+<meta charset="utf8">
+<title>CSS Content Visibility: auto in overflow hidden paints</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-079-ref.html">
+<meta name="assert" content="content-visibility auto element paints in an overflow hidden element that is not sized">
+
+<style>
+.auto { content-visibility: auto; }
+.overflow { overflow: hidden; }
+</style>
+
+<p>Test passes if you see the word “PASS” below.
+<div class=overflow>
+ <div class=auto>PASS</div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-080.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-080.html
new file mode 100644
index 0000000000..6ee1c2a962
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-080.html
@@ -0,0 +1,32 @@
+<!doctype HTML>
+<html id=html>
+<meta charset="utf8">
+<title>Content Visibility: caret position with html hidden</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="caretRangeFromPoint works even if html has content-visibility hidden">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<meter></meter>
+<iframe></iframe>
+<style>
+* {
+ all: initial;
+ content-visibility: hidden;
+}
+</style>
+
+<script>
+test((t) => {
+ t.add_cleanup(() => { document.getElementsByTagName('style')[0].remove(); });
+ const range = document.caretRangeFromPoint();
+ assert_not_equals(range, null, "range exists");
+ assert_equals(range.startContainer, html, "startContainer is html");
+ assert_equals(range.startOffset, 0, "startOffset is zero");
+ assert_equals(range.endContainer, html, "endContainer is html");
+ assert_equals(range.endOffset, 0, "endOffset is zero");
+}, "Caret range from point");
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-081.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-081.html
new file mode 100644
index 0000000000..b5f10cb6c8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-081.html
@@ -0,0 +1,55 @@
+<!doctype HTML>
+<html id=html>
+<meta charset="utf8">
+<title>Content Visibility: scroll position restoration</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="if an scroller is hidden via content-visibility and then shown again, its scroll offset should be restored">
+<meta name="viewport" content="width=device-width">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.js"></script>
+
+<style>
+.scroller {
+ width: 100px;
+ height: 500px;
+ overflow-y: scroll;
+}
+.spacer { height: 3000px; }
+.hidden { content-visibility: hidden; }
+</style>
+
+<div id=target class=scroller>
+ <div class=spacer></div>
+</div>
+</style>
+
+<script>
+function removeHiddenAndScheduleTest(t) {
+ target.classList.remove("hidden");
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ testScrollTop(t);
+ });
+ });
+}
+
+function testScrollTop(t) {
+ t.step(() => assert_equals(target.scrollTop, 2000));
+ t.done();
+}
+
+async_test((t) => {
+ target.scrollTop = 2000;
+ target.classList.add("hidden");
+
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ removeHiddenAndScheduleTest(t);
+ });
+ });
+}, "Scroll offset is restored when content-visibility hidden is removed");
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-082.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-082.html
new file mode 100644
index 0000000000..3313ca0f65
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-082.html
@@ -0,0 +1,32 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: focus selects content-visibility element</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-focus-ref.html">
+<meta name="assert" content="The elements with content-visibility are still focusable">
+
+<style>
+#container {
+ content-visibility: hidden;
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: lightgreen;
+}
+</style>
+
+<p>Test passes if the light blue box below has focus.
+<div id=container tabindex=0>
+ <div id=child></div>
+</div>
+
+<script>
+onload = () => container.focus();
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-083.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-083.html
new file mode 100644
index 0000000000..488465f02b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-083.html
@@ -0,0 +1,42 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: anchor links prevented on hidden</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="spacer-and-container-ref.html">
+<meta name="assert" content="anchor link scroll is prevented when the target is hidden">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#container {
+ width: 150px;
+ height: 150px;
+ background: red;
+ content-visibility: hidden;
+}
+
+#target {
+ width: 100px;
+ height: 100px;
+}
+</style>
+
+<div class="spacer">Test passes if there is no red.</div>
+<div id="container"><div id="target"></div></div>
+
+<script>
+function runTest() {
+ location.href += "#target";
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-084.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-084.html
new file mode 100644
index 0000000000..742b1d5189
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-084.html
@@ -0,0 +1,50 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: anchor links prevented on hidden</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="spacer-and-container-ref.html">
+<meta name="assert" content="anchor link scroll is prevented when the target is hidden">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#container {
+ width: 150px;
+ height: 150px;
+ background: red;
+}
+
+.hidden {
+ content-visibility: hidden;
+}
+
+#target {
+ width: 100px;
+ height: 100px;
+}
+</style>
+
+<div class="spacer">Test passes if there is no red.</div>
+<div id="container"><div id="target"></div></div>
+
+<script>
+function tryToScroll() {
+ location.href += "#target";
+ requestAnimationFrame(takeScreenshot);
+}
+
+function runTest() {
+ container.classList.add("hidden");
+ requestAnimationFrame(tryToScroll);
+}
+
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-applied-to-th-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-applied-to-th-crash.html
new file mode 100644
index 0000000000..cde696e2f6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-applied-to-th-crash.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+ <meta name="assert" content="content-visiblity: auto on a <th> element should not cause a crash.">
+ <style>
+ TR {
+ content-visibility: auto;
+ }
+ * {
+ inset-block-end: 21%;
+ }
+ </style>
+</head>
+<body>
+ <table>
+ <th>
+ <sub>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-in-iframe-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-in-iframe-ref.html
new file mode 100644
index 0000000000..03a2875b75
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-in-iframe-ref.html
@@ -0,0 +1,25 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: auto container in an iframe (reference)</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<iframe id="frame" srcdoc='
+ <style>
+ #container {
+ width: 200px;
+ height: 200px;
+ }
+ #child {
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ </style>
+ <div id="container">
+ <div id="child"></div>
+ </div>
+ hello
+'></iframe>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-in-iframe.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-in-iframe.html
new file mode 100644
index 0000000000..ba02cac668
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-in-iframe.html
@@ -0,0 +1,28 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: auto container in an iframe</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-auto-in-iframe-ref.html">
+<meta name="assert" content="content-visibility: auto shows on screen iframe contents">
+
+<iframe id="frame" srcdoc='
+ <style>
+ #container {
+ width: 200px;
+ height: 200px;
+ content-visibility: auto;
+ }
+ #child {
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ </style>
+ <div id="container">
+ <div id="child"></div>
+ </div>
+ hello
+'></iframe>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-intrinsic-width.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-intrinsic-width.html
new file mode 100644
index 0000000000..bd90fff514
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-intrinsic-width.html
@@ -0,0 +1,25 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: Elements with content-visibility: auto and intrinsic width should render correctly</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="Elements with content-visibility: auto and intrinsic width should render correctly">
+
+<style>
+#container {
+ content-visibility: auto;
+ width: max-content;
+ background: lightblue;
+}
+
+#child {
+ width: 150px;
+ height: 150px;
+}
+</style>
+
+<div id="container">
+ <div id="child"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-selection-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-selection-crash.html
new file mode 100644
index 0000000000..4cfe62eaca
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-selection-crash.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+ <meta name="assert" content="Changes to selection that result in no selection do not cause a crash.">
+ <style>
+ * {
+ content-visibility: auto;
+ }
+ </style>
+ <script>
+ document.addEventListener('DOMContentLoaded', () => {
+ document.documentElement.convertPointFromNode({}, marquee, {})
+ textarea.setSelectionRange(0, 0, 'forward')
+ input.setAttribute('type', 'number')
+ document.documentElement.getBoundingClientRect()
+ })
+ </script>
+</head>
+<body>
+ <marquee id='marquee'></marquee>
+ <textarea id='textarea'></textarea>
+ <input id='input'></input>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-state-changed-first-observation.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-state-changed-first-observation.html
new file mode 100644
index 0000000000..1c51851488
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-state-changed-first-observation.html
@@ -0,0 +1,65 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: ContentVisibilityAutoStateChange event.</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="ContentVisibilityAutoStateChange fires once when element is inserted">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+.spacer {
+ height: 10000px;
+}
+</style>
+
+<div id=topdiv></div>
+<div class=spacer></div>
+<div id=bottomdiv></div>
+
+<script>
+promise_test(t => new Promise(async (resolve, reject) => {
+ await new Promise((waited, _) => {
+ requestAnimationFrame(() => requestAnimationFrame(waited));
+ });
+
+ let observed = false;
+ let div = document.createElement("div");
+ div.addEventListener("contentvisibilityautostatechange", (e) => {
+ if (observed)
+ reject("already observed");
+ if (e.skipped)
+ reject("unexpected skipped");
+ observed = true;
+ // Wait a couple of frames to ensure no other signal comes in
+ requestAnimationFrame(() => requestAnimationFrame(resolve));
+ });
+
+ div.style.contentVisibility = "auto";
+ topdiv.appendChild(div);
+}), "ContentVisibilityAutoStateChange fires once when added (not skipped)");
+
+promise_test(t => new Promise(async (resolve, reject) => {
+ await new Promise((waited, _) => {
+ requestAnimationFrame(() => requestAnimationFrame(waited));
+ });
+
+ let observed = false;
+ let div = document.createElement("div");
+ div.addEventListener("contentvisibilityautostatechange", (e) => {
+ if (observed)
+ reject("already observed");
+ if (!e.skipped)
+ reject("unexpected not skipped");
+ observed = true;
+ // Wait a couple of frames to ensure no other signal comes in
+ requestAnimationFrame(() => requestAnimationFrame(resolve));
+ });
+
+ div.style.contentVisibility = "auto";
+ bottomdiv.appendChild(div);
+}), "ContentVisibilityAutoStateChange fires once when added (skipped)");
+</script>
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-state-changed.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-state-changed.html
new file mode 100644
index 0000000000..65b501de1b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-state-changed.html
@@ -0,0 +1,98 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: ContentVisibilityAutoStateChange event.</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="timeout" content="long">
+<meta name="assert" content="ContentVisibilityAutoStateChange fires when things enter/exit viewport">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/scroll-to-text-fragment/stash.js"></script>
+
+<style>
+.spacer {
+ height: 3000px;
+}
+.auto { content-visibility: auto; }
+</style>
+
+<div id=upper></div>
+<div class=spacer></div>
+<div id=middle></div>
+<div class=spacer></div>
+<div id=lower></div>
+
+<script>
+promise_test(t => new Promise(async (resolve, reject) => {
+ let shouldSkip = false;
+ const listener = (e) => {
+ if (!e.skipped)
+ resolve();
+ };
+
+ upper.addEventListener("contentvisibilityautostatechange", listener);
+ t.add_cleanup(() => upper.removeEventListener("contentvisibilityautostatechange", listener));
+ upper.classList.add("auto");
+}), "ContentVisibilityAutoStateChange fires when relevant element gains `content-visibility:auto`");
+
+promise_test(t => new Promise(async (resolve, reject) => {
+ let shouldSkip = false;
+ const listener = (e) => {
+ if (e.skipped)
+ resolve();
+ else
+ reject();
+ };
+
+ lower.addEventListener("contentvisibilityautostatechange", listener);
+ t.add_cleanup(() => lower.removeEventListener("contentvisibilityautostatechange", listener));
+ lower.classList.add("auto");
+}), "ContentVisibilityAutoStateChange fires when not relevant element gains `content-visibility:auto`");
+
+promise_test(t => new Promise(async (resolve, reject) => {
+ await new Promise((waited, _) => {
+ requestAnimationFrame(() => requestAnimationFrame(waited));
+ });
+
+ const listener = (e) => {
+ if (e.skipped)
+ resolve();
+ };
+
+ upper.addEventListener("contentvisibilityautostatechange", listener);
+ t.add_cleanup(() => upper.removeEventListener("contentvisibilityautostatechange", listener));
+
+ requestAnimationFrame(() => requestAnimationFrame(() => {
+ middle.scrollIntoView();
+ }));
+}), "ContentVisibilityAutoStateChange fires when skipped");
+
+promise_test(t => new Promise(async (resolve, reject) => {
+ await new Promise((waited, _) => {
+ requestAnimationFrame(() => requestAnimationFrame(waited));
+ });
+
+ const listener = (e) => {
+ if (!e.skipped)
+ resolve();
+ else
+ reject();
+ }
+
+ lower.addEventListener("contentvisibilityautostatechange", listener);
+ t.add_cleanup(() => {
+ lower.removeEventListener("contentvisibilityautostatechange", listener);
+ });
+
+ requestAnimationFrame(() => requestAnimationFrame(() => {
+ lower.scrollIntoView();
+ }));
+}), "ContentVisibilityAutoStateChange fires when not skipped");
+
+</script>
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-canvas-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-canvas-ref.html
new file mode 100644
index 0000000000..dbedcf18ad
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-canvas-ref.html
@@ -0,0 +1,17 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hidden canvas (reference)</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+div {
+ width: 200px;
+ height: 200px;
+ background: green;
+ border: 1px solid black;
+}
+</style>
+
+<div></div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-canvas.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-canvas.html
new file mode 100644
index 0000000000..fe46948952
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-canvas.html
@@ -0,0 +1,43 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: hidden canvas</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-canvas-ref.html">
+<meta name="assert" content="content-visibility hidden canvas element does not paint replaced content">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+canvas {
+ width: 200px;
+ height: 200px;
+ background: green;
+ border: 1px solid black;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<canvas id="canvas">
+</canvas>
+
+<script>
+async function runTest() {
+ var context = canvas.getContext("2d");
+ context.fillStyle = "red";
+ context.fillRect(0, 0, canvas.width, canvas.height);
+
+ canvas.classList.add("hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(runTest);
+ });
+};
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-continuations-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-continuations-crash.html
new file mode 100644
index 0000000000..e20d26fcee
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-continuations-crash.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="help" href="https://crbug.com/1197492">
+<map>
+ <ul></ul>
+ <progress></progress>
+ <iframe></iframe>
+</map>
+<style>
+body, map, ul, progress {
+ content-visibility: auto;
+ height: 0vw;
+ }
+</style>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-fieldset-size-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-fieldset-size-ref.html
new file mode 100644
index 0000000000..7958810b40
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-fieldset-size-ref.html
@@ -0,0 +1,14 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: fieldset hiding content</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+fieldset {
+ background: green;
+}
+</style>
+
+<fieldset></fieldset>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-fieldset-size.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-fieldset-size.html
new file mode 100644
index 0000000000..830bf851ff
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-fieldset-size.html
@@ -0,0 +1,17 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: fieldset hiding content</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-fieldset-size-ref.html">
+<meta name="assert" content="A fieldset hiding content with content-visibility should be equivalent to an empty fieldset">
+
+<style>
+fieldset {
+ background: green;
+ content-visibility: hidden
+}
+</style>
+
+<fieldset><legend>Hidden legend content</legend>Hidden fieldset content</fieldset>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-forced-layout-client-rects.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-forced-layout-client-rects.html
new file mode 100644
index 0000000000..60e6849892
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-forced-layout-client-rects.html
@@ -0,0 +1,105 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: nested forced layouts</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="nested content-visibility items are all processed when layout is forced">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body, html {
+ padding: 0;
+ margin: 0;
+}
+.spacer {
+ height: 3000px;
+}
+.target {
+ width: 12px;
+ height: 34px;
+
+ position: relative;
+ left: 5px;
+ top: 7px;
+}
+
+.hidden {
+ content-visibility: hidden;
+}
+
+.will-hide {
+ contain: style;
+ contain: size;
+ contain: layout;
+ contain: paint;
+}
+</style>
+
+<div class=spacer></div>
+
+<div class="will-hide">
+ <div id=one>A line of a certain length...</div>
+</div>
+
+<div class="will-hide">
+ <div class=target id=two></div>
+</div>
+
+<div class="will-hide">
+ <div class=target id=three></div>
+</div>
+
+<div class="will-hide">
+ <div class="will-hide">
+ <div class=target id=four></div>
+ </div>
+</div>
+
+<div class="will-hide">
+ <div class="will-hide">
+ <div class="will-hide">
+ <div class="will-hide">
+ <div class="will-hide">
+ <div class=target id=five></div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<script>
+function hideContent() {
+ document
+ .querySelectorAll('.will-hide')
+ .forEach(content => content.classList.add("hidden"));
+}
+
+function showContent() {
+ document
+ .querySelectorAll('.will-hide')
+ .forEach(content => content.classList.remove("hidden"));
+}
+
+const ids = ["one", "two", "three", "four", "five"];
+for (let i = 0; i < ids.length; ++i) {
+ test(() => {
+ const expectedRect = document.getElementById(ids[i]).getClientRects()[0];
+ const expectedBoundingRect = document.getElementById(ids[i]).getBoundingClientRect();
+ hideContent();
+
+ const rect = document.getElementById(ids[i]).getClientRects()[0];
+ assert_equals(rect.width, expectedRect.width, `width for "${ids[i]}"`);
+ assert_equals(rect.height, expectedRect.height, `height for "${ids[i]}`);
+
+ const boundingRect = document.getElementById(ids[i]).getClientRects()[0];
+ assert_equals(boundingRect.width, expectedBoundingRect.width, `width for "${ids[i]}"`);
+ assert_equals(boundingRect.height, expectedBoundingRect.height, `height for "${ids[i]}`);
+
+ showContent();
+ }, `${ids[i]}.getBoundingClientRect(): `);
+}
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-form-controls-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-form-controls-crash.html
new file mode 100644
index 0000000000..6c9634dc1f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-form-controls-crash.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="help" href="https://crbug.com/1143620">
+<style>
+input, select, textarea {
+ content-visibility: auto;
+}
+</style>
+<input type="button">
+<input type="checkbox">
+<input type="color">
+<input type="date">
+<input type="datetime">
+<input type="datetime-local">
+<input type="email">
+<input type="file">
+<input type="hidden">
+<input type="image">
+<input type="month">
+<input type="number">
+<input type="password">
+<input type="radio">
+<input type="range">
+<input type="reset">
+<input type="search">
+<input type="submit">
+<input type="tel">
+<input type="text">
+<input type="time">
+<input type="url">
+<input type="week">
+<select><option>Option1</option></select>
+<select multiple><option>Option1</option></select>
+<textarea></textarea>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-hit-test-contents-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-hit-test-contents-crash.html
new file mode 100644
index 0000000000..737d2af5d8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-hit-test-contents-crash.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<link rel=author name="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel=assert content="Hit testing around hidden elements should not crash regardless of contents">
+
+<style>
+.box { width: 100px; height: 100px; border: 1px solid black; }
+.hidden { content-visibility: hidden }
+</style>
+
+<div id=container class="box hidden">
+ content
+ <dialog id=dialog>
+ dialog
+ <div id=inner></div>
+ </dialog>
+</div>
+text
+
+<script>
+function runTest() {
+ inner.getBoundingClientRect();
+ document.elementFromPoint(20, 109);
+ document.elementFromPoint(20, 20);
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-img.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-img.html
new file mode 100644
index 0000000000..94981aa264
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-img.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1247417">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+<div class="hidden" id="container1"></div>
+<div class="hidden" id="container2"></div>
+<div class="hidden" id="container3"></div>
+<div class="hidden" id="container4"></div>
+
+<script>
+promise_test(async () => {
+ const img1 = document.createElement('img');
+ container1.appendChild(img1);
+ const img1Load = new Promise(resolve => img1.onload = resolve);
+ img1.src = 'resources/dice.png';
+ await img1Load;
+ assert_not_equals(img1.height, 0, 'height');
+
+ const img2 = document.createElement('img');
+ container2.appendChild(img2);
+ const img2Load = new Promise(resolve => img2.onload = resolve);
+ img2.src = 'resources/dice.png';
+ await img2Load;
+ assert_not_equals(img2.width, 0, 'width');
+
+ const img3 = document.createElement('img');
+ container3.appendChild(img3);
+ const img3Load = new Promise(resolve => img3.onload = resolve);
+ img3.src = 'resources/dice.png';
+ await img3Load;
+ assert_not_equals(img3.x, 0, 'x');
+
+ const img4 = document.createElement('img');
+ container4.appendChild(img4);
+ const img4Load = new Promise(resolve => img4.onload = resolve);
+ img4.src = 'resources/dice.png';
+ await img4Load;
+ assert_not_equals(img4.y, 0, 'y');
+
+}, `c-v:hidden <img> layout APIs shouldn't return zero when accessed from script.`);
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-in-svg-000-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-in-svg-000-crash.html
new file mode 100644
index 0000000000..d1084f7216
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-in-svg-000-crash.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html class="test-wait">
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://crbug.com/1247196">
+<meta name="assert" content="Clip path with content-visibility does not cause an assert">
+
+<svg width="138">
+ <defs>
+ <clipPath id="snowglobe_clipPath">
+ <circle cx="34" />
+ </clipPath>
+ </defs>
+ <circle />
+ <g class="group-snow" clip-path="url(#snowglobe_clipPath)">
+ <g class="snowContainer">
+ <circle class="snow" />
+ </g>
+ </g>
+</svg>
+<script type="text/javascript">
+onload = () => {
+ var test0 = document.getElementById("snowglobe_clipPath");
+ test0.style.setProperty("content-visibility", "auto ", "important");
+ test0.innerHTML = "";
+ test0.offsetHeight;
+
+ requestAnimationFrame(() => document.documentElement.classList.remove('test-wait'));
+};
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-input-image.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-input-image.html
new file mode 100644
index 0000000000..7d603eaf58
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-input-image.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<link rel="author" href="mailto:jarhar@chromium.org">
+<link rel="help" href="http://crbug.com/1247417">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div style="content-visibility:hidden" id=container1></div>
+<div style="content-visibility:hidden" id=container2></div>
+
+<script>
+promise_test(async () => {
+ const image1 = document.createElement('input');
+ image1.type = 'image';
+ const image1Load = new Promise(resolve => {
+ image1.addEventListener('load', resolve);
+ });
+ image1.src = 'resources/dice.png';
+ container1.appendChild(image1);
+ await image1Load;
+ assert_not_equals(image1.width, 0, 'width');
+
+ const image2 = document.createElement('input');
+ image2.type = 'image';
+ const image2Load = new Promise(resolve => {
+ image2.addEventListener('load', resolve);
+ });
+ image2.src = 'resources/dice.png';
+ container2.appendChild(image2);
+ await image2Load;
+ assert_not_equals(image2.height, 0, 'height');
+
+}, `<input type=image> should return nonzero values for width and height in a c-v:hidden subtree.`);
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-output-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-output-crash.html
new file mode 100644
index 0000000000..6c7c7d2b1b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-output-crash.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="help" href="https://crbug.com/1316517">
+<meta name="assert" content="Ensure content-visibility: hidden doesn't apply to <output> elements">
+<style>
+output {
+ content-visibility: hidden;
+}
+</style>
+<output>
+ <iframe></iframe>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-resize-observer-no-error-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-resize-observer-no-error-ref.html
new file mode 100644
index 0000000000..228eebfaa6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-resize-observer-no-error-ref.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<meta charset="utf8">
+<title>Content Visibility: resize observer interaction (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+div {
+ min-height: 50px;
+ background: blue;
+}
+</style>
+
+<span>There should be no red color on this page.</span>
+<span><div></div></span>
+<div></div>
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-resize-observer-no-error.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-resize-observer-no-error.html
new file mode 100644
index 0000000000..f323e60603
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-resize-observer-no-error.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf8">
+<title>Content Visibility: resize observer interaction</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-resize-observer-no-error-ref.html">
+<meta name="assert" content="the test doesn't cause resize observer to produce an error">
+
+<script>
+addEventListener('error', () => {
+ document.documentElement.style.background = "red";
+});
+</script>
+
+<style>
+div {
+ contain-intrinsic-size: auto 200px;
+ content-visibility: auto;
+ min-height: 50px;
+ background: blue;
+}
+</style>
+
+<span>There should be no red color on this page.</span>
+<span><div></div></span>
+<div></div>
+
+<script>
+new ResizeObserver(() => {});
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-svg.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-svg.html
new file mode 100644
index 0000000000..568149ba7f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-svg.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<link rel="author" href="mailto:jarhar@chromium.org">
+<link rel="help" href="http://crbug.com/1247417">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div style="content-visibility:hidden">
+ <svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
+ <g id="group_text_1">
+ <text x="5" y="16" transform="scale(2, 2)">Hello World!</text>
+ <text x="8" y="32" transform="translate(0 20) scale(1.25 1)">Hello World Again!</text>
+ </g>
+ </svg>
+</div>
+
+<script>
+ test(() => {
+ const groupElement = document.getElementById('group_text_1');
+ const bbox = groupElement.getBBox();
+ assert_not_equals(bbox.width, 0, 'width');
+ assert_not_equals(bbox.height, 0, 'height');
+ assert_not_equals(bbox.x, 0, 'x');
+ assert_not_equals(bbox.y, 0, 'y');
+ }, `getBBox() should return nonzero values in a c-v:hidden subtree.`);
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-video-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-video-ref.html
new file mode 100644
index 0000000000..5e1e9bdde8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-video-ref.html
@@ -0,0 +1,17 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hidden video (reference)</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+div {
+ width: 200px;
+ height: 200px;
+ background: green;
+ border: 1px solid black;
+}
+</style>
+
+<div></div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-video.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-video.html
new file mode 100644
index 0000000000..bed5954fe4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-video.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>Content Visibility: hidden video</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-video-ref.html">
+<meta name="assert" content="content-visibility hidden video element does not paint replaced content">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+video {
+ width: 200px;
+ height: 200px;
+ background: green;
+ border: 1px solid black;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<body>
+ <video id="video" poster="../support/blue-100x100.png" src="../support/white.webm" controls></video>
+</body>
+
+<script>
+async function runTest() {
+ video.classList.add("hidden");
+ video.play();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(runTest);
+ });
+};
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-000.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-000.html
new file mode 100644
index 0000000000..61856611f9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-000.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: dialog doesn't show when hidden</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="top layer dialogs don't render when in skipped subtrees">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.box { width: 150px; height: 150px; background: lightblue }
+.hidden { content-visibility: hidden }
+</style>
+
+<div class="box hidden">
+Fail
+<dialog id=dialog>Fail<div id=inner></div></dialog>
+</div>
+
+<script>
+function runTest() {
+ dialog.showModal();
+ takeScreenshot();
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-001.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-001.html
new file mode 100644
index 0000000000..43242eb2cb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-001.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: dialog doesn't show when hidden after render</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="top layer dialogs don't render when in skipped subtrees">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.box { width: 150px; height: 150px; background: lightblue }
+.hidden { content-visibility: hidden }
+</style>
+
+<div id=container class=box>
+Fail
+<dialog id=dialog>Fail<div id=inner></div></dialog>
+</div>
+
+<script>
+function runTest() {
+ container.classList.add("hidden");
+ dialog.showModal();
+ takeScreenshot();
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-002.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-002.html
new file mode 100644
index 0000000000..f54c639d7b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-002.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: dialog doesn't show when hidden after render</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="top layer dialogs don't render when in skipped subtrees">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.box { width: 150px; height: 150px; background: lightblue }
+.hidden { content-visibility: hidden }
+</style>
+
+<div id=container class=box>
+content
+<dialog id=dialog>dialog<div id=inner></div></dialog>
+</div>
+
+<script>
+function runTest() {
+ container.classList.add("hidden");
+ dialog.showModal();
+ inner.getBoundingClientRect();
+
+ takeScreenshot();
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-003.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-003.html
new file mode 100644
index 0000000000..b8685954ff
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-003.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: dialog shows when rendered</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-with-top-layer-ref.html">
+<meta name="assert" content="top layer dialogs start rendering when c-v is removed">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.box { width: 100px; height: 100px; border: 1px solid black; }
+.hidden { content-visibility: hidden }
+</style>
+
+<div id=container class=box>
+This test passes if you can see “PASS” in a white box.
+<dialog id=dialog>PASS<div id=inner></div></dialog>
+</div>
+text
+
+<script>
+function unhide() {
+ container.classList.remove("hidden");
+ takeScreenshot();
+}
+
+function runTest() {
+ container.classList.add("hidden");
+ dialog.showModal();
+ requestAnimationFrame(unhide);
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-004.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-004.html
new file mode 100644
index 0000000000..e21b11e92d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-004.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: dialog shows under c-v auto</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="spacer-with-top-layer-ref.html">
+<meta name="assert" content="top layer dialogs render under c-v auto">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.box { width: 100px; height: 100px; border: 1px solid black; }
+.auto { content-visibility: auto }
+.spacer { width: 10px; height: 3000px; background: lightblue; }
+</style>
+
+<div class=spacer></div>
+<div id=container class="box auto">
+content
+<dialog id=dialog>PASS<div id=inner></div></dialog>
+</div>
+
+<script>
+function runTest() {
+ dialog.showModal();
+ takeScreenshot();
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-005.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-005.html
new file mode 100644
index 0000000000..5283aea197
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-005.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: dialog shows under c-v auto</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="spacer-with-top-layer-ref.html">
+<meta name="assert" content="top layer dialogs render under c-v auto">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.box { width: 100px; height: 100px; border: 1px solid black; }
+.auto { content-visibility: auto }
+.spacer { width: 10px; height: 3000px; background: lightblue; }
+</style>
+
+<div class=spacer></div>
+<div id=container class="box">
+content
+<dialog id=dialog><div id=inner class="auto">PASS</div></dialog>
+</div>
+
+<script>
+function runTest() {
+ dialog.showModal();
+ takeScreenshot();
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-006.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-006.html
new file mode 100644
index 0000000000..f533f3dfa5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-006.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<meta charset="utf8">
+<title>CSS Content Visibility: offscreen c-v auto content is relevant when in top layer</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="offscreen c-v auto content is relevant when in top layer">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+#inner {
+ content-visibility: auto;
+ contain-intrinsic-size: 100px 100px;
+}
+</style>
+
+<dialog id="dialog">
+ <div id="spacer" style="height: 100000px;"></div>
+ <div id="inner">
+ <div style="height: 200px; width: 200px;">content</div>
+ </div>
+</dialog>
+
+<script>
+test(() => {
+ dialog.show();
+
+ assert_equals(inner.getBoundingClientRect().height, 100);
+
+ dialog.close();
+ dialog.showModal();
+
+ // Even though the element with `content-visibility: auto` is offscreen
+ // it should be considered relevant content because it is now in the top
+ // layer.
+ assert_equals(inner.getBoundingClientRect().height, 200);
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-hide-after-addition.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-hide-after-addition.html
new file mode 100644
index 0000000000..54f632ffbd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-hide-after-addition.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: dialog doesn't show when hidden after showModal()</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="top layer dialogs don't render when in skipped subtrees">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.box { width: 150px; height: 150px; background: lightblue }
+.hidden { content-visibility: hidden }
+</style>
+
+<div id=container class=box>
+FAIL
+<dialog id=dialog>FAIL<div id=inner></div></dialog>
+</div>
+
+<script>
+function runTest() {
+ dialog.showModal();
+ inner.getBoundingClientRect();
+
+ container.classList.add("hidden");
+
+ takeScreenshot();
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-with-top-layer-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-with-top-layer-ref.html
new file mode 100644
index 0000000000..1a3cad3278
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-with-top-layer-ref.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<meta charset="utf8">
+<title>CSS Content Visibility: dialog shows when rendered (ref)</title>
+
+<style>
+.box { width: 100px; height: 100px; border: 1px solid black; }
+</style>
+
+<div id=container class=box>
+This test passes if you can see “PASS” in a white box.
+<dialog id=dialog>PASS<div id=inner></div></dialog>
+</div>
+text
+
+<script>
+dialog.showModal();
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/contentvisibility-nestedslot-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/contentvisibility-nestedslot-crash.html
new file mode 100644
index 0000000000..f4f07814e6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/contentvisibility-nestedslot-crash.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html class="test-wait">
+<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1208573">
+
+<div style="content-visibility:hidden">hidden</div>
+
+<div id=host>
+ <template shadowroot=open>
+ <div>nested slots:</div>
+ <slot name=parent>
+ <slot name=child></slot>
+ </slot>
+ </template>
+ <div slot=parent>lightdom slot=parent</div>
+ <div slot=child>lightdom slot=child</div>
+</div>
+
+<script>
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ const div = document.createElement('div');
+ div.textContent = 'new lightdom child';
+ host.appendChild(div);
+
+ requestAnimationFrame(() => {
+ document.documentElement.classList.remove('test-wait');
+ });
+ });
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/crashtests/first-line-and-inline-block.html b/testing/web-platform/tests/css/css-contain/content-visibility/crashtests/first-line-and-inline-block.html
new file mode 100644
index 0000000000..6d6c6605ee
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/crashtests/first-line-and-inline-block.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<style>
+div, span {
+ content-visibility: auto;
+ contain-intrinsic-width: auto 100vw;
+}
+div::first-line {
+ color: blue;
+}
+</style>
+<div>
+ <span style="display: inline-block">foo</span>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/detach-locked-slot-children-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/detach-locked-slot-children-crash.html
new file mode 100644
index 0000000000..409a9697b2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/detach-locked-slot-children-crash.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<html class="reftest-wait">
+<link rel="help" href="https://crbug.com/1284278">
+<body dir="auto">
+ <p>Pass if no crash.</p>
+ <details id="details">
+ <img id="img" alt="alt"></img>
+ <marquee id="marquee"></marquee>
+ </details>
+</body>
+<script>
+ requestAnimationFrame(() => requestAnimationFrame(() => {
+ marquee.appendChild(details.firstChild);
+ img.srcset = "dummy";
+ img.alt = "dummy";
+ document.documentElement.classList.remove("reftest-wait");
+ }));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/document-element-computed-style.html b/testing/web-platform/tests/css/css-contain/content-visibility/document-element-computed-style.html
new file mode 100644
index 0000000000..22d00d0584
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/document-element-computed-style.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html style="display:none">
+
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1251931">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div style="content-visibility:hidden"></div>
+
+<script>
+test(() => {
+ document.documentElement.offsetTop;
+ document.documentElement.style.display = "block";
+ assert_equals(getComputedStyle(document.documentElement).color, 'rgb(0, 0, 0)');
+}, `Verifies that ComputedStyle gets updated when the documentElement's style is dirtied in the presence of content-visibility.`);
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/dynamic-change-paint-fully-obscuring-child-001.html b/testing/web-platform/tests/css/css-contain/content-visibility/dynamic-change-paint-fully-obscuring-child-001.html
new file mode 100644
index 0000000000..781a11ca40
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/dynamic-change-paint-fully-obscuring-child-001.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<title>content-visibility:hidden elements painting with a fully-obscuring child</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1370776">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<style>
+
+div { width: 100px; height: 100px; }
+
+.small { height: 50px; }
+
+.hidden { content-visibility: hidden }
+
+.green { background: green; }
+.red { background: red; }
+
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+
+<!--
+ This example shows the bug because the child would fully obscure the
+ parent if the parent were not content-visibility: hidden.
+
+ If the child has class="small", then the bug is not present.
+
+-->
+<div class="green">
+ <div class="red"></div>
+</div>
+
+<script>
+
+document.documentElement.addEventListener("TestRendered", function(event) {
+ for (let elt of document.querySelectorAll("body > div")) {
+ elt.classList.add("hidden");
+ }
+ document.documentElement.classList.remove("reftest-wait");
+});
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/element-reassigned-to-skipped-slot.html b/testing/web-platform/tests/css/css-contain/content-visibility/element-reassigned-to-skipped-slot.html
new file mode 100644
index 0000000000..d71ee9eef0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/element-reassigned-to-skipped-slot.html
@@ -0,0 +1,68 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: element reslotting</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="element is correctly removed when slot assignment takes it into a skipped slot">
+
+<script src="/common/reftest-wait.js"></script>
+
+<script>
+window.customElements.define("my-element", class extends HTMLElement {
+ connectedCallback() {
+ if (this.shadowRoot) {
+ this.computeEdges_();
+ return;
+ }
+
+ this.attachShadow({ mode: 'open' }).innerHTML = `
+ <style>
+ slot[name=locked] {
+ display: block;
+ content-visibility: hidden;
+ }
+ </style>
+ <slot name=unlocked></slot>
+ <slot name=locked></slot>
+ `;
+ }
+});
+</script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+
+div {
+ width: 50px;
+ height: 50px;
+}
+.composited { will-change: transform; }
+#one { background: pink; }
+#two { background: red; }
+</style>
+
+<div id=container>
+ <my-element>
+ <div id=one slot=unlocked>FAIL</div>
+ <div id=two slot=locked>FAIL</div>
+ </my-element>
+</div>
+
+<script>
+// Ensure everything is loaded and rendered.
+onload = () =>
+ requestAnimationFrame(() =>
+ requestAnimationFrame(() =>
+ requestAnimationFrame(() => {
+ // Reslot the element and composite the other one.
+ one.slot = "locked";
+ two.classList.add("composited");
+ requestAnimationFrame(takeScreenshot);
+})));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/element-reassigned-to-slot-in-skipped-subtree.html b/testing/web-platform/tests/css/css-contain/content-visibility/element-reassigned-to-slot-in-skipped-subtree.html
new file mode 100644
index 0000000000..df6b64d7bc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/element-reassigned-to-slot-in-skipped-subtree.html
@@ -0,0 +1,70 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: element reslotting</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="container-ref.html">
+<meta name="assert" content="element is correctly removed when slot assignment takes it into a skipped slot">
+
+<script src="/common/reftest-wait.js"></script>
+
+<script>
+window.customElements.define("my-element", class extends HTMLElement {
+ connectedCallback() {
+ if (this.shadowRoot) {
+ this.computeEdges_();
+ return;
+ }
+
+ this.attachShadow({ mode: 'open' }).innerHTML = `
+ <style>
+ #locked {
+ display: block;
+ content-visibility: hidden;
+ }
+ </style>
+ <slot name=unlocked></slot>
+ <div id=locked>
+ <slot name=locked></slot>
+ </div>
+ `;
+ }
+});
+</script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+
+div {
+ width: 50px;
+ height: 50px;
+}
+.composited { will-change: transform; }
+#one { background: pink; }
+#two { background: red; }
+</style>
+
+<div id=container>
+ <my-element>
+ <div id=one slot=unlocked>FAIL</div>
+ <div id=two slot=locked>FAIL</div>
+ </my-element>
+</div>
+
+<script>
+// Ensure everything is loaded and rendered.
+onload = () =>
+ requestAnimationFrame(() =>
+ requestAnimationFrame(() =>
+ requestAnimationFrame(() => {
+ // Reslot the element and composite the other one.
+ one.slot = "locked";
+ two.classList.add("composited");
+ requestAnimationFrame(takeScreenshot);
+})));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/hidden-execcommand-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/hidden-execcommand-crash.html
new file mode 100644
index 0000000000..67e297e652
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/hidden-execcommand-crash.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1280134">
+
+<html contenteditable=true>
+ X<div style="content-visibility:hidden">Y</div>Z
+<script>
+document.execCommand("selectall");
+document.execCommand("fontSize", false, 6);
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/hidden-pseudo-element-removed-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/hidden-pseudo-element-removed-crash.html
new file mode 100644
index 0000000000..62e38f214b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/hidden-pseudo-element-removed-crash.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html class="test-wait">
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<meta name="assert" content="Removing elements under hidden subtrees doesn't crash">
+
+<p id="parent"><q><svg><marker display="list-item"><hr><object id="inner">
+<style>
+q {
+ content-visibility: hidden;
+}
+</style>
+<script>
+ onload = () => {
+ document.getElementById("parent").hidden = true;
+ var test = document.getElementById("inner").border;
+ document.getElementById("parent").textContent = undefined;
+
+ requestAnimationFrame(() => document.documentElement.classList.remove('test-wait'));
+ }
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/inheritance.html b/testing/web-platform/tests/css/css-contain/content-visibility/inheritance.html
new file mode 100644
index 0000000000..e1ae8164de
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/inheritance.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Content Visibility: content-visibility inheritance</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility does not inherit">
+<meta name="assert" content="content-visibility has initial value 'visible'">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script src="/css/support/inheritance-testcommon.js"></script>
+</head>
+<body>
+<div id="container">
+<div id="target"></div>
+</div>
+<script>
+assert_not_inherited("content-visibility", "visible", "auto");
+</script>
+</body>
+</html>
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/inline-container-with-child-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/inline-container-with-child-ref.html
new file mode 100644
index 0000000000..0230dba853
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/inline-container-with-child-ref.html
@@ -0,0 +1,27 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: container with child and text (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+ display: inline;
+}
+#child {
+ width: 50px;
+ height: 50px;
+ background: green;
+}
+</style>
+
+<p>Test passes if you can see PASS and a green box below.
+<div id=container>
+ PASS
+ <div id=child></div>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/meter-selection-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/meter-selection-crash.html
new file mode 100644
index 0000000000..9edca97568
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/meter-selection-crash.html
@@ -0,0 +1,21 @@
+<!doctype HTML>
+<link rel=author href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="meter, iframe, and selection API should not crash">
+
+<style>
+* {
+ all: initial;
+ content-visibility: hidden;
+}
+</style>
+
+<meter></meter><iframe id="frame"></iframe>
+<script>
+function runTest() {
+ var range_beadc = window.getSelection();
+ var elem1 = document.getElementById("frame");
+ range_beadc.setBaseAndExtent(elem1, 0, document.getElementById("none"), 0);
+}
+onload = runTest;
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/parsing/content-visibility-computed.html b/testing/web-platform/tests/css/css-contain/content-visibility/parsing/content-visibility-computed.html
new file mode 100644
index 0000000000..6e08deebea
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/parsing/content-visibility-computed.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Content Visibility: content-visibility with computed values</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility supports the full grammar 'visible | auto | hidden'.">
+<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>
+<div id=scratch></div>
+<script>
+
+test_computed_value("content-visibility", "visible");
+test_computed_value("content-visibility", "auto");
+test_computed_value("content-visibility", "hidden");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/parsing/content-visibility-invalid.html b/testing/web-platform/tests/css/css-contain/content-visibility/parsing/content-visibility-invalid.html
new file mode 100644
index 0000000000..610e219e1b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/parsing/content-visibility-invalid.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Content Visibility: content-visibility with invalid values</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility supports the full grammar 'visible | auto | hidden'.">
+<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("content-visibility", "visible auto");
+test_invalid_value("content-visibility", "foo-bar");
+test_invalid_value("content-visibility", "foo bar baz");
+test_invalid_value("content-visibility", "hidden visible");
+test_invalid_value("content-visibility", "invisible invisible invisible");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/parsing/content-visibility-valid.html b/testing/web-platform/tests/css/css-contain/content-visibility/parsing/content-visibility-valid.html
new file mode 100644
index 0000000000..a0525695de
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/parsing/content-visibility-valid.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Content Visibility Test: content-visibility with valid values</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="content-visibility supports the full grammar 'visible | auto | hidden'.">
+<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("content-visibility", "visible");
+test_valid_value("content-visibility", "auto");
+test_valid_value("content-visibility", "hidden");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/positioned-container-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/positioned-container-ref.html
new file mode 100644
index 0000000000..2ea2c18b0d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/positioned-container-ref.html
@@ -0,0 +1,22 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: positioned container (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+.positioned {
+ position: absolute;
+ top: 0;
+ left: 0;
+}
+</style>
+
+<div id=container class=positioned></div>
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/resources/circles.svg b/testing/web-platform/tests/css/css-contain/content-visibility/resources/circles.svg
new file mode 100644
index 0000000000..1a9ad7534d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/resources/circles.svg
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>
+<svg viewBox="0 0 500 300" xmlns="http://www.w3.org/2000/svg">
+<rect x="0" y="0" width="500" height="300" fill="#fff" />
+
+<g stroke-width="10" transform="translate(-30)">
+ <circle cx="80" cy="50" r="35" fill="#084" stroke="none"/>
+ <circle cx="80" cy="50" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="120" r="35" fill="#004" stroke="none"/>
+ <circle cx="80" cy="120" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="190" r="35" fill="#088" stroke="none"/>
+ <circle cx="80" cy="190" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="260" r="35" fill="#008" stroke="none"/>
+ <circle cx="80" cy="260" r="20" fill="#080" stroke="#FF0"/>
+</g>
+
+<g stroke-width="10" transform="translate(170)">
+ <circle cx="80" cy="50" r="35" fill="#085" stroke="none"/>
+ <circle cx="80" cy="50" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="120" r="35" fill="#005" stroke="none"/>
+ <circle cx="80" cy="120" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="190" r="35" fill="#689" stroke="none"/>
+ <circle cx="80" cy="190" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="260" r="35" fill="#609" stroke="none"/>
+ <circle cx="80" cy="260" r="20" fill="#080" stroke="#FF0"/>
+</g>
+
+<g stroke-width="10" transform="translate(370)">
+ <circle cx="80" cy="50" r="35" fill="#084" stroke="none"/>
+ <circle cx="80" cy="50" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="120" r="35" fill="#084" stroke="none"/>
+ <circle cx="80" cy="120" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="190" r="35" fill="#088" stroke="none"/>
+ <circle cx="80" cy="190" r="20" fill="#080" stroke="#FF0"/>
+ <circle cx="80" cy="260" r="35" fill="#088" stroke="none"/>
+ <circle cx="80" cy="260" r="20" fill="#080" stroke="#FF0"/>
+</g>
+</svg>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/resources/dice.png b/testing/web-platform/tests/css/css-contain/content-visibility/resources/dice.png
new file mode 100644
index 0000000000..f18b814176
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/resources/dice.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/resources/frame.html b/testing/web-platform/tests/css/css-contain/content-visibility/resources/frame.html
new file mode 100644
index 0000000000..14f48b99a8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/resources/frame.html
@@ -0,0 +1,8 @@
+<!doctype HTML>
+<style>
+div {
+ background: lightgreen;
+}
+</style>
+<div>dolor sit amet</div>
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/resources/slot-content-visibility.html b/testing/web-platform/tests/css/css-contain/content-visibility/resources/slot-content-visibility.html
new file mode 100644
index 0000000000..8652f91ded
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/resources/slot-content-visibility.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+
+>
+<div>
+ <template shadowroot=open>
+ <slot style="content-visibility: hidden; display: block"></slot>
+ </template>
+ a
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/resources/text-fragment-target-auto.html b/testing/web-platform/tests/css/css-contain/content-visibility/resources/text-fragment-target-auto.html
new file mode 100644
index 0000000000..53a22f5fd8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/resources/text-fragment-target-auto.html
@@ -0,0 +1,64 @@
+<!doctype html>
+<title>Text fragment navigation helper.</title>
+
+<script src="/scroll-to-text-fragment/stash.js"></script>
+<script>
+function isInView(element) {
+ let rect = element.getBoundingClientRect();
+ return rect.top >= 0 && rect.top <= window.innerHeight
+ && rect.left >= 0 && rect.left <= window.innerWidth;
+}
+function checkScroll() {
+ let position = 'unknown';
+ if (window.scrollY == 0)
+ position = 'top';
+ else if(isInView(document.getElementById("text")))
+ position = 'text';
+ else if(isInView(document.getElementById("text2")))
+ position = 'text2';
+ else if(isInView(document.getElementById("text3")))
+ position = 'text3';
+
+ const target = document.querySelector(":target");
+ let results = {
+ scrollPosition: position,
+ href: window.location.href,
+ target: target ? target.id : 'undefined'
+ };
+ let key = (new URL(document.location)).searchParams.get("key");
+ stashResultsThenClose(key, results);
+}
+function doubleRafCheckScroll() {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ checkScroll();
+ });
+ });
+}
+</script>
+
+<style>
+.spacer {
+ height: 10000px;
+}
+.auto {
+ content-visibility: auto;
+}
+</style>
+
+<body onload="doubleRafCheckScroll()">
+<div class=spacer></div>
+<div class=auto>
+ <div id=text>hiddentext</div>
+</div>
+<div class=spacer></div>
+<div id=text2and3ancestor>
+ <div class=auto>
+ <div id=text2>start</div>
+ </div>
+ <div class=spacer></div>
+ <div class=auto>
+ <div id=text3>end</div>
+ </div>
+</div>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/scrollIntoView-target-with-contents-hidden-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/scrollIntoView-target-with-contents-hidden-ref.html
new file mode 100644
index 0000000000..1b554d7468
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/scrollIntoView-target-with-contents-hidden-ref.html
@@ -0,0 +1,34 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: scrollIntoView should scroll when target has content-visibility: hidden</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#target {
+ width: 150px;
+ height: 150px;
+ background: lightgreen;
+}
+</style>
+
+<div class="spacer"></div>
+<div id="target"></div>
+
+<script>
+function runTest() {
+ document.getElementById("target").scrollIntoView();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/scrollIntoView-target-with-contents-hidden.html b/testing/web-platform/tests/css/css-contain/content-visibility/scrollIntoView-target-with-contents-hidden.html
new file mode 100644
index 0000000000..42c8e43c8d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/scrollIntoView-target-with-contents-hidden.html
@@ -0,0 +1,37 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: scrollIntoView should scroll when target has content-visibility: hidden</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="scrollIntoView-target-with-contents-hidden-ref.html">
+<meta name="assert" content="scrollIntoView works properly when used on target with content-visibility: hidden">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#target {
+ width: 150px;
+ height: 150px;
+ background: lightgreen;
+ content-visibility: hidden;
+}
+</style>
+
+<div class="spacer"></div>
+<div id="target">FAIL</div>
+
+<script>
+function runTest() {
+ document.getElementById("target").scrollIntoView();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/scrollIntoView-with-focus-target-with-contents-hidden-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/scrollIntoView-with-focus-target-with-contents-hidden-ref.html
new file mode 100644
index 0000000000..8c45c7de51
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/scrollIntoView-with-focus-target-with-contents-hidden-ref.html
@@ -0,0 +1,34 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: scrollIntoView should scroll when target has content-visibility: hidden</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#target {
+ width: 150px;
+ height: 150px;
+ background: lightgreen;
+}
+</style>
+
+<div class="spacer"></div>
+<div id="target" tabindex="0"></div>
+
+<script>
+function runTest() {
+ document.getElementById("target").focus();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/scrollIntoView-with-focus-target-with-contents-hidden.html b/testing/web-platform/tests/css/css-contain/content-visibility/scrollIntoView-with-focus-target-with-contents-hidden.html
new file mode 100644
index 0000000000..454d1bafa7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/scrollIntoView-with-focus-target-with-contents-hidden.html
@@ -0,0 +1,37 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: scrollIntoView triggered by focus() should scroll when target has content-visibility: hidden</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="scrollIntoView-with-focus-target-with-contents-hidden-ref.html">
+<meta name="assert" content="scrollIntoView triggered by focus() works properly when used on target with content-visibility: hidden">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#target {
+ width: 150px;
+ height: 150px;
+ background: lightgreen;
+ content-visibility: hidden;
+}
+</style>
+
+<div class="spacer"></div>
+<div id="target" tabindex="0">FAIL</div>
+
+<script>
+function runTest() {
+ document.getElementById("target").focus();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-1-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-1-crash.html
new file mode 100644
index 0000000000..7fd4ba7bba
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-1-crash.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1221036">
+
+>
+<div>
+ <template shadowroot=open>
+ <slot style="content-visibility: hidden; display: block"></slot>
+ </template>
+ a
+<script type="text/javascript">
+document.execCommand("selectall");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-10-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-10-crash.html
new file mode 100644
index 0000000000..cc319e26ed
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-10-crash.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1221036">
+
+>
+<div>
+ <template shadowroot=open>
+ <slot style="content-visibility: hidden; display: block"></slot>
+ </template>
+ a
+<script type="text/javascript">
+ const range = new Range();
+ range.setStartBefore(document.body.firstChild);
+ range.setEndAfter(document.body.lastChild);
+ range.getBoundingClientRect();
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-11-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-11-crash.html
new file mode 100644
index 0000000000..7ffc54ca18
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-11-crash.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1221036">
+
+>
+<div>
+ <template shadowroot=open>
+ <slot style="content-visibility: hidden; display: block"></slot>
+ </template>
+ <div style="content-visibility: hidden">a</div>
+<script type="text/javascript">
+ const range = new Range();
+ range.setStartBefore(document.body.firstChild);
+ range.setEndAfter(document.body.lastChild);
+ range.getBoundingClientRect();
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-12-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-12-crash.html
new file mode 100644
index 0000000000..33e9d702a4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-12-crash.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1221036">
+
+<div>
+ <template shadowroot=open>
+ <slot style="content-visibility: hidden; display: block"></slot>
+ </template>
+ a
+</div>
+<iframe src="resources/slot-content-visibility.html"></iframe>
+<div>
+ <template shadowroot=open>
+ <slot style="content-visibility: hidden; display: block"></slot>
+ </template>
+ a
+</div>
+<iframe src="resources/slot-content-visibility.html"></iframe>
+<div>
+ <template shadowroot=open>
+ <slot style="content-visibility: hidden; display: block"></slot>
+ </template>
+ a
+</div>
+
+<script>
+ const range = new Range();
+ range.setStartBefore(document.body.firstChild);
+ range.setEndAfter(document.body.lastChild);
+ range.getBoundingClientRect();
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-13-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-13-crash.html
new file mode 100644
index 0000000000..3bbe97ce1d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-13-crash.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1250391">
+
+<script>
+ function go() {
+ const range = document.createRange();
+ range.setEnd(document.querySelector('textarea'), 0);
+ document.querySelector('progress').getBoundingClientRect();
+ range.getBoundingClientRect();
+ }
+</script>
+
+<body onload='go()'>
+ <progress>
+ <textarea>hello</textarea>
+ </progress>
+ <div style="content-visibility:hidden"></div>
+</body>
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-14-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-14-crash.html
new file mode 100644
index 0000000000..0f36a7afee
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-14-crash.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1250772">
+
+<script>
+window.onload = () => {
+ window.getSelection().selectAllChildren(document.body);
+ id6.remove();
+};
+</script>
+
+<div>
+ <template shadowroot=open>
+ <slot style="content-visibility:hidden; display:block"></slot>
+ </template>
+ <div id='id6'>
+ <template shadowroot=open>
+ <slot></slot>
+ </template>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-15-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-15-crash.html
new file mode 100644
index 0000000000..14abfb361b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-15-crash.html
@@ -0,0 +1,13 @@
+<script>
+window.onload = () => {
+ window.getSelection().addRange(document.createRange());
+ window.getSelection().modify('extend','right','paragraph')
+}
+</script>
+
+<div>
+ <template shadowroot=open>
+ <slot style="content-visibility:hidden; display:block"></slot>
+ </template>
+ <meter></meter>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-16-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-16-crash.html
new file mode 100644
index 0000000000..80e5d06e11
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-16-crash.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1251931">
+
+<div>
+ <template shadowroot=open></template>
+ <span id="outside"></span>
+</div>
+<div style="content-visibility:hidden"></div>
+<script>
+ getComputedStyle(outside).color;
+ outside.style.color = "green";
+ getComputedStyle(outside).color;
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-17-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-17-crash.html
new file mode 100644
index 0000000000..64e9550e11
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-17-crash.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1251931">
+
+<style>
+ .a + .b { color: green }
+</style>
+<div id="host">
+ <div>
+ <div>
+ <div id="a"></div><div id="b" class="b"></div>
+ </div>
+ </div>
+</div>
+<div style="content-visibility:hidden"></div>
+<script>
+ host.attachShadow({mode:"open"});
+ document.body.offsetTop;
+ a.className = "a";
+ getComputedStyle(b).color;
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-18-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-18-crash.html
new file mode 100644
index 0000000000..0860c37e49
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-18-crash.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1267276">
+
+<table>foo</table>
+<details open=true>
+ <dialog open=true>
+ <table>
+ <tr></tr>
+ </table>
+ </dialog>
+</details>
+
+<script>
+ const dialog = document.querySelector('dialog');
+ dialog.close();
+ dialog.showModal();
+ const cell = document.querySelector('tr').insertCell();
+ document.querySelector('details').appendChild(cell);
+ document.body.attachShadow({mode: 'closed'});
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-19-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-19-crash.html
new file mode 100644
index 0000000000..33b9f39b5f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-19-crash.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1266891">
+
+<details id=details open="true">hello world</details>
+
+<script>
+ document.execCommand("selectAll");
+ details.open = false;
+ document.execCommand(false);
+ document.body.attachShadow({mode: 'open'});
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-2-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-2-crash.html
new file mode 100644
index 0000000000..47b7962ae0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-2-crash.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1221821">
+
+<div>
+ <template shadowroot=open>
+ <slot style="content-visibility: hidden; display: block"></slot>
+ </template>
+<link rel=stylesheet href="/fonts/ahem.css">
+<span style="columns: 1 46px">
+<style>
+* {}
+</style>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-20-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-20-crash.html
new file mode 100644
index 0000000000..a128f6a59d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-20-crash.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1268837">
+
+<style>
+summary {
+ margin: 1px 1px 1px -1px;
+}
+* {
+ max-height: 0vh;
+}
+</style>
+
+<script>
+function jsfuzzer() {
+ document.documentElement.appendChild(document.querySelector('details'));
+ document.execCommand("selectAll");
+ document.querySelector('li').replaceChild(
+ document.querySelector('q'),
+ document.querySelector('div'));
+ document.caretRangeFromPoint(127,487);
+}
+</script>
+
+<body onload=jsfuzzer()>
+
+<li>
+ <div></div>
+ <details>
+ <summary></summary>
+ <q></q>
+ </details>
+</li>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-21-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-21-crash.html
new file mode 100644
index 0000000000..196f0b4a90
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-21-crash.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1269743">
+
+<script>
+ const selection = window.getSelection();
+ document.execCommand("SelectAll");
+ document.documentElement.innerHTML = '<map><rt></rt><b></b></map><article>foo</article><details></details>';
+ const range = selection.getRangeAt(0);
+ const details = document.querySelector('details');
+ range.insertNode(details)
+ selection.modify('extend', 'forward', 'paragraph')
+ selection.collapseToEnd()
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-22-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-22-crash.html
new file mode 100644
index 0000000000..c8b4935ef6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-22-crash.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1318401">
+<details>
+ <details style="column-count:5" open>
+ <select size="2">
+ <option selected>text</option>
+ </select>
+ </details>
+</details>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-3-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-3-crash.html
new file mode 100644
index 0000000000..a84923946a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-3-crash.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1221821">
+
+<div>
+ <template shadowroot=open>
+ <slot style="content-visibility: hidden; display: block"></slot>
+ </template>
+<span autofocus>
+<link rel=stylesheet href="/fonts/ahem.css">
+<body hidden>
+<span style="columns: 4294967236 46px; ">
+<style>
+* {}
+</style>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-4-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-4-crash.html
new file mode 100644
index 0000000000..83e85a14cf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-4-crash.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1221767">
+
+<div>
+ <template shadowroot=open>
+ <slot style="content-visibility: hidden; display: block"></slot>
+ </template>
+a
+<meter>a
+<script>
+document.execCommand("selectall");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-5-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-5-crash.html
new file mode 100644
index 0000000000..01f063301c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-5-crash.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1221121">
+
+<style>
+</style>
+<style>
+</style>
+<style>
+</style>
+<div>
+ <template shadowroot=open>
+ <slot style="content-visibility: hidden; display: block"></slot>
+ </template>
+<embed id="I7" class= accesskey="h">
+<meter class="C8">a
+<script>
+ document.head.appendChild(document.createElement("style"));
+ const styleSheet = document.styleSheets[document.styleSheets.length - 1];
+ styleSheet.insertRule(":root{}");
+ const styleSheet0 = document.styleSheets[0];
+ const test2 = document.getElementById("I7");
+ test2.className += "fuzzClass5";
+ styleSheet0.insertRule('.C8 {}');
+ try {
+ test2.style.setProperty();
+ } catch(e) {}
+ document.styleSheets[3].disabled = true;
+ test2.style['border-right-color-value'] = '';
+ styleSheet0.insertRule('.foo { color: blue }', styleSheet0.cssRules.length);
+ document.execCommand("false");
+ document.designMode = "on";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-6-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-6-crash.html
new file mode 100644
index 0000000000..3055b04e80
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-6-crash.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1221890">
+
+<a autofocus="autofocus">
+<div>
+ <template shadowroot=open>
+ <slot style="content-visibility: hidden; display: block"></slot>
+ </template>
+</a>
+<svg>
+<clipPath id="svgvar00002">
+</div>
+<svg clip-path="url(#svgvar00002)">
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-7-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-7-crash.html
new file mode 100644
index 0000000000..896ebf7831
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-7-crash.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1221508">
+
+<script>
+function showmodal() {
+ dialog.showModal();
+}
+</script>
+
+<body onload=showmodal()>
+ <div>
+ <template shadowroot=open>
+ <slot style="content-visibility: hidden; display:block"></slot>
+ </template>
+ <dialog id=dialog></dialog>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-8-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-8-crash.html
new file mode 100644
index 0000000000..208e2c72bf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-8-crash.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1222408">
+
+<div id=details>
+ <template shadowroot=open>
+ <slot style="content-visibility: hidden; display: block"></slot>
+ </template>
+</div>
+
+<div id="clear-left">
+<div>X</div>
+<script>
+document.head.appendChild(document.createElement("style"));
+var styleSheet = document.styleSheets[document.styleSheets.length-1];
+styleSheet.insertRule(":root{}"); styleSheet.disabled=false;
+var styleSheet0 = document.styleSheets[0];
+var test0=document.getElementById("clear-left");
+var test5=test0.appendChild(details);
+var test6=test5.appendChild(document.createElement("figure"));
+var test7=test5.appendChild(document.createElement("cite"));
+requestAnimationFrame(function() {
+ styleSheet0.insertRule('p:checked, #clear-left:before {-ms-transform:perspective(45in) rotateX(90deg); -ms-flex-wrap:wrap; }',styleSheet0.cssRules.length);
+ document.execCommand(null);
+ styleSheet0.insertRule('hgroup:link, #clear-left:link {-webkit-animation-name:test; padding-bottom:$grid-padding; }',styleSheet0.cssRules.length);
+ test6.style.setProperty('font-Weight','bold');
+});
+window.scrollTo();
+test7.style.transform = 'scale(1)';
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-9-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-9-crash.html
new file mode 100644
index 0000000000..455d9ffa2e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/slot-content-visibility-9-crash.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1221036">
+
+>
+<div>
+ <template shadowroot=open>
+ <slot style="content-visibility: hidden; display: block"></slot>
+ </template>
+ a
+<script type="text/javascript">
+ const range = new Range();
+ range.setStartBefore(document.body.firstChild);
+ range.setEndAfter(document.body.lastChild);
+ range.getClientRects();
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/spacer-and-container-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/spacer-and-container-ref.html
new file mode 100644
index 0000000000..a2d5f14471
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/spacer-and-container-ref.html
@@ -0,0 +1,23 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: spacer and a container (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+.spacer {
+ width: 150px;
+ height: 3000px;
+ background: lightblue;
+}
+#container {
+ contain: style layout;
+ width: 150px;
+ height: 150px;
+}
+</style>
+
+<div class="spacer">Test passes if there is no red.</div>
+<div id="container"></div>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/spacer-and-container-scrolled-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/spacer-and-container-scrolled-ref.html
new file mode 100644
index 0000000000..a3f8079595
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/spacer-and-container-scrolled-ref.html
@@ -0,0 +1,27 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: spacer and a container, scrolled to container (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+.spacer {
+ width: 150px;
+ height: 300vh;
+ background: lightblue;
+}
+#container {
+ width: 150px;
+ height: 150px;
+ background: green;
+}
+</style>
+
+<div class="spacer"></div>
+<div id="container">Test passes if this is on screen.</div>
+
+<script>
+onload = () => container.scrollIntoView();
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/spacer-with-top-layer-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/spacer-with-top-layer-ref.html
new file mode 100644
index 0000000000..e274b0fcaa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/spacer-with-top-layer-ref.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf8">
+<title>CSS Content Visibility: dialog shows under c-v auto (ref)</title>
+
+<style>
+.box { width: 100px; height: 100px; border: 1px solid black; }
+.spacer { width: 10px; height: 3000px; background: lightblue; }
+</style>
+
+<div class=spacer></div>
+<div id=container class=box>
+content
+<dialog id=dialog>PASS<div id=inner></div></dialog>
+</div>
+
+<script>
+dialog.showModal();
+</script>