summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-contain
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/css/css-contain
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/css/css-contain')
-rw-r--r--testing/web-platform/tests/css/css-contain/META.yml4
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-animation-001.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-bg-001.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-bg-002.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-bg-003.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-bg-004.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-dir-001.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-dir-002.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-dir-003.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-dir-004.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-overflow-001.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-overflow-002.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-overflow-003.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-overflow-004.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-t-o-001.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-t-o-002.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-t-o-003.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-t-o-004.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-w-m-001.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-w-m-002.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-w-m-003.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-body-w-m-004.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-chrome-thcrash-001.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-content-001.html42
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-content-002.html55
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-content-003.html52
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-content-004.html62
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-content-011.html93
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-crash.html12
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-flexbox-outline.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-bg-001.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-bg-002.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-bg-003.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-bg-004.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-dir-001.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-dir-002.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-dir-003.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-dir-004.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-overflow-001.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-overflow-002.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-overflow-003.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-overflow-004.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-t-o-001.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-t-o-002.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-t-o-003.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-t-o-004.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-w-m-001.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-w-m-002.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-w-m-003.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-html-w-m-004.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-bfc-floats-001-ref.html9
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-bfc-floats-001.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-bfc-floats-002-ref.html9
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-bfc-floats-002.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-fieldset-ref.html15
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-fieldset.html16
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-flex.html10
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-flexitem.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-grid-indefinite-height-min-height-flex-row.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-grid-stretches-auto-rows.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-grid.html10
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-intrinsic.html15
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-legend-ref.html13
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-legend.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-multicol.html11
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-regular-container.html10
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-removed.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-replaced.html104
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-table.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-inline-size-vertical-rl-.html10
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-001.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-002.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-003.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-004.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-005.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-006.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-007.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-009.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-010.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-011.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-012.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-013.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-014.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-016.html20
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-017.html22
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-018.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-019.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-020.html43
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-021.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-baseline-001.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-baseline-002.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-baseline-003.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-baseline-004.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-baseline-005.html65
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-breaks-001.html47
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-breaks-002.html53
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-button-001.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-cell-001.html68
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-cell-002.html62
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-containing-block-absolute-001.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-containing-block-fixed-001.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-dynamic-001.html228
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-dynamic-004-ref.html57
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-dynamic-004.html70
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-dynamic-005-ref.html57
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-dynamic-005.html70
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-flexbox-001.html20
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-formatting-context-float-001.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-formatting-context-margin-001-ref.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-formatting-context-margin-001.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-grid-001.html20
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-ifc-022.html53
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-ib-split-001-ref.html76
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-ib-split-001.html77
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-001.html61
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-002-ref.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-002.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-003-ref.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-003.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-independent-formatting-context-001.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-independent-formatting-context-002.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-independent-formatting-context-003.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-013.html40
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-014.html46
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-015.html40
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-016.html46
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-017.html47
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-018.html47
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-019.html69
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-020.html69
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-overflow-001-ref.html55
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-overflow-001.html66
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-overflow-002-ref.html57
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-overflow-002.html67
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-size-003.html41
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-stacking-context-001.html66
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-suppress-baseline-001-ref.html53
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-suppress-baseline-001.html57
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-suppress-baseline-002-ref.html64
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-layout-suppress-baseline-002.html71
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-001.html39
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-002.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-004.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-005.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-006.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-007.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-008.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-009.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-010.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-011.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-012.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-014.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-015.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-016.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-017.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-018.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-019.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-020.html20
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-021.html22
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-022.html56
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-023.html66
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-024.html49
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-025.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-026.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-047.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-048.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-049.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-050-ref.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-050.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-baseline-001.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-cell-001.html69
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-cell-002.html60
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-change-opacity.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-001-ref.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-001.html63
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-002-ref.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-002.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-003-ref.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-003.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-004-ref.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-004.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-005.html41
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-006-ref.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-006.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-011.html64
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-012.html64
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-013.html62
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-014.html63
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-015.html72
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-016.html69
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-017.html59
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-018.html59
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-clip-019.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-containing-block-absolute-001-ref.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-containing-block-absolute-001.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-containing-block-fixed-001-ref.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-containing-block-fixed-001.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-dynamic-001.html199
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-dynamic-002-ref.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-dynamic-002.html47
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-dynamic-003-ref.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-dynamic-003.html48
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-dynamic-004-ref.html57
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-dynamic-004.html70
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-dynamic-005-ref.html57
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-dynamic-005.html70
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-formatting-context-float-001-ref.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-formatting-context-float-001.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-formatting-context-margin-001-ref.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-formatting-context-margin-001.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-ifc-011.html55
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ib-split-001-ref.html76
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ib-split-001.html77
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-internal-table-001-ref.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-internal-table-001a.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-internal-table-001b.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-no-principal-box-001-ref.html57
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-no-principal-box-001.html61
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ruby-containing-block-001-ref.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ruby-containing-block-001.html41
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ruby-stacking-and-clipping-001-ref.html52
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ruby-stacking-and-clipping-001.html60
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-independent-formatting-context-001.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-independent-formatting-context-002.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-independent-formatting-context-003.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-size-001.html39
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-size-002.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-size-003.html41
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-stacking-context-001-ref.html62
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-stacking-context-001a.html66
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-stacking-context-001b.html66
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-table-001.html41
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-paint-table-002.html49
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-001.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-002.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-003.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-004.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-005.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-006.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-007.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-008.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-009.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-010.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-011.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-012.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-012b.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-013.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-021.html56
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-023.html64
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-025.html68
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-027.html73
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-041.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-042.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-051.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-052.html39
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-056.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-061.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-062.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-063.html61
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-064.html39
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-baseline-001.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-block-001-ref.html62
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-block-001.html81
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-block-002-ref.html88
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-block-002.html93
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-block-003-ref.html88
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-block-003.html93
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-block-004-ref.html87
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-block-004.html93
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-borders.html9
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-breaks-001.html65
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-button-001.html20
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-button-002-ref.html87
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-button-002.html109
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-dynamic-001.html90
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-fieldset-001.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-fieldset-002.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-fieldset-003-ref.html43
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-fieldset-003.html99
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-fieldset-004-ref.html41
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-fieldset-004.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-flex-001-ref.html49
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-flex-001.html72
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-flexbox-001.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-flexbox-002.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-grid-001.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-grid-002.html44
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-grid-003.html201
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-grid-004.html210
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-grid-005.html72
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-grid-006.html74
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-grid-indefinite-height-min-height-flex-row.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-grid-stretches-auto-rows.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-inline-block-001-ref.html43
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-inline-block-001.html59
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-inline-block-002-ref.html56
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-inline-block-002.html67
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-inline-block-003-ref.html56
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-inline-block-003.html67
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-inline-block-004-ref.html55
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-inline-block-004.html67
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-inline-flex-001-ref.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-inline-flex-001.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-monolithic-001.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-monolithic-002.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-multicol-001.html46
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-multicol-002-ref.html49
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-multicol-002.html72
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-multicol-003-ref.html66
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-multicol-003.html78
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-multicol-004-ref.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-multicol-004.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-multicol-as-flex-item.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-removed.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-replaced-001.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-replaced-002.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-replaced-003-ref.html46
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-replaced-003a.html50
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-replaced-003b.html50
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-replaced-003c.html50
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-replaced-004-ref.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-replaced-004.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-replaced-005-ref.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-replaced-005.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-replaced-006-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-replaced-006.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-replaced-007.html10
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-scrollbars-001.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-scrollbars-002.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-scrollbars-003.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-scrollbars-004.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-select-001.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-select-002.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-select-elem-001-ref.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-select-elem-001.html50
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-select-elem-002-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-select-elem-002.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-select-elem-003-ref.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-select-elem-003.html44
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-select-elem-004-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-select-elem-004.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-select-elem-005-ref.html42
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-select-elem-005.html54
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-table-caption-001-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-size-table-caption-001.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-strict-001.html39
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-strict-002.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-strict-003.html41
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-strict-011.html63
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-baseline-001.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-breaks-001.html48
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-breaks-002.html52
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-breaks-003.html52
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-breaks-004.html46
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-breaks-005.html46
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-counters-001.html58
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-counters-002.html68
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-counters-003.html69
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-counters-004.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-counters-005.html27
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-counters-ref.html4
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-dynamic-001.html280
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-li-container.html12
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-pseudo-reversed.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-pseudo.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-reversed.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-start-reversed.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-start.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-style-remove-element-crash.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/contain-subgrid-001.html45
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/WEB_FEATURES.yml3
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/animation-container-size.html43
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/animation-container-type-dynamic.html68
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/animation-nested-animation.html47
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/animation-nested-transition.html44
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/aspect-ratio-feature-evaluation.html49
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/at-container-parsing.html195
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/at-container-serialization.html74
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/at-container-style-parsing.html75
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/at-container-style-serialization.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/auto-scrollbars.html53
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/backdrop-invalidation.html51
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/calc-evaluation.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-001.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-002.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-003.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-004.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-005.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-006.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/change-display-in-container-ref.html4
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/change-display-in-container.html27
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/chrome-legacy-skip-recalc.html20
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/column-spanner-in-container.html41
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/conditional-container-status.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-computed.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-for-cue-ref.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-for-cue.html27
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-for-shadow-dom.html343
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-inheritance.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-inner-at-rules.html196
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-inside-multicol-with-table.html41
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-longhand-animation-type.html45
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-name-computed.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-name-invalidation.html74
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-name-parsing.html45
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-name-tree-scoped.html112
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-nested.html239
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-parsing.html63
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-selection-unknown-features.html39
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-selection.html183
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-size-invalidation-after-load.html39
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-size-invalidation.html39
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-size-nested-invalidation.html62
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-size-shadow-invalidation.html53
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-type-computed.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-type-containment.html85
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-type-invalidation.html70
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-type-layout-invalidation.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-type-parsing.html44
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-animation.html70
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-basic.html54
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-computational-independence.html20
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-content-box.html58
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient-invalidation.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient-ref.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container-dynamic.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container-fallback.html68
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container.html111
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-ineligible-container.html44
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-invalidation.html119
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-media-queries.html61
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-rule-cache-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-rule-cache.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-selection.html101
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-shadow.html63
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-sharing-via-rule-node-ref.html22
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-sharing-via-rule-node.html53
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-small-viewport-fallback.html70
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-svglength.html95
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/container-units-typed-om.html59
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/counters-flex-circular.html76
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/counters-in-container-dynamic.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/counters-in-container.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/counters-ref.html4
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/br-crash.html6
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/canvas-as-container-crash.html10
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1289718-000-crash.html6
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1289718-001-crash.html6
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1346969-crash.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1362391-crash.html8
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1429955-crash.html5
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1505250-crash.html16
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-custom-highlight-crash.html11
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-layout-root-crash.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-quotes-crash.html11
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-remove-insert-evaluator-crash.html15
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/columns-in-table-001-crash.html10
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/columns-in-table-002-crash.html15
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/container-in-canvas-crash.html11
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/container-type-change-chrome-legacy-crash.html16
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/dialog-backdrop-crash.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/dirty-rowgroup-crash.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-000-crash.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-001-crash.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-002-crash.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-003-crash.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/focus-inside-content-visibility-crash.html42
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/force-sibling-style-crash.html16
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-000-crash.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-001-crash.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-002-crash.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-003-crash.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/iframe-init-crash.html3
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-multicol-inside-container-crash.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-with-columns-000-crash.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-with-columns-001-crash.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/input-column-group-container-crash.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/input-placeholder-inline-size-crash.html12
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/marker-gcs-after-disconnect-crash.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/math-block-container-child-crash.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/mathml-container-type-crash.html9
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/orthogonal-replaced-crash.html11
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/pseudo-container-crash.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/remove-dom-child-change-style.html13
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/reversed-ol-crash.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/size-change-during-transition-crash.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/svg-layout-root-crash.html22
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/svg-text-crash.html8
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-000-crash.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-001-crash.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-002-crash.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-003-crash.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-004-crash.html16
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-005-crash.html8
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/custom-layout-container-001.https.html66
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/custom-property-style-queries.html436
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/custom-property-style-query-change.html89
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/deep-nested-inline-size-containers.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/dialog-backdrop-create.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/dialog-backdrop-remove.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/display-contents-dynamic-style-queries.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/display-contents.html93
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/display-in-container-ref.html47
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/display-in-container.html69
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/display-none.html393
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/fieldset-legend-change-ref.html4
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/fieldset-legend-change.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/font-relative-calc-dynamic.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/font-relative-units-dynamic.html328
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/font-relative-units.html118
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/fragmented-container-001.html48
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/get-animations.html34
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/grid-container.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/grid-item-container.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/idlharness.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/iframe-in-container-invalidation.html58
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/iframe-invalidation.html43
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/ineligible-containment.html51
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/inheritance-from-container.html43
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/inline-size-and-min-width.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/inline-size-bfc-floats-ref.html9
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/inline-size-bfc-floats.html47
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/inline-size-containment-vertical-rl.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/inline-size-containment.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/inner-first-line-non-matching-ref.html3
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/inner-first-line-non-matching.html13
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/layout-dependent-focus.html39
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/multicol-container-001.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/multicol-inside-container.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/nested-query-containers.html125
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/nested-size-style-container-invalidation.html40
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/never-match-container.html44
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/orthogonal-wm-container-query.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/percentage-padding-orthogonal.html66
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-001.html59
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002-ref.html6
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002b-ref.html12
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002b.html58
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-003.html69
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-004.html52
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-005.html58
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-006.html66
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-007.html49
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-008.html66
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-009-ref.html4
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-009.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-010-ref.html3
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-010.html39
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-011.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-012.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-013.html42
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/query-content-box.html80
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/query-evaluation-style.html80
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/query-evaluation.html87
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/reattach-container-with-dirty-child.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/resize-while-content-visibility-hidden-ref.html3
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/resize-while-content-visibility-hidden.html53
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/sibling-layout-dependency.html134
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/size-container-no-principal-box.html63
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/size-container-with-quotes-ref.html3
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/size-container-with-quotes.html11
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/size-feature-evaluation.html91
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/style-change-in-container.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/style-container-for-shadow-dom.html263
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/style-container-invalidation-inheritance.html45
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/style-not-sharing-float.html40
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/style-query-with-unknown-width.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/support/cq-testcommon.js3
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/support/test.vtt4
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-child-container.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-no-size-container-ref.html4
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-no-size-container.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/svg-g-no-size-container-ref.html4
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/svg-g-no-size-container.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/svg-root-size-container.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/table-inside-container-changing-display-ref.html4
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/table-inside-container-changing-display.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-backdrop-ref.html3
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-backdrop.html20
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-container.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog.html45
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/top-layer-nested-dialog.html45
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/transition-scrollbars.html59
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/transition-style-change-event-002.html45
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/transition-style-change-event.html58
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/unsupported-axis.html228
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/viewport-units-dynamic.html59
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/viewport-units.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/container-queries/whitespace-update-after-removal.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/WEB_FEATURES.yml3
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/animation-display-lock.html192
-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.html36
-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.html45
-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.html47
-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.html63
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-029.html26
-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.html72
-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.html44
-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.html42
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-050.html40
-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.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-075.html45
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-076.html45
-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.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-079.html20
-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-085.html39
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-086.html42
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-087.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-088.html46
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-089.html48
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-090.html51
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-091.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-092.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-093.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-094-ref.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-094.html44
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-095-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-095.html47
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-096-ref.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-096.html56
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-097-ref.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-097.html60
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-098.html52
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-099-ref.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-099.html59
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-and-scroll-ref.html20
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-and-scroll.html60
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-becomes-visible-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-becomes-visible.html54
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-in-auto-subtree.html239
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-auto-subtree.html82
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-hidden-subtree.html81
-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-first-observation-immediate.html53
-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-nested-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-nested-scroll-ref.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-nested-scroll.html40
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-nested.html27
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-relevancy-updates.html109
-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-removed.html41
-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-auto-text-fragment.html46
-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-interpolation.html84
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-layout-containment-001.html185
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-layout-paint-containment-001.html179
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-on-g-ref.html13
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-on-g.html15
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-on-root-svg-ref.html5
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-on-root-svg.html15
-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-paint-containment-001-ref.html46
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-001.html50
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-002-ref.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-002.html53
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-003-ref.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-003.html53
-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-selection-crash.html20
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-size-containment-001.html264
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-style-containment-001.html202
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-svg-path.html101
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-svg-rect.html52
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-svg-text.html60
-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-vs-scrollIntoView-001-ref.html42
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-001.html59
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-002-ref.html59
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-002.html63
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-003.html80
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-web-animation-in-auto-subtree.html74
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-float-crash.html12
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-000.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-001.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-002.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-003.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-004.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-005.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-006.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-and-auto-descendant-ref.html13
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-and-auto-descendant.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-hide-after-addition.html33
-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.html37
-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.html45
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-007.html41
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-008.html46
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-and-auto-descendant-ref.html13
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-and-auto-descendant.html31
-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-visibility-with-top-layer-in-auto-subtree-removal.html43
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-with-popover-top-layer-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/content-with-top-layer-ref.html18
-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/content-visibility-transition-finished-001.html43
-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/crashtests/grid-dynamic.html11
-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/display-ruby-text-crash.html13
-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/locked-frame-crash.html8
-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/resources/text-fragment-target-matchable.html61
-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-popover-top-layer-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/spacer-with-top-layer-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/content-visibility/touch-action-beside-display-locked-fixedpos-iframe-crash.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/counter-scoping-001.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/counter-scoping-002.html27
-rw-r--r--testing/web-platform/tests/css/css-contain/counter-scoping-003.html29
-rw-r--r--testing/web-platform/tests/css/css-contain/counter-scoping-004.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/crashtests/contain-nested-crash-001.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/crashtests/contain-nested-crash-002.html15
-rw-r--r--testing/web-platform/tests/css/css-contain/crashtests/contain-nested-crash-003.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/crashtests/contain-nested-crash-004.html12
-rw-r--r--testing/web-platform/tests/css/css-contain/crashtests/contain-nested-relayout-boundary.html11
-rw-r--r--testing/web-platform/tests/css/css-contain/inheritance.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/parsing/contain-computed-children.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/parsing/contain-computed.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/parsing/contain-invalid.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/parsing/contain-valid.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/quote-scoping-001.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/quote-scoping-002.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/quote-scoping-003.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/quote-scoping-004.html32
-rw-r--r--testing/web-platform/tests/css/css-contain/quote-scoping-empty-style-boundaries.html13
-rw-r--r--testing/web-platform/tests/css/css-contain/quote-scoping-invalidation-001.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/quote-scoping-invalidation-002.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/quote-scoping-invalidation-003.html41
-rw-r--r--testing/web-platform/tests/css/css-contain/quote-scoping-invalidation-004.html40
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-baseline-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-body-bg-001-ref.html15
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-body-overflow-001-ref.html15
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-body-t-o-001-ref.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-body-w-m-001-ref.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-content-011-ref.html27
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-layout-020-ref.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-layout-021-ref.html27
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-layout-baseline-004-ref.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-layout-baseline-005-ref.html61
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-layout-breaks-002-ref.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-layout-button-001-ref.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-layout-cell-001-ref.html43
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-layout-flexbox-001-ref.html16
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-layout-grid-001-ref.html16
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-layout-ifc-022-ref.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-013-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-014-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-015-ref.html11
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-019-ref.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-020-ref.html20
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-layout-size-003-ref.html37
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-paint-001-ref.html26
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-paint-007-ref.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-paint-008-ref.html16
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-paint-022-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-paint-047-ref.html20
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-paint-clip-015-ref.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-paint-clip-019-ref.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-paint-ifc-011-ref.html46
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-paint-independent-formatting-context-001-ref.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-paint-independent-formatting-context-003-ref.html14
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-paint-size-001-ref.html20
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-paint-size-003-ref.html38
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-004-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-005-ref.html16
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-021-ref.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-022-ref.html11
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-023-ref.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-025-ref.html13
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-027-ref.html41
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-051-ref.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-056-ref.html33
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-061-ref.html9
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-062-ref.html22
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-063-ref.html6
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-064-ref.html28
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-breaks-001-ref.html31
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-button-001-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-fieldset-001-ref.html15
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-fieldset-002-ref.html19
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-flexbox-001-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-flexbox-002-ref.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-grid-001-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-grid-005-ref.html49
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-monolithic-001-ref.html21
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-scrollbars-001-ref.html13
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-scrollbars-004-ref.html25
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-size-select-001-ref.html12
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-strict-011-ref.html23
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-style-breaks-001-ref.html36
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-style-breaks-004-ref.html30
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-style-counters-001-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-style-counters-003-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-style-counters-004-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-style-counters-005-ref.html22
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-li-container-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-pseudo-ref.html12
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-pseudo-reversed-ref.html12
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-ref.html12
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-reversed-ref.html12
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-start-ref.html12
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-start-reversed-ref.html12
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/contain-subgrid-001.html35
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/counter-scoping-001-ref.html9
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/counter-scoping-003-ref.html9
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/counter-scoping-004-ref.html15
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/pass_if_pass_below_clipped.html13
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/quote-scoping-001-ref.html8
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/quote-scoping-002-ref.html8
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/quote-scoping-003-ref.html8
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/quote-scoping-empty-style-boundaries-ref.html12
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/quote-scoping-invalidation-001-ref.html7
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/quote-scoping-invalidation-002-ref.html7
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/quote-scoping-invalidation-003-ref.html7
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/quote-scoping-invalidation-004-ref.html7
-rw-r--r--testing/web-platform/tests/css/css-contain/reference/ref-if-there-is-no-red.xht18
-rw-r--r--testing/web-platform/tests/css/css-contain/support/60x60-green.pngbin0 -> 218 bytes
-rw-r--r--testing/web-platform/tests/css/css-contain/support/blue-100x100.pngbin0 -> 40279 bytes
-rw-r--r--testing/web-platform/tests/css/css-contain/support/blue50wBy25h.pngbin0 -> 203 bytes
-rw-r--r--testing/web-platform/tests/css/css-contain/support/blue50wBy46h.pngbin0 -> 234 bytes
-rw-r--r--testing/web-platform/tests/css/css-contain/support/pattern-gg-gr-100x100.pngbin0 -> 309 bytes
-rw-r--r--testing/web-platform/tests/css/css-contain/support/swatch-blue.pngbin0 -> 84 bytes
-rw-r--r--testing/web-platform/tests/css/css-contain/support/swatch-orange.pngbin0 -> 84 bytes
-rw-r--r--testing/web-platform/tests/css/css-contain/support/swatch-red.pngbin0 -> 84 bytes
-rw-r--r--testing/web-platform/tests/css/css-contain/support/swatch-yellow.pngbin0 -> 84 bytes
-rw-r--r--testing/web-platform/tests/css/css-contain/support/white.webmbin0 -> 10880 bytes
989 files changed, 40019 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-contain/META.yml b/testing/web-platform/tests/css/css-contain/META.yml
new file mode 100644
index 0000000000..259c00b2a5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/META.yml
@@ -0,0 +1,4 @@
+spec: https://drafts.csswg.org/css-contain/
+suggested_reviewers:
+ - tabatkins
+ - frivoal
diff --git a/testing/web-platform/tests/css/css-contain/contain-animation-001.html b/testing/web-platform/tests/css/css-contain/contain-animation-001.html
new file mode 100644
index 0000000000..449221428c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-animation-001.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: contain is not animatable</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert content="the contain property is not animatable">
+<style>
+div {
+ border: 50px solid green;
+ background: red;
+ position: absolute; /* for shrinkwrap */
+ contain: strict;
+
+ animation-duration: 1s;
+ animation-name: bad;
+ animation-play-state: paused;
+
+ font-size: 100px;
+}
+
+@keyframes bad {
+ from {
+ contain: none;
+ }
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div>&nbsp;</div>
+
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-bg-001.html b/testing/web-platform/tests/css/css-contain/contain-body-bg-001.html
new file mode 100644
index 0000000000..b7890faeba
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-bg-001.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment on body prevents background propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="layout containment on body prevents background propagation">
+ <link rel="match" href="reference/contain-body-bg-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html, body, p {
+ margin: 0;
+ width: 300px;
+ height: 200px;
+}
+p {
+ background: white;
+}
+body {
+ background: red;
+ contain: layout;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-bg-002.html b/testing/web-platform/tests/css/css-contain/contain-body-bg-002.html
new file mode 100644
index 0000000000..71237d977e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-bg-002.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on body prevents background propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="paint containment on body prevents background propagation">
+ <link rel="match" href="reference/contain-body-bg-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html, body, p {
+ margin: 0;
+ width: 300px;
+ height: 200px;
+}
+p {
+ background: white;
+}
+body {
+ background: red;
+ contain: paint;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-bg-003.html b/testing/web-platform/tests/css/css-contain/contain-body-bg-003.html
new file mode 100644
index 0000000000..0aaf8b0da8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-bg-003.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment on body prevents background propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="size containment on body prevents background propagation">
+ <link rel="match" href="reference/contain-body-bg-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html, body, p {
+ margin: 0;
+ width: 300px;
+ height: 200px;
+}
+p {
+ background: white;
+}
+body {
+ background: red;
+ contain: size;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-bg-004.html b/testing/web-platform/tests/css/css-contain/contain-body-bg-004.html
new file mode 100644
index 0000000000..af046a96c4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-bg-004.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment on body prevents background propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment on body prevents background propagation">
+ <link rel="match" href="reference/contain-body-bg-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-2/#contain-property">
+
+<style>
+html, body, p {
+ margin: 0;
+ width: 300px;
+ height: 200px;
+}
+p {
+ background: white;
+}
+body {
+ background: red;
+ contain: style;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-dir-001.html b/testing/web-platform/tests/css/css-contain/contain-body-dir-001.html
new file mode 100644
index 0000000000..c055778fe4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-dir-001.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment on body prevents direction propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="layout containment on body prevents direction propagation">
+ <link rel="match" href="reference/contain-body-w-m-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+p {
+ margin: 0;
+ direction: ltr;
+}
+body {
+ margin: 0 auto 0 0;
+ width: 200px;
+ height: 200px;
+ direction: rtl;
+ contain: layout;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-dir-002.html b/testing/web-platform/tests/css/css-contain/contain-body-dir-002.html
new file mode 100644
index 0000000000..31e188f8d1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-dir-002.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on body prevents direction propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="paint containment on body prevents direction propagation">
+ <link rel="match" href="reference/contain-body-w-m-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+p {
+ margin: 0;
+ direction: ltr;
+}
+body {
+ margin: 0 auto 0 0;
+ width: 200px;
+ height: 200px;
+ direction: rtl;
+ contain: paint;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-dir-003.html b/testing/web-platform/tests/css/css-contain/contain-body-dir-003.html
new file mode 100644
index 0000000000..cd01c6f253
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-dir-003.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment on body prevents direction propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="size containment on body prevents direction propagation">
+ <link rel="match" href="reference/contain-body-w-m-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+p {
+ margin: 0;
+ direction: ltr;
+}
+body {
+ margin: 0 auto 0 0;
+ width: 200px;
+ height: 200px;
+ direction: rtl;
+ contain: size;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-dir-004.html b/testing/web-platform/tests/css/css-contain/contain-body-dir-004.html
new file mode 100644
index 0000000000..8b39b4324b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-dir-004.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment on body prevents direction propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment on body prevents direction propagation">
+ <link rel="match" href="reference/contain-body-w-m-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+p {
+ margin: 0;
+ direction: ltr;
+}
+body {
+ margin: 0 auto 0 0;
+ width: 200px;
+ height: 200px;
+ direction: rtl;
+ contain: style;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-overflow-001.html b/testing/web-platform/tests/css/css-contain/contain-body-overflow-001.html
new file mode 100644
index 0000000000..7f368756ca
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-overflow-001.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment on body prevents overflow propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="layout containment on body prevents overflow propagation">
+ <link rel="match" href="reference/contain-body-overflow-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html, body, p, div {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+}
+div { background: red; }
+body {
+ overflow: hidden;
+ contain: layout;
+}
+</style>
+
+<p>Test passes if there is no red.
+
+<div></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-overflow-002.html b/testing/web-platform/tests/css/css-contain/contain-body-overflow-002.html
new file mode 100644
index 0000000000..bf741491c6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-overflow-002.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<html lang=en class="reftest-wait">
+<meta charset=utf-8>
+<title>CSS-contain test: paint containment on body prevents overflow propagation</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<meta name="assert" content="paint containment on body prevents overflow propagation">
+<link rel="match" href="reference/contain-body-overflow-001-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#contain-property">
+<style>
+html, body, p, div {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+}
+div { background: red; }
+body {
+ overflow: hidden;
+ contain: paint;
+}
+:focus {
+ outline: none;
+}
+</style>
+
+<div></div>
+<p tabindex=1 id=target>Test passes if there is no red.
+<script>
+window.onload = function() {
+ document.getElementById("target").focus();
+ setTimeout(() => {
+ document.documentElement.className = "";
+ }, 0);
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-overflow-003.html b/testing/web-platform/tests/css/css-contain/contain-body-overflow-003.html
new file mode 100644
index 0000000000..d38cf53c2f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-overflow-003.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment on body prevents overflow propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="size containment on body prevents overflow propagation">
+ <link rel="match" href="reference/contain-body-overflow-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html, body, p, div {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+}
+div { background: red; }
+body {
+ overflow: hidden;
+ contain: size;
+}
+</style>
+
+<p>Test passes if there is no red.
+
+<div></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-overflow-004.html b/testing/web-platform/tests/css/css-contain/contain-body-overflow-004.html
new file mode 100644
index 0000000000..5064d00c8b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-overflow-004.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment on body prevents overflow propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment on body prevents overflow propagation">
+ <link rel="match" href="reference/contain-body-overflow-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-2/#contain-property">
+
+<style>
+html, body, p, div {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+}
+div { background: red; }
+body {
+ overflow: hidden;
+ contain: style;
+}
+</style>
+
+<p>Test passes if there is no red.
+
+<div></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-t-o-001.html b/testing/web-platform/tests/css/css-contain/contain-body-t-o-001.html
new file mode 100644
index 0000000000..36f70a1df4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-t-o-001.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment on body prevents text-orientation propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="layout containment on body prevents text-orientation propagation">
+ <link rel="match" href="reference/contain-body-t-o-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html {
+ writing-mode: vertical-lr;
+ direction: rtl;
+ width: 100vw;
+ height: 100vh;
+ overflow: hidden;
+}
+body {
+ margin: 0;
+ border-top: 100px solid red;
+ border-bottom: 100px solid green;
+ width: 100vw;
+ height: 100vh;
+ text-orientation: upright;
+ contain: layout;
+}
+p {
+ margin: auto;
+ padding: 150px 0;
+ writing-mode: horizontal-tb;
+ direction: ltr;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-t-o-002.html b/testing/web-platform/tests/css/css-contain/contain-body-t-o-002.html
new file mode 100644
index 0000000000..47d3f480d1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-t-o-002.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on body prevents text-orientation propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="paint containment on body prevents text-orientation propagation">
+ <link rel="match" href="reference/contain-body-t-o-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html {
+ writing-mode: vertical-lr;
+ direction: rtl;
+ width: 100vw;
+ height: 100vh;
+ overflow: hidden;
+}
+body {
+ margin: 0;
+ border-top: 100px solid red;
+ border-bottom: 100px solid green;
+ width: 100vw;
+ height: 100vh;
+ text-orientation: upright;
+ contain: paint;
+}
+p {
+ margin: auto;
+ padding: 150px 0;
+ writing-mode: horizontal-tb;
+ direction: ltr;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-t-o-003.html b/testing/web-platform/tests/css/css-contain/contain-body-t-o-003.html
new file mode 100644
index 0000000000..2323d07838
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-t-o-003.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment on body prevents text-orientation propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="size containment on body prevents text-orientation propagation">
+ <link rel="match" href="reference/contain-body-t-o-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html {
+ writing-mode: vertical-lr;
+ direction: rtl;
+ width: 100vw;
+ height: 100vh;
+ overflow: hidden;
+}
+body {
+ margin: 0;
+ border-top: 100px solid red;
+ border-bottom: 100px solid green;
+ width: 100vw;
+ height: 100vh;
+ text-orientation: upright;
+ contain: size;
+}
+p {
+ margin: auto;
+ padding: 150px 0;
+ writing-mode: horizontal-tb;
+ direction: ltr;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-t-o-004.html b/testing/web-platform/tests/css/css-contain/contain-body-t-o-004.html
new file mode 100644
index 0000000000..3eea6b8d32
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-t-o-004.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment on body prevents text-orientation propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment on body prevents text-orientation propagation">
+ <link rel="match" href="reference/contain-body-t-o-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-2/#contain-property">
+
+<style>
+html {
+ writing-mode: vertical-lr;
+ direction: rtl;
+ width: 100vw;
+ height: 100vh;
+ overflow: hidden;
+}
+body {
+ margin: 0;
+ border-top: 100px solid red;
+ border-bottom: 100px solid green;
+ width: 100vw;
+ height: 100vh;
+ text-orientation: upright;
+ contain: style;
+}
+p {
+ margin: auto;
+ padding: 150px 0;
+ writing-mode: horizontal-tb;
+ direction: ltr;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-w-m-001.html b/testing/web-platform/tests/css/css-contain/contain-body-w-m-001.html
new file mode 100644
index 0000000000..b37e96115c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-w-m-001.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment on body prevents writing-mode propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="layout containment on body prevents writing-mode propagation">
+ <link rel="match" href="reference/contain-body-w-m-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+p { writing-mode: horizontal-tb; margin: 0;}
+body {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+ writing-mode: vertical-rl;
+ contain: layout;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-w-m-002.html b/testing/web-platform/tests/css/css-contain/contain-body-w-m-002.html
new file mode 100644
index 0000000000..15040f0399
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-w-m-002.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on body prevents writing-mode propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="paint containment on body prevents writing-mode propagation">
+ <link rel="match" href="reference/contain-body-w-m-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+p { writing-mode: horizontal-tb; margin: 0;}
+body {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+ writing-mode: vertical-rl;
+ contain: paint;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-w-m-003.html b/testing/web-platform/tests/css/css-contain/contain-body-w-m-003.html
new file mode 100644
index 0000000000..87b1d63466
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-w-m-003.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment on body prevents writing-mode propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="size containment on body prevents writing-mode propagation">
+ <link rel="match" href="reference/contain-body-w-m-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+p { writing-mode: horizontal-tb; margin: 0;}
+body {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+ writing-mode: vertical-rl;
+ contain: size;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/contain-body-w-m-004.html b/testing/web-platform/tests/css/css-contain/contain-body-w-m-004.html
new file mode 100644
index 0000000000..736d4a58aa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-body-w-m-004.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment on body prevents writing-mode propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment on body prevents writing-mode propagation">
+ <link rel="match" href="reference/contain-body-w-m-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-2/#contain-property">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+p { writing-mode: horizontal-tb; margin: 0;}
+body {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+ writing-mode: vertical-rl;
+ contain: style;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/contain-chrome-thcrash-001.html b/testing/web-platform/tests/css/css-contain/contain-chrome-thcrash-001.html
new file mode 100644
index 0000000000..c7c03bca10
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-chrome-thcrash-001.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>CSS Overflow and Transforms: css-overflow-3</title>
+<link rel="author" href="mailto:atotic@google.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://crbug.com/964924">
+<meta name="assert" content="chrome does not crash with css contain edge case">
+<style>
+ * {
+ contain: size layout;
+ }
+ html {
+ outline-style: auto;
+ margin-bottom: 39%;
+ }
+ #target {
+ -webkit-appearance: push-button;
+ }
+</style>
+<output id="target">text</output>
+<script>
+test(() => {
+ document.body.offsetTop;
+ document.querySelector("#target").value = "";
+ document.body.offsetTop;
+ assert_equals(document.querySelector("#target").value, "");
+}, 'chrome does not crash with contain');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/contain-content-001.html b/testing/web-platform/tests/css/css-contain/contain-content-001.html
new file mode 100644
index 0000000000..9d8e1e5c09
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-content-001.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: a block with 'contain: content' alongside a float</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+ <link rel="match" href="reference/contain-layout-ifc-022-ref.html">
+
+
+ <style>
+ div
+ {
+ color: transparent;
+ font-size: 16px;
+ padding: 8px;
+ }
+
+ div#floated-left
+ {
+ background-color: blue;
+ float: left;
+ margin: 8px;
+ width: 6em;
+ }
+
+ div#with-contain-content
+ {
+ background-color: orange;
+ width: 12em;
+
+ contain: content;
+ }
+ </style>
+
+
+ <p>Test passes if the orange rectangle and blue rectangle do not overlap.
+
+ <div id="floated-left">Some text in a blue rectangle.</div>
+
+ <div id="with-contain-content">Some text in an orange rectangle. Some text in an orange rectangle. Some text in an orange rectangle.</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-content-002.html b/testing/web-platform/tests/css/css-contain/contain-content-002.html
new file mode 100644
index 0000000000..7468df7cde
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-content-002.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: content' and margin collapsing</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+ <link rel="match" href="reference/contain-paint-ifc-011-ref.html">
+
+ <meta content="This test checks that a block element with 'contain: content' establishes a new block formatting context which is independent and separate from others. This causes margin collapsing to be ineffective among vertically-adjacent boxes. In this test, the top margin of parent boxes and top margin of their respective first in-flow child do not collapse. Also, in this test, the bottom margin of the last in-flow child of boxes and bottom margin of their respective parent boxes do not collapse." name="assert">
+
+ <style>
+ div
+ {
+ contain: content;
+ margin: 30px 0px;
+ }
+
+ div#grand-grand-parent-orange
+ {
+ background-color: orange;
+ }
+
+ div#grand-parent-blue
+ {
+ background-color: blue;
+ }
+
+ div#parent-lime
+ {
+ background-color: lime;
+ }
+
+ div#collapse-through-child /* margin collapsing through element */
+ {
+ contain: none;
+ }
+ </style>
+
+ <p>Test passes if there are 5 horizontal stripes across the page in this order (from top to bottom): an orange stripe, a blue stripe, a bright green stripe, a blue stripe and then an orange stripe.
+
+ <div id="grand-grand-parent-orange">
+
+ <div id="grand-parent-blue">
+
+ <div id="parent-lime">
+
+ <div id="collapse-through-child"></div>
+
+ </div>
+
+ </div>
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-content-003.html b/testing/web-platform/tests/css/css-contain/contain-content-003.html
new file mode 100644
index 0000000000..24d877740f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-content-003.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: element with 'contain: content' and absolutely positioned descendants</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+ <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+ <meta name="assert" content="This test checks that an element with 'contain: content' acts as containing block for its absolutely positioned descendants.">
+
+ <style>
+ div
+ {
+ width: 100px;
+ }
+
+ div#contain-content
+ {
+ background-color: red;
+ contain: content;
+ height: 100px;
+ }
+
+ div.abspos
+ {
+ background-color: green;
+ height: 50px;
+ position: absolute;
+ right: 0;
+ }
+
+ div#first-abspos
+ {
+ top: 0px;
+ }
+
+ div#second-abspos
+ {
+ bottom: 0px;
+ }
+ </style>
+
+ <body>
+
+ <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+ <div id="contain-content">
+ <div id="first-abspos" class="abspos"></div>
+ <div id="second-abspos" class="abspos"></div>
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-content-004.html b/testing/web-platform/tests/css/css-contain/contain-content-004.html
new file mode 100644
index 0000000000..5276b4d08c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-content-004.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: content' applies to 'table-cell' elements</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+ <link rel="match" href="reference/contain-layout-cell-001-ref.html">
+
+ <meta content="In this test, the td#contain should act as the containing block for div#abs-pos ." name="assert">
+
+ <style>
+ table
+ {
+ background-color: blue;
+ border-spacing: 2px;
+ height: 206px;
+ table-layout: fixed;
+ width: 206px;
+ }
+
+ td
+ {
+ background-color: white;
+ padding: 0px;
+ vertical-align: top;
+ }
+
+ td#contain
+ {
+ contain: content;
+ }
+
+ span
+ {
+ background-color: red;
+ color: yellow;
+ font-family: monospace;
+ vertical-align: top;
+ }
+
+ div#abs-pos
+ {
+ background-color: green;
+ color: white;
+ font-family: monospace;
+ left: 0px;
+ position: absolute;
+ top: 0px;
+ }
+ </style>
+
+ <p>Test passes if there is the word PASS and if there is <strong>no red</strong>.
+
+ <table>
+
+ <tr><td>&nbsp;<td>&nbsp;
+
+ <tr><td>&nbsp;<td id="contain"><span>FAIL</span><div id="abs-pos">PASS</div>
+
+ </table>
diff --git a/testing/web-platform/tests/css/css-contain/contain-content-011.html b/testing/web-platform/tests/css/css-contain/contain-content-011.html
new file mode 100644
index 0000000000..8bed8c4d22
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-content-011.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: content' does not turn on style containment</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+ <link rel="match" href="reference/contain-content-011-ref.html">
+
+ <meta name="assert" content="'contain: content' turns on style containment. So, in this test, the counter of div.abspos child should not be reset and must not be reset.">
+
+ <style>
+ body
+ {
+ counter-reset: counter-of-abspos-div 17;
+ }
+
+ /*
+ This creates a new counter identified as
+ "counter-of-abspos-div" and initially sets
+ such counter to 17 (an entirely arbitrary
+ number)
+ */
+
+ div
+ {
+ width: 100px;
+ }
+
+
+ div#contain-content
+ {
+ background-color: red;
+ contain: content;
+ height: 100px;
+ }
+
+ div.abspos
+ {
+ background-color: green;
+ height: 50px;
+ position: absolute;
+ right: 0;
+ }
+
+ div#contain-content > div.abspos
+ {
+ counter-increment: counter-of-abspos-div 4;
+ }
+
+ /*
+ This increments the counter identified as
+ "counter-of-abspos-div" of the step value
+ of 4 (an entirely arbitrary number) each and
+ every time there is a div.abspos child
+ within the subtree of div#contain-content
+ */
+
+ div#first-abspos
+ {
+ top: 0px;
+ }
+
+ div#second-abspos
+ {
+ bottom: 0px;
+ }
+
+ div#result::after
+ {
+ content: counter(counter-of-abspos-div);
+ font-size: 3em;
+ }
+
+ /*
+ Now, the generated content is set to the
+ current value of the counter identified
+ as "counter-of-abspos-div":
+ 17 + 4 * 2 == 25
+ */
+ </style>
+
+ <body>
+
+ <p>Test passes if there is a filled green square, no red and the number 17.
+
+ <div id="contain-content">
+ <div id="first-abspos" class="abspos"></div>
+ <div id="second-abspos" class="abspos"></div>
+ </div>
+
+ <div id="result"></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-crash.html b/testing/web-platform/tests/css/css-contain/contain-crash.html
new file mode 100644
index 0000000000..373e004c05
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-crash.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1129563">
+<body style="contain: size layout;">
+ <div id="target" style="contain: size layout;"></div>
+ <div id="child"></div>
+</body>
+<script>
+document.body.offsetTop;
+const target = document.getElementById('target');
+const child = document.getElementById('child');
+target.appendChild(child);
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/contain-flexbox-outline.html b/testing/web-platform/tests/css/css-contain/contain-flexbox-outline.html
new file mode 100644
index 0000000000..39cf81688e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-flexbox-outline.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<title>Test `contain: strict` to Flexbox does not crash</title>
+<link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+<link rel="author" href="mailto:kojii@chromium.org">
+<style>
+body {
+ contain: strict;
+ display: flex;
+}
+html {
+ outline: 1px auto;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="target"></div>
+<div id="log"></div>
+<script>
+test(() => {
+ document.body.offsetTop;
+ target.style.width = '100px';
+ document.body.offsetTop;
+}, "Pass if no crash");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-bg-001.html b/testing/web-platform/tests/css/css-contain/contain-html-bg-001.html
new file mode 100644
index 0000000000..6d77ce081e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-bg-001.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment on html prevents background propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="layout containment on html prevents background propagation">
+ <link rel="match" href="reference/contain-body-bg-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html, body, p {
+ margin: 0;
+ width: 300px;
+ height: 200px;
+}
+p {
+ background: white;
+}
+body {
+ background: red;
+}
+html {
+ contain: layout;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-bg-002.html b/testing/web-platform/tests/css/css-contain/contain-html-bg-002.html
new file mode 100644
index 0000000000..57324052b2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-bg-002.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on html prevents background propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="paint containment on html prevents background propagation">
+ <link rel="match" href="reference/contain-body-bg-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html, body, p {
+ margin: 0;
+ width: 300px;
+ height: 200px;
+}
+p {
+ background: white;
+}
+body {
+ background: red;
+}
+html {
+ contain: paint;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-bg-003.html b/testing/web-platform/tests/css/css-contain/contain-html-bg-003.html
new file mode 100644
index 0000000000..f1115ceb2f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-bg-003.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment on html prevents background propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="size containment on html prevents background propagation">
+ <link rel="match" href="reference/contain-body-bg-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html, body, p {
+ margin: 0;
+ width: 300px;
+ height: 200px;
+}
+p {
+ background: white;
+}
+body {
+ background: red;
+}
+html {
+ contain: size;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-bg-004.html b/testing/web-platform/tests/css/css-contain/contain-html-bg-004.html
new file mode 100644
index 0000000000..05fa3f820e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-bg-004.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment on html prevents background propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment on html prevents background propagation">
+ <link rel="match" href="reference/contain-body-bg-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-2/#contain-property">
+
+<style>
+html, body, p {
+ margin: 0;
+ width: 300px;
+ height: 200px;
+}
+p {
+ background: white;
+}
+body {
+ background: red;
+}
+html {
+ contain: style;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-dir-001.html b/testing/web-platform/tests/css/css-contain/contain-html-dir-001.html
new file mode 100644
index 0000000000..c02c2e2765
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-dir-001.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment on html prevents direction propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="layout containment on html prevents direction propagation">
+ <link rel="match" href="reference/contain-body-w-m-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+p {
+ margin: 0;
+ direction: ltr;
+}
+body {
+ margin: 0 auto 0 0;
+ width: 200px;
+ height: 200px;
+ direction: rtl;
+}
+html {
+ contain: layout;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-dir-002.html b/testing/web-platform/tests/css/css-contain/contain-html-dir-002.html
new file mode 100644
index 0000000000..7d23558538
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-dir-002.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on html prevents direction propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="paint containment on html prevents direction propagation">
+ <link rel="match" href="reference/contain-body-w-m-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+p {
+ margin: 0;
+ direction: ltr;
+}
+body {
+ margin: 0 auto 0 0;
+ width: 200px;
+ height: 200px;
+ direction: rtl;
+}
+html {
+ contain: paint;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-dir-003.html b/testing/web-platform/tests/css/css-contain/contain-html-dir-003.html
new file mode 100644
index 0000000000..125f4b70e3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-dir-003.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment on html prevents direction propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="size containment on html prevents direction propagation">
+ <link rel="match" href="reference/contain-body-w-m-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+p {
+ margin: 0;
+ direction: ltr;
+}
+body {
+ margin: 0 auto 0 0;
+ width: 200px;
+ height: 200px;
+ direction: rtl;
+}
+html {
+ contain: size;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-dir-004.html b/testing/web-platform/tests/css/css-contain/contain-html-dir-004.html
new file mode 100644
index 0000000000..af31f64082
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-dir-004.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment on html prevents direction propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment on html prevents direction propagation">
+ <link rel="match" href="reference/contain-body-w-m-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+p {
+ margin: 0;
+ direction: ltr;
+}
+body {
+ margin: 0 auto 0 0;
+ width: 200px;
+ height: 200px;
+ direction: rtl;
+}
+html {
+ contain: style;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-overflow-001.html b/testing/web-platform/tests/css/css-contain/contain-html-overflow-001.html
new file mode 100644
index 0000000000..736ad1a54d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-overflow-001.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment on html prevents overflow propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="layout containment on html prevents overflow propagation">
+ <link rel="match" href="reference/contain-body-overflow-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html, body, p, div {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+}
+div { background: red; }
+body {
+ overflow: hidden;
+}
+html {
+ contain: layout;
+}
+</style>
+
+<p>Test passes if there is no red.
+
+<div></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-overflow-002.html b/testing/web-platform/tests/css/css-contain/contain-html-overflow-002.html
new file mode 100644
index 0000000000..2fd0b5e1a3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-overflow-002.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on html prevents overflow propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="paint containment on html prevents overflow propagation">
+ <link rel="match" href="reference/contain-body-overflow-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html, body, p, div {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+}
+div { background: red; }
+body {
+ overflow: hidden;
+}
+html {
+ height: 400px;
+ contain: paint;
+}
+</style>
+
+<p>Test passes if there is no red.
+
+<div></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-overflow-003.html b/testing/web-platform/tests/css/css-contain/contain-html-overflow-003.html
new file mode 100644
index 0000000000..88ce091891
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-overflow-003.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment on html prevents overflow propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="size containment on html prevents overflow propagation">
+ <link rel="match" href="reference/contain-body-overflow-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html, body, p, div {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+}
+div { background: red; }
+body {
+ overflow: hidden;
+}
+html {
+ contain: size;
+}
+</style>
+
+<p>Test passes if there is no red.
+
+<div></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-overflow-004.html b/testing/web-platform/tests/css/css-contain/contain-html-overflow-004.html
new file mode 100644
index 0000000000..15339ed3dc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-overflow-004.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment on html prevents overflow propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment on html prevents overflow propagation">
+ <link rel="match" href="reference/contain-body-overflow-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-2/#contain-property">
+
+<style>
+html, body, p, div {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+}
+div { background: red; }
+body {
+ overflow: hidden;
+}
+html {
+ contain: style;
+}
+</style>
+
+<p>Test passes if there is no red.
+
+<div></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-t-o-001.html b/testing/web-platform/tests/css/css-contain/contain-html-t-o-001.html
new file mode 100644
index 0000000000..d74fa25266
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-t-o-001.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment on html prevents text-orientation propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="layout containment on html prevents text-orientation propagation">
+ <link rel="match" href="reference/contain-body-t-o-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html {
+ writing-mode: vertical-lr;
+ direction: rtl;
+ width: 100vw;
+ height: 100vh;
+ overflow: hidden;
+}
+body {
+ margin: 0;
+ border-top: 100px solid red;
+ border-bottom: 100px solid green;
+ width: 100vw;
+ height: 100vh;
+ text-orientation: upright;
+}
+html {
+ contain: layout;
+}
+p {
+ margin: auto;
+ padding: 150px 0;
+ writing-mode: horizontal-tb;
+ direction: ltr;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-t-o-002.html b/testing/web-platform/tests/css/css-contain/contain-html-t-o-002.html
new file mode 100644
index 0000000000..9ee3837bd2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-t-o-002.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on html prevents text-orientation propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="paint containment on html prevents text-orientation propagation">
+ <link rel="match" href="reference/contain-body-t-o-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html {
+ writing-mode: vertical-lr;
+ direction: rtl;
+ width: 100vw;
+ height: 100vh;
+ overflow: hidden;
+}
+body {
+ margin: 0;
+ border-top: 100px solid red;
+ border-bottom: 100px solid green;
+ width: 100vw;
+ height: 100vh;
+ text-orientation: upright;
+}
+html {
+ contain: paint;
+}
+p {
+ margin: auto;
+ padding: 150px 0;
+ writing-mode: horizontal-tb;
+ direction: ltr;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-t-o-003.html b/testing/web-platform/tests/css/css-contain/contain-html-t-o-003.html
new file mode 100644
index 0000000000..87e70d505a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-t-o-003.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment on html prevents text-orientation propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="size containment on html prevents text-orientation propagation">
+ <link rel="match" href="reference/contain-body-t-o-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html {
+ writing-mode: vertical-lr;
+ direction: rtl;
+ width: 100vw;
+ height: 100vh;
+ overflow: hidden;
+}
+body {
+ margin: 0;
+ border-top: 100px solid red;
+ border-bottom: 100px solid green;
+ width: 100vw;
+ height: 100vh;
+ text-orientation: upright;
+}
+html {
+ contain: size;
+}
+p {
+ margin: auto;
+ padding: 150px 0;
+ writing-mode: horizontal-tb;
+ direction: ltr;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-t-o-004.html b/testing/web-platform/tests/css/css-contain/contain-html-t-o-004.html
new file mode 100644
index 0000000000..5f7ea2ef18
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-t-o-004.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment on html prevents text-orientation propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment on html prevents text-orientation propagation">
+ <link rel="match" href="reference/contain-body-t-o-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-2/#contain-property">
+
+<style>
+html {
+ writing-mode: vertical-lr;
+ direction: rtl;
+ width: 100vw;
+ height: 100vh;
+ overflow: hidden;
+}
+body {
+ margin: 0;
+ border-top: 100px solid red;
+ border-bottom: 100px solid green;
+ width: 100vw;
+ height: 100vh;
+ text-orientation: upright;
+}
+html {
+ contain: style;
+}
+p {
+ margin: auto;
+ padding: 150px 0;
+ writing-mode: horizontal-tb;
+ direction: ltr;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-w-m-001.html b/testing/web-platform/tests/css/css-contain/contain-html-w-m-001.html
new file mode 100644
index 0000000000..e8c0a8222d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-w-m-001.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment on html prevents writing-mode propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="layout containment on html prevents writing-mode propagation">
+ <link rel="match" href="reference/contain-body-w-m-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+p { writing-mode: horizontal-tb; margin: 0;}
+body {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+ writing-mode: vertical-rl;
+}
+html {
+ contain: layout;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-w-m-002.html b/testing/web-platform/tests/css/css-contain/contain-html-w-m-002.html
new file mode 100644
index 0000000000..f4001a75c0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-w-m-002.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on html prevents writing-mode propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="paint containment on html prevents writing-mode propagation">
+ <link rel="match" href="reference/contain-body-w-m-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+p { writing-mode: horizontal-tb; margin: 0;}
+body {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+ writing-mode: vertical-rl;
+}
+html {
+ contain: paint;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-w-m-003.html b/testing/web-platform/tests/css/css-contain/contain-html-w-m-003.html
new file mode 100644
index 0000000000..c56d42ed7a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-w-m-003.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment on html prevents writing-mode propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="size containment on html prevents writing-mode propagation">
+ <link rel="match" href="reference/contain-body-w-m-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#contain-property">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+p { writing-mode: horizontal-tb; margin: 0;}
+body {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+ writing-mode: vertical-rl;
+}
+html {
+ contain: size;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/contain-html-w-m-004.html b/testing/web-platform/tests/css/css-contain/contain-html-w-m-004.html
new file mode 100644
index 0000000000..09a32ba505
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-html-w-m-004.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment on html prevents writing-mode propagation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment on html prevents writing-mode propagation">
+ <link rel="match" href="reference/contain-body-w-m-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-2/#contain-property">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+p { writing-mode: horizontal-tb; margin: 0;}
+body {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+ writing-mode: vertical-rl;
+}
+html {
+ contain: style;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-bfc-floats-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-bfc-floats-001-ref.html
new file mode 100644
index 0000000000..383920cc99
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-bfc-floats-001-ref.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<p>You should see a wide orange rectangle to the left of the third float, overlapping the float.</p>
+<div style="width:400px;position:relative">
+ <div style="float:right;width:200px;height:100px;background:blue"></div>
+ <div style="float:left;width:250px;height:100px;background:blue"></div>
+ <div style="float:right;width:300px;height:100px;background:blue"></div>
+ <div style="position:absolute;left:0;top:200px;width:200px;height:20px;background-color:orange"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-bfc-floats-001.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-bfc-floats-001.html
new file mode 100644
index 0000000000..0600959756
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-bfc-floats-001.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<title>CSS Containment Test: inline-size of fit-content bfc constrained by floats, affected by height via its contents</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size">
+<link rel="match" href="contain-inline-size-bfc-floats-001-ref.html">
+<style>
+ .float { float: left; background-color: blue; }
+ .right { float: right; }
+
+ #outer { width: 400px; }
+ #float1 { width: 200px; height: 100px; }
+ #float2 { width: 250px; height: 100px; }
+ #float3 { width: 300px; height: 100px; }
+
+ #contain {
+ contain: inline-size;
+ display: flow-root;
+ width: fit-content;
+ line-height: 1em;
+ }
+ #filler { height: 150px; }
+ #orange {
+ display: inline-block;
+ width: 200px;
+ height: 20px;
+ background: orange;
+ vertical-align: top;
+ }
+</style>
+<p>You should see a wide orange rectangle to the left of the third float, overlapping the float.</p>
+<div id="outer">
+ <div id="float1" class="float right"></div>
+ <div id="float2" class="float left"></div>
+ <div id="float3" class="float right"></div>
+ <div id="contain">
+ <span id="orange"></span>
+ <div id="filler"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-bfc-floats-002-ref.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-bfc-floats-002-ref.html
new file mode 100644
index 0000000000..a7d4bc759a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-bfc-floats-002-ref.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<p>You should see a wide orange rectangle to the left of the first float, overlapping the float.</p>
+<div style="width:400px;position:relative">
+ <div style="float:right;width:200px;height:100px;background:blue"></div>
+ <div style="float:left;width:250px;height:100px;background:blue"></div>
+ <div style="float:right;width:300px;height:100px;background:blue"></div>
+ <div style="position:absolute;left:0;top:0;width:300px;height:20px;background-color:orange"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-bfc-floats-002.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-bfc-floats-002.html
new file mode 100644
index 0000000000..691f47c5aa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-bfc-floats-002.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<title>CSS Containment Test: inline-size of fit-content bfc constrained by floats, not affected by height</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size">
+<link rel="match" href="contain-inline-size-bfc-floats-002-ref.html">
+<style>
+ .float { float: left; background-color: blue; }
+ .right { float: right; }
+
+ #outer { width: 400px; }
+ #float1 { width: 200px; height: 100px; }
+ #float2 { width: 250px; height: 100px; }
+ #float3 { width: 300px; height: 100px; }
+
+ #contain {
+ contain: inline-size;
+ display: flow-root;
+ width: fit-content;
+ }
+ #orange {
+ display: inline-block;
+ width: 300px;
+ height: 20px;
+ background: orange;
+ vertical-align: top;
+ }
+</style>
+<p>You should see a wide orange rectangle to the left of the first float, overlapping the float.</p>
+<div id="outer">
+ <div id="float1" class="float right"></div>
+ <div id="float2" class="float left"></div>
+ <div id="float3" class="float right"></div>
+ <div id="contain">
+ <span id="orange"></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-fieldset-ref.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-fieldset-ref.html
new file mode 100644
index 0000000000..fa5415db21
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-fieldset-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>contain:inline-size and fieldset</title>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size">
+<p>The fieldset below has inline-size containment. It should not make any
+ inline-size room for the blue legend line, but it should fit the hotpink
+ square in the block direction (but not in the inline direction, where it
+ should overflow the right border of the fieldset.</p>
+<fieldset style="border:20px solid; width:0; min-width:0;">
+ <legend>
+ <div style="width:200px; height:2px; background:blue;"></div>
+ </legend>
+ <div style="width:100px; height:100px; background:hotpink;"></div>
+</fieldset>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-fieldset.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-fieldset.html
new file mode 100644
index 0000000000..036bffe802
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-fieldset.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>contain:inline-size and fieldset</title>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size">
+<link rel="match" href="contain-inline-size-fieldset-ref.html">
+<p>The fieldset below has inline-size containment. It should not make any
+ inline-size room for the blue legend line, but it should fit the hotpink
+ square in the block direction (but not in the inline direction, where it
+ should overflow the right border of the fieldset.</p>
+<fieldset style="contain:inline-size; border:20px solid; width:fit-content;">
+ <legend>
+ <div style="width:200px; height:2px; background:blue;"></div>
+ </legend>
+ <div style="width:100px; height:100px; background:hotpink;"></div>
+</fieldset>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-flex.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-flex.html
new file mode 100644
index 0000000000..7517ffaca2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-flex.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<title>contain:inline-size on flexbox</title>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="display:flex; contain:inline-size; width:fit-content; border:solid green; border-width:0 50px; background:red;">
+ <div style="width:100px; height:100px;"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-flexitem.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-flexitem.html
new file mode 100644
index 0000000000..12f60fadac
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-flexitem.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title>contain:inline-size on flexitem</title>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width:100px; height:100px; background:red;">
+ <div style="display:flex;">
+ <div style="contain:inline-size; flex-basis:100px; background:green;">
+ <div style="width:300px; height:100px;"></div>
+ </div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-grid-indefinite-height-min-height-flex-row.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-grid-indefinite-height-min-height-flex-row.html
new file mode 100644
index 0000000000..4c27b1cc9f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-grid-indefinite-height-min-height-flex-row.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="author" title="Sammy Gill" href="mailto:sammy.gill@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+<link rel="help" href="https://drafts.csswg.org/css-grid-2/#algo-flex-tracks"
+<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="Grid with inline-size containment, an indefinite height, and min-height will properly size flex rows">
+<style>
+grid {
+ display: grid;
+ min-height: 100px;
+ grid-template-rows: 1fr;
+ contain: inline-size;
+}
+.absolute {
+ position: absolute;
+}
+.align-last-baseline{
+ align-self: last baseline;
+}
+.item {
+ width: 100px;
+ height: 50px;
+ background-color: green;
+}
+</style>
+</head>
+<body>
+ <p>Test passes if there is a filled green square.</p>
+ <grid>
+ <div class="absolute item"></div>
+ <div class="item align-last-baseline"></div>
+ </grid>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-grid-stretches-auto-rows.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-grid-stretches-auto-rows.html
new file mode 100644
index 0000000000..c168950929
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-grid-stretches-auto-rows.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="author" title="Sammy Gill" href="mailto:sammy.gill@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-2/#algo-stretch">
+<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="grid with inline-size containment, and min-height will still distribute extra space to auto rows">
+<style>
+grid {
+ display: grid;
+ min-height: 100px;
+ grid-template-rows: auto;
+ contain: inline-size;
+}
+.absolute {
+ position: absolute;
+}
+.align-end {
+ align-self: end;
+}
+.item {
+ width: 100px;
+ height: 50px;
+ background-color: green;
+}
+</style>
+</head>
+<body>
+ <p>Test passes if there is a filled green square.</p>
+ <grid>
+ <div class="absolute item"></div>
+ <div class="item align-end"></div>
+ </grid>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-grid.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-grid.html
new file mode 100644
index 0000000000..5cd8bfc96e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-grid.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<title>contain:inline-size on grid</title>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="display:grid; contain:inline-size; width:fit-content; border:solid green; border-width:0 50px; background:red;">
+ <div style="width:100px; height:100px;"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-intrinsic.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-intrinsic.html
new file mode 100644
index 0000000000..5d59b6b8d9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-intrinsic.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>contain:inline-size with contain-intrinsic-size</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size">
+<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#propdef-contain-intrinsic-size">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="background:green; contain:inline-size; height:50px; width:fit-content; contain-intrinsic-inline-size:100px">
+ <div style="display:inline-block; width:75px;"></div>
+ <div style="display:inline-block; width:75px;"></div>
+</div>
+<div style="background:green; contain:inline-size; height:fit-content; width:100px; contain-intrinsic-inline-size:50px; writing-mode: vertical-rl;">
+ <div style="display:inline-block; height:35px;"></div>
+ <div style="display:inline-block; height:35px;"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-legend-ref.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-legend-ref.html
new file mode 100644
index 0000000000..6ee9f4fb8f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-legend-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title>contain:inline-size on legend</title>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size">
+<p>There should be blue square (legend), and a yellow square below it (fieldset
+ content).</p>
+<fieldset style="width:fit-content; min-width:0;">
+ <legend style="width:0; border:solid blue; border-width:0 50px; padding:0; background:red;">
+ <div style="width:500px; height:100px;"></div>
+ </legend>
+ <div style="height:100px; background:yellow;"></div>
+</fieldset>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-legend.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-legend.html
new file mode 100644
index 0000000000..13c8d7d7f4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-legend.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title>contain:inline-size on legend</title>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size">
+<link rel="match" href="contain-inline-size-legend-ref.html">
+<p>There should be blue square (legend), and a yellow square below it (fieldset
+ content).</p>
+<fieldset style="width:fit-content; min-width:0;">
+ <legend style="contain:inline-size; border:solid blue; border-width:0 50px; padding:0; background:red;">
+ <div style="width:500px; height:100px;"></div>
+ </legend>
+ <div style="height:100px; background:yellow;"></div>
+</fieldset>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-multicol.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-multicol.html
new file mode 100644
index 0000000000..43510677f5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-multicol.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<title>contain:inline-size on multicol</title>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="columns:4; column-gap:0; contain:inline-size; width:fit-content; border:solid green; border-width:0 50px; background:red;">
+ <div style="width:25px; height:200px;"></div>
+ <div style="column-span:all; width:400px; height:50px;"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-regular-container.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-regular-container.html
new file mode 100644
index 0000000000..bb87a9354c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-regular-container.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<title>contain:inline-size on block-level box</title>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="contain:inline-size; width:fit-content; border:solid green; border-width:0 50px; background:red;">
+ <div style="width:100px; height:100px;"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-removed.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-removed.html
new file mode 100644
index 0000000000..6e82f8c760
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-removed.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Remove inline-size from style.contain</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size">
+<meta name="assert" content="After removing inline-size from style.contain, the element should trigger layout">
+<link rel="match" href="reference/pass_if_pass_below_clipped.html">
+<style>
+
+</style>
+<p>Test passes if there is the word "PASS" below.</p>
+<div id="container" style="contain: inline-size; width:fit-content; overflow: hidden;"><span>PASS</span></div>
+
+<script>
+ window.requestAnimationFrame(() => {
+ document.getElementById("container").style.contain = "";
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-replaced.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-replaced.html
new file mode 100644
index 0000000000..71c9fd7711
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-replaced.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: intrinsic size of inline-size-contained replaced elems</title>
+<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+<meta name=assert
+ content="This test checks that various replaced elements with contain: inline-size have an intrinsic inline size of 0 regardless of their content.">
+<style>
+ .inline-contained {
+ contain: inline-size;
+ width: auto;
+ height: auto;
+ border: none;
+ }
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+
+<body onload="checkLayout('.inline-contained')">
+ <div>
+ <!-- video element: -->
+ <video class="inline-contained" data-expected-width="0" data-expected-height="150"></video>
+ <video class="inline-contained" data-expected-width="0" data-expected-height="150" controls></video>
+ <video class="inline-contained" data-expected-width="0" data-expected-height="100"
+ poster="support/blue-100x100.png"></video>
+ <video class="inline-contained" data-expected-width="0" data-expected-height="100" poster="support/blue-100x100.png"
+ controls></video>
+ <video class="inline-contained" data-expected-width="0" data-expected-height="240" controls>
+ <source src="support/white.webm" type=video/webm>
+ <source src="/media/white.mp4" type="video/mp4">
+ </video>
+ <video class="inline-contained" data-expected-width="0" data-expected-height="240" controls>
+ <source src="support/white.webm" type=video/webm>
+ <source src="/media/white.mp4" type="video/mp4">
+ </video>
+ <br>
+
+ <!-- other misc replaced elements: -->
+ <canvas class="inline-contained" data-expected-width="0" data-expected-height="150"></canvas>
+ <svg class="inline-contained" data-expected-bounding-client-rect-width="0"
+ data-expected-bounding-client-rect-height="150"></svg>
+ <br>
+
+ <!-- Image elements: -->
+ <img class="inline-contained" data-expected-width="0" src="broken">
+ <img class="inline-contained" data-expected-width="0" data-expected-height="100" src="support/blue-100x100.png">
+ <picture>
+ <source srcset="support/blue-100x100.png"><img class="inline-contained" data-expected-width="0"
+ data-expected-height="100">
+ </picture>
+ <br>
+
+ <!-- Document-embedding elements (with a target resource that
+ could provide an intrinsic ratio in some cases, in the absence of
+ contain:inline-size): -->
+ <embed class="inline-contained" data-expected-width="0" data-expected-height="100" src="support/blue-100x100.png">
+ <object class="inline-contained" data-expected-width="0" data-expected-height="100"
+ data="support/blue-100x100.png"></object>
+ <iframe class="inline-contained" data-expected-width="0" data-expected-height="150"></iframe>
+ <iframe class="inline-contained" data-expected-width="0" data-expected-height="150"
+ src="support/blue-100x100.png"></iframe>
+ <br>
+ </div>
+ <!-- Same, but in vertical mode -->
+ <div style="writing-mode: vertical-rl;">
+ <video class="inline-contained" data-expected-width="300" data-expected-height="0"></video>
+ <video class="inline-contained" data-expected-width="300" data-expected-height="0" controls></video>
+ <video class="inline-contained" data-expected-width="100" data-expected-height="0"
+ poster="support/blue-100x100.png"></video>
+ <video class="inline-contained" data-expected-width="100" data-expected-height="0" poster="support/blue-100x100.png"
+ controls></video>
+ <video class="inline-contained" data-expected-width="320" data-expected-height="0" controls>
+ <source src="support/white.webm" type=video/webm>
+ <source src="/media/white.mp4" type="video/mp4">
+ </video>
+ <video class="inline-contained" data-expected-width="320" data-expected-height="0" controls>
+ <source src="support/white.webm" type=video/webm>
+ <source src="/media/white.mp4" type="video/mp4">
+ </video>
+
+ <canvas class="inline-contained" data-expected-width="300" data-expected-height="0"></canvas>
+ <svg class="inline-contained" data-expected-bounding-client-rect-width="300"
+ data-expected-bounding-client-rect-height="0"></svg>
+ <br>
+
+ <img class="inline-contained" data-expected-height="0" src="broken">
+ <img class="inline-contained" data-expected-width="100" data-expected-height="0" src="support/blue-100x100.png">
+ <picture>
+ <source srcset="support/blue-100x100.png"><img class="inline-contained" data-expected-width="100"
+ data-expected-height="0">
+ </picture>
+ <br>
+
+ <embed class="inline-contained" data-expected-width="100" data-expected-height="0" src="support/blue-100x100.png">
+ <object class="inline-contained" data-expected-width="100" data-expected-height="0"
+ data="support/blue-100x100.png"></object>
+ <iframe class="inline-contained" data-expected-width="300" data-expected-height="0"></iframe>
+ <iframe class="inline-contained" data-expected-width="300" data-expected-height="0"
+ src="support/blue-100x100.png"></iframe>
+ <br>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-table.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-table.html
new file mode 100644
index 0000000000..de726caa90
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-table.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title>contain:inline-size on table</title>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<!-- Note that size containment doesn't apply to tables:
+ https://www.w3.org/TR/css-contain-1/#containment-size -->
+<div style="width:100px; height:100px; background:red;">
+ <div style="display:table; contain:inline-size; width:fit-content; background:green;">
+ <div style="width:100px; height:100px;"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-inline-size-vertical-rl-.html b/testing/web-platform/tests/css/css-contain/contain-inline-size-vertical-rl-.html
new file mode 100644
index 0000000000..357ea4fcaf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-inline-size-vertical-rl-.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<title>contain:inline-size on element with vertical writing-mode</title>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="writing-mode:vertical-rl; contain:inline-size; width:fit-content; border:solid green; border-width:50px 0; background:red;">
+ <div style="width:100px; height:100px;"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-001.html
new file mode 100644
index 0000000000..85b959da2b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-001.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment on non-atomic inlines</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="layout containment does not apply to non atomic inlines">
+ <link rel="match" href="../reference/pass_if_pass_below.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+
+<style>
+#pa {
+ contain: layout;
+ height: 100vh; /*If layout containment applies, the span becomes a BFC, height applies, and knocks SS off the page */
+}
+
+#ss {
+ vertical-align: bottom;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div><span id="pa">PA</span><span id="ss">SS</span></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-002.html b/testing/web-platform/tests/css/css-contain/contain-layout-002.html
new file mode 100644
index 0000000000..c243c8eb29
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-002.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment on ruby-base</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="ahem">
+ <meta name=assert content="layout containment does not apply to ruby-base">
+ <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+ position: relative;
+ background: red;
+ width: 100px;
+ height: 100px;
+ padding: 25px;
+ box-sizing: border-box;
+}
+rb {
+ contain: layout;
+ display: ruby-base;
+ font-family: Ahem;
+ font-size: 100px;
+ line-height: 1;
+}
+rb::after {
+ content: "X";
+ color: green;
+ position: absolute;
+ top:0; left: 0;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div><ruby><rb></rb></ruby></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-003.html b/testing/web-platform/tests/css/css-contain/contain-layout-003.html
new file mode 100644
index 0000000000..bc672d9ba1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-003.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment on ruby-base-container</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="ahem">
+ <meta name=assert content="layout containment does not apply to ruby-base-container">
+ <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+ position: relative;
+ background: red;
+ width: 100px;
+ height: 100px;
+ padding: 25px;
+ box-sizing: border-box;
+}
+rbc {
+ contain: layout;
+ display: ruby-base-container;
+ font-family: Ahem;
+ font-size: 100px;
+ line-height: 1;
+}
+rbc::after {
+ content: "X";
+ color: green;
+ position: absolute;
+ top:0; left: 0;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div><ruby><rbc></rbc></ruby></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-004.html b/testing/web-platform/tests/css/css-contain/contain-layout-004.html
new file mode 100644
index 0000000000..08d379d996
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-004.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment on ruby-text-container</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="ahem">
+ <meta name=assert content="layout containment does not apply to ruby-text-container">
+ <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+ position: relative;
+ background: red;
+ width: 100px;
+ height: 100px;
+ padding: 25px;
+ box-sizing: border-box;
+}
+rtc {
+ contain: layout;
+ display: ruby-text-container;
+ font-family: Ahem;
+ font-size: 100px;
+ line-height: 1;
+}
+rtc::after {
+ content: "X";
+ color: green;
+ position: absolute;
+ top:0; left: 0;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div><ruby><rtc></rtc></ruby></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-005.html b/testing/web-platform/tests/css/css-contain/contain-layout-005.html
new file mode 100644
index 0000000000..72256d4348
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-005.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment on ruby-text</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="ahem">
+ <meta name=assert content="layout containment does not apply to ruby-text">
+ <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+ position: relative;
+ background: red;
+ width: 100px;
+ height: 100px;
+ padding: 25px;
+ box-sizing: border-box;
+}
+rt {
+ contain: layout;
+ display: ruby-text;
+ font-family: Ahem;
+ font-size: 100px;
+ line-height: 1;
+}
+rt::after {
+ content: "X";
+ color: green;
+ position: absolute;
+ top:0; left: 0;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div><ruby><rt></rt></ruby></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-006.html b/testing/web-platform/tests/css/css-contain/contain-layout-006.html
new file mode 100644
index 0000000000..57dc518a65
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-006.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment absolutely positioned descendants</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert content="Layout containment makes an element to act as containing block for absolutely positioned descendants.">
+<style>
+#contain-layout {
+ contain: layout;
+ width: 100px;
+ height: 100px;
+ background: red;
+}
+
+#abspos {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="contain-layout">
+ <div id="abspos"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-007.html b/testing/web-platform/tests/css/css-contain/contain-layout-007.html
new file mode 100644
index 0000000000..39be5fe7fd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-007.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment fixed positioned descendants</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert content="Layout containment makes an element to act as containing block for fixed positioned descendants.">
+<style>
+#contain-layout {
+ contain: layout;
+ width: 100px;
+ height: 100px;
+ background: red;
+}
+
+#fixed {
+ position: fixed;
+ bottom: 0;
+ right: 0;
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="contain-layout">
+ <div id="fixed"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-009.html b/testing/web-platform/tests/css/css-contain/contain-layout-009.html
new file mode 100644
index 0000000000..39ef1271af
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-009.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>CSS Containment Test: Layout containment on table-row-group</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=flags content="ahem">
+<meta name=assert content="Layout containment doesn't apply to table-row-group elements.">
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+#wrapper {
+ position: relative;
+ background: red;
+ width: 100px;
+ height: 100px;
+ padding: 25px;
+ box-sizing: border-box;
+}
+#table-row-group {
+ display: table-row-group;
+ contain: layout;
+}
+#abspos {
+ position: absolute;
+ font: 100px/1 Ahem;
+ color: green;
+ top: 0;
+ left: 0;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="wrapper">
+ <div id="table-row-group">
+ <div id="abspos">X</div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-010.html b/testing/web-platform/tests/css/css-contain/contain-layout-010.html
new file mode 100644
index 0000000000..6e4dde8aeb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-010.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>CSS Containment Test: Layout containment on table-header-group</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=flags content="ahem">
+<meta name=assert content="Layout containment doesn't apply to table-header-group elements.">
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+#wrapper {
+ position: relative;
+ background: red;
+ width: 100px;
+ height: 100px;
+ padding: 25px;
+ box-sizing: border-box;
+}
+#table-header-group {
+ display: table-header-group;
+ contain: layout;
+}
+#abspos {
+ position: absolute;
+ font: 100px/1 Ahem;
+ color: green;
+ top: 0;
+ left: 0;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="wrapper">
+ <div id="table-header-group">
+ <div id="abspos">X</div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-011.html b/testing/web-platform/tests/css/css-contain/contain-layout-011.html
new file mode 100644
index 0000000000..99021b4852
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-011.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>CSS Containment Test: Layout containment on table-footer-group</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=flags content="ahem">
+<meta name=assert content="Layout containment doesn't apply to table-footer-group elements.">
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+#wrapper {
+ position: relative;
+ background: red;
+ width: 100px;
+ height: 100px;
+ padding: 25px;
+ box-sizing: border-box;
+}
+#table-footer-group {
+ display: table-footer-group;
+ contain: layout;
+}
+#abspos {
+ position: absolute;
+ font: 100px/1 Ahem;
+ color: green;
+ top: 0;
+ left: 0;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="wrapper">
+ <div id="table-footer-group">
+ <div id="abspos">X</div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-012.html b/testing/web-platform/tests/css/css-contain/contain-layout-012.html
new file mode 100644
index 0000000000..9a2534ee69
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-012.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>CSS Containment Test: Layout containment on table-row</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=flags content="ahem">
+<meta name=assert content="Layout containment doesn't apply to table-row elements.">
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+#wrapper {
+ position: relative;
+ background: red;
+ width: 100px;
+ height: 100px;
+ padding: 25px;
+ box-sizing: border-box;
+}
+#table-row {
+ display: table-row;
+ contain: layout;
+}
+#abspos {
+ position: absolute;
+ font: 100px/1 Ahem;
+ color: green;
+ top: 0;
+ left: 0;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="wrapper">
+ <div id="table-row">
+ <div id="abspos">X</div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-013.html b/testing/web-platform/tests/css/css-contain/contain-layout-013.html
new file mode 100644
index 0000000000..08e1e4d9ec
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-013.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>CSS Containment Test: Layout containment on table-cell</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert content="Layout containment does apply to table-cell elements.">
+
+<style>
+#table-cell {
+ display: table-cell;
+ contain: layout;
+ width: 100px;
+ height: 100px;
+ background: red;
+}
+#abspos {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="table-cell">
+ <div id="abspos"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-014.html b/testing/web-platform/tests/css/css-contain/contain-layout-014.html
new file mode 100644
index 0000000000..bf0e47eee1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-014.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>CSS Containment Test: Layout containment on table-caption</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert content="Layout containment does apply to table-caption elements.">
+
+<style>
+#table-caption {
+ display: table-caption;
+ contain: layout;
+ width: 100px;
+ height: 100px;
+ background: red;
+}
+#abspos {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="table-caption">
+ <div id="abspos"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-016.html b/testing/web-platform/tests/css/css-contain/contain-layout-016.html
new file mode 100644
index 0000000000..e8fdede277
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-016.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment stacking context</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="../reference/pass_if_pass_below.html">
+<meta name=assert content="Layout containment elements create a stacking context.">
+<style>
+div {
+ contain: layout;
+ background: white;
+}
+span {
+ position: relative;
+ z-index: -1;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div><span>PASS</span></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-017.html b/testing/web-platform/tests/css/css-contain/contain-layout-017.html
new file mode 100644
index 0000000000..fd74c5a5f4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-017.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment stacking context</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="../reference/nothing.html">
+<meta name=assert content="Elements in which layout containment doesn't apply, do not create a stacking context.">
+<style>
+rt {
+ display: ruby-text;
+ contain: layout;
+ background: white;
+ overflow: hidden;
+}
+span {
+ position: relative;
+ z-index: -1;
+}
+</style>
+
+<p>There should be nothing below.</p>
+<ruby><rt><span>FAIL</span></rt></ruby>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-018.html b/testing/web-platform/tests/css/css-contain/contain-layout-018.html
new file mode 100644
index 0000000000..5d7ebc0195
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-018.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment stacking context</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="../reference/nothing.html">
+<meta name=assert content="Elements in which layout containment doesn't apply, do not create a stacking context.">
+<style>
+div {
+ display: inline;
+ contain: layout;
+ background: white;
+}
+span {
+ position: relative;
+ z-index: -1;
+}
+</style>
+
+<p>There should be nothing below.</p>
+<div><span>FAIL</span></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-019.html b/testing/web-platform/tests/css/css-contain/contain-layout-019.html
new file mode 100644
index 0000000000..5d112e26f9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-019.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment inside a fit-content element</title>
+<link rel="help" href="https://crbug.com/1268449">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert
+ content="Layout containment inside a fit-content element should update size when the content is changed">
+<style>
+ #contain-parent {
+ width: fit-content;
+ }
+
+ #contain-layout {
+ contain: layout;
+ background: green;
+ }
+
+ #content {
+ width: 50px;
+ height: 100px;
+ }
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="contain-parent">
+ <div id="contain-layout">
+ <div id="content"></div>
+ </div>
+</div>
+
+<script>
+window.requestAnimationFrame(() => {
+ document.body.offsetTop;
+ document.getElementById('content').style.width = '100px';
+ document.body.offsetTop;
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-020.html b/testing/web-platform/tests/css/css-contain/contain-layout-020.html
new file mode 100644
index 0000000000..655d4431d8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-020.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset=utf-8>
+<title>CSS Containment Test: Removing layout containment and contained positioned elements</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="reference/contain-layout-020-ref.html">
+<meta name=assert content="Removing layout containment relayouts contained positioned elements correctly.">
+
+<style>
+#container {
+ width: 300px;
+ height: 300px;
+ contain: layout;
+}
+.box {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+}
+.fixed {
+ position: fixed;
+ top: 0;
+ left: 0;
+}
+.abspos {
+ position: absolute;
+ top: 0;
+ right: 0;
+}
+</style>
+
+<div id="container">
+ <div class="fixed box"></div>
+ <div class="abspos box"></div>
+</div>
+
+<script>
+ requestAnimationFrame(() => {
+ container.style.contain = "none";
+ document.documentElement.removeAttribute("class");
+ });
+</script>
+
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-021.html b/testing/web-platform/tests/css/css-contain/contain-layout-021.html
new file mode 100644
index 0000000000..fcb8130828
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-021.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment fixed positioned descendants</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="reference/contain-layout-021-ref.html">
+<meta name=assert content="Layout containment makes an element to act as containing block for fixed positioned descendants.">
+<style>
+html {
+ contain: layout;
+}
+#fixed {
+ position: fixed;
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+body {
+ height: 3000px;
+ margin: 0px;
+}
+#spacer {
+ height: 200px;
+}
+</style>
+<script>
+function runTest() {
+ document.documentElement.scrollTop += 200;
+}
+</script>
+<body onload="runTest()">
+<div id="spacer"></div>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="fixed"></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-baseline-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-baseline-001.html
new file mode 100644
index 0000000000..cf8e94faa4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-baseline-001.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment and baselines</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=assert content="With contain:layout, for the purpose of the vertical-align property, the containing element is treated as having no baseline.">
+ <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+
+<style>
+#red {
+ position: absolute;
+ background: red;
+ width: 100px;
+ height: 100px;
+ z-index: -1;
+}
+.green {
+ display: inline-block;
+ height: 100px;
+ background: green;
+ width: 50px;
+ contain: layout;
+ color: transparent;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id=red></div>
+<div class=green></div><div class=green>a</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-baseline-002.html b/testing/web-platform/tests/css/css-contain/contain-layout-baseline-002.html
new file mode 100644
index 0000000000..9b86afa9ae
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-baseline-002.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment supress baseline in flex items</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#valdef-align-items-baseline">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert content="Flex items with layout containment are treated as having no baseline, for that reason their baseline is synthesized from the flex item's border box when they're baseline aligned.">
+<style>
+#flex {
+ display: inline-flex;
+ align-items: baseline;
+ background: red;
+}
+
+canvas {
+ background: green;
+ width: 50px;
+ height: 100px;
+}
+
+#item {
+ contain: layout;
+ color: transparent;
+ background: green;
+ width: 50px;
+ height: 100px;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="flex">
+ <canvas></canvas>
+ <div id="item">item</div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-baseline-003.html b/testing/web-platform/tests/css/css-contain/contain-layout-baseline-003.html
new file mode 100644
index 0000000000..d4f8c73878
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-baseline-003.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment supress baseline in grid items</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-baselines">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert content="Grid items with layout containment are treated as having no baseline, for that reason their baseline is synthesized from the grid item's border box when they're baseline aligned.">
+<style>
+#grid {
+ display: inline-grid;
+ align-items: baseline;
+ background: red;
+ grid-auto-flow: column;
+}
+
+canvas {
+ background: green;
+ width: 50px;
+ height: 100px;
+}
+
+#item {
+ contain: layout;
+ color: transparent;
+ background: green;
+ width: 50px;
+ height: 100px;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="grid">
+ <canvas></canvas>
+ <div id="item">item</div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-baseline-004.html b/testing/web-platform/tests/css/css-contain/contain-layout-baseline-004.html
new file mode 100644
index 0000000000..11e81b270b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-baseline-004.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment supress baseline in table cells</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="reference/contain-layout-baseline-004-ref.html">
+<meta name=assert content="Table cells with layout containment are treated as having no baseline, for that reason their baseline is synthesized from the cell's border box when they're baseline aligned.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+#table {
+ display: table;
+ font: 100px/1 Ahem;
+}
+
+#table > * {
+ display: table-cell;
+}
+
+#first {
+ color: blue;
+}
+
+#second {
+ color: green;
+ contain: layout;
+}
+</style>
+<p>Test passes if there is not a rectangle as the two boxes ("blue" and "green") are not baseline aligned.</p>
+<div id="table">
+ <div id="first">X</div>
+ <div id="second">X</div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-baseline-005.html b/testing/web-platform/tests/css/css-contain/contain-layout-baseline-005.html
new file mode 100644
index 0000000000..0971402e6b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-baseline-005.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment supress baseline</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="reference/contain-layout-baseline-005-ref.html">
+<meta name=assert content="This test checks that baseline is suppressed for elements with 'contain: layout', so they are treated as having no baseline (thus its baseline is synthetized).">
+<style>
+.wrapper {
+ height: 110px;
+}
+.wrapper > * {
+ contain: layout;
+ background: cyan;
+ font-size: 20px;
+ vertical-align: baseline;
+}
+.wrapper > :nth-child(1) {
+ background: magenta;
+}
+.inline-block {
+ display: inline-block;
+}
+canvas {
+ width: 100px;
+ height: 100px;
+}
+fieldset, details {
+ display: inline-block;
+ width: max-content;
+}
+</style>
+<p>Test passes if it has the same output than the reference (all elements are aligned on the bottom edge).</p>
+<div class="wrapper">
+ <div class="inline-block" style="font-size: 80px;">foo</div>
+ <div class="inline-block">foo</div>
+ <div class="inline-block" style="border: solid thick; padding: 2px;">foo</div>
+ <div style="display: inline-flex;">foo</div>
+ <div style="display: inline-flex; border: solid thick; padding: 2px;">foo</div>
+ <div style="display: inline-grid;">foo</div>
+ <div style="display: inline-grid; border: solid thick; padding: 2px;">foo</div>
+</div>
+<div class="wrapper">
+ <canvas></canvas>
+ <div class="inline-block">foo</div>
+ <button>foo</button>
+ <select><option>foo</option></select>
+ <select multiple style="height: 40px;"><option>foo</option></select>
+ <textarea style="height: 40px;"></textarea>
+</div>
+<div class="wrapper">
+ <canvas></canvas>
+ <input value="foo" size="3"></input>
+ <input type="file"></input>
+</div>
+<div class="wrapper">
+ <canvas></canvas>
+ <table style="display: inline-table;"><tr><td>foo</td></tr></table>
+ <canvas></canvas>
+ <fieldset></fieldset>
+ <fieldset><legend>foo</legend></fieldset>
+ <fieldset><legend>foo</legend>foo</fieldset>
+ <details></details>
+ <details><summary>foo</summary>foo</details> <details open="true"><summary>foo</summary>foo</details>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-breaks-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-breaks-001.html
new file mode 100644
index 0000000000..a85cf2c6c8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-breaks-001.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout containment and forced breaks</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="layout containment allows forced breaks.">
+ <link rel="match" href="reference/contain-style-breaks-004-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+ <link rel=help href="https://drafts.csswg.org/css-break-3/#forced-break">
+
+<style>
+article {
+ columns: 2 1ch;
+ column-gap: 0;
+ float: left;
+ font-family: monospace;
+ margin-right: 3em;
+ line-height: 1;
+ height: 4em;
+ column-fill: auto;
+}
+div > div:last-of-type {
+ break-before: column;
+}
+#test > div {
+ contain: layout;
+}
+</style>
+
+<p>Test passes if there are two identical blocks “A” letters below.
+<article id=ref>
+ <div>
+ <div>A<br>A</div>
+ <div>A<br>A</div>
+ </div>
+</article>
+<article id=test>
+ <div>
+ <div>A<br>A</div>
+ <div>A<br>A</div>
+ </div>
+</article>
+<!--
+Having two blocks to avoid making browsers that don't support forced break at all fail.
+Since containment is supposed to have no effect, failing such browsers would not be useful.
+-->
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-breaks-002.html b/testing/web-platform/tests/css/css-contain/contain-layout-breaks-002.html
new file mode 100644
index 0000000000..7b5c17ac55
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-breaks-002.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS-contain test: layout containment and forced breaks</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <meta content="forced breaks within layout containment do not propagate to the parent." name="assert">
+
+ <link href="reference/contain-layout-breaks-002-ref.html" rel="match">
+
+ <link href="https://drafts.csswg.org/css-contain-1/#containment-layout" rel="help">
+ <link href="https://drafts.csswg.org/css-break-3/#forced-break" rel="help">
+
+ <style>
+ article
+ {
+ column-fill: auto; /* columns are filled sequentially */
+ column-gap: 0em;
+ columns: 2 100px; /* 2 columns each 100px wide */
+ float: left; /* to make multi-column element shrink-wrap */
+ height: 400px; /* give more than enough to go wrong */
+ }
+
+ div#yellow-normal
+ {
+ border-top: yellow solid 100px;
+ }
+
+ div#blue-parent
+ {
+ border-top: blue solid 100px;
+ contain: layout;
+ }
+
+ div#orange-child
+ {
+ border-top: orange solid 100px;
+ break-before: column;
+ }
+ </style>
+
+ <p>Test passes if there is a) a blue square below a yellow square and b) an orange square below a blue square.
+
+ <article>
+
+ <div id="yellow-normal"></div>
+
+ <div id="blue-parent">
+ <div id="orange-child"></div>
+ </div>
+
+ </article>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-button-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-button-001.html
new file mode 100644
index 0000000000..b53b28879e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-button-001.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment on button</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#propdef-vertical-align">
+<link rel="match" href="reference/contain-layout-button-001-ref.html">
+<meta name=assert content="Layout containment does apply to buttons, thus their baseline is their margin-bottom edge.">
+<style>
+button {
+ border: 5px solid green;
+ padding: 0;
+ /* We use a nonzero margin-bottom to be sure we're synthesizing a baseline
+ from the margin-box rather than from the border-box: */
+ margin-bottom: 2px;
+ contain: layout;
+ color: transparent;
+ width: 0;
+ height: 0;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square aligned 2px above the text's baseline, and then the word "after".</p>
+before<button>b</button>after
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-cell-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-cell-001.html
new file mode 100644
index 0000000000..66710060a7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-cell-001.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: layout' applies to 'table-cell' elements</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+ <link rel="match" href="reference/contain-layout-cell-001-ref.html">
+
+ <meta content="In this test, the div#contain should act as the containing block for div#abs-pos ." name="assert">
+
+ <style>
+ div#table
+ {
+ background-color: blue;
+ border-spacing: 2px;
+ display: table;
+ height: 206px;
+ table-layout: fixed;
+ width: 206px;
+ }
+
+ div.row
+ {
+ display: table-row;
+ }
+
+ div.cell
+ {
+ background-color: white;
+ display: table-cell;
+ vertical-align: top;
+ }
+
+ div#contain
+ {
+ contain: layout;
+ }
+
+ span
+ {
+ background-color: red;
+ color: yellow;
+ font-family: monospace;
+ vertical-align: top;
+ }
+
+ div#abs-pos
+ {
+ background-color: green;
+ color: white;
+ font-family: monospace;
+ left: 0px;
+ position: absolute;
+ top: 0px;
+ }
+ </style>
+
+ <p>Test passes if there is the word PASS and if there is <strong>no red</strong>.
+
+ <div id="table">
+
+ <div class="row"><div class="cell">&nbsp;</div><div class="cell">&nbsp;</div></div>
+
+ <div class="row"><div class="cell">&nbsp;</div><div class="cell" id="contain"><span>FAIL</span><div id="abs-pos">PASS</div></div></div>
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-cell-002.html b/testing/web-platform/tests/css/css-contain/contain-layout-cell-002.html
new file mode 100644
index 0000000000..2c10eb21e0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-cell-002.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: layout' applies to 'table-cell' elements</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+ <link rel="match" href="reference/contain-layout-cell-001-ref.html">
+
+ <meta content="In this test, the td#contain should act as the containing block for div#abs-pos ." name="assert">
+
+ <style>
+ table
+ {
+ background-color: blue;
+ border-spacing: 2px;
+ height: 206px;
+ table-layout: fixed;
+ width: 206px;
+ }
+
+ td
+ {
+ background-color: white;
+ padding: 0px;
+ vertical-align: top;
+ }
+
+ td#contain
+ {
+ contain: layout;
+ }
+
+ span
+ {
+ background-color: red;
+ color: yellow;
+ font-family: monospace;
+ vertical-align: top;
+ }
+
+ div#abs-pos
+ {
+ background-color: green;
+ color: white;
+ font-family: monospace;
+ left: 0px;
+ position: absolute;
+ top: 0px;
+ }
+ </style>
+
+ <p>Test passes if there is the word PASS and if there is <strong>no red</strong>.
+
+ <table>
+
+ <tr><td>&nbsp;<td>&nbsp;
+
+ <tr><td>&nbsp;<td id="contain"><span>FAIL</span><div id="abs-pos">PASS</div>
+
+ </table>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-containing-block-absolute-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-containing-block-absolute-001.html
new file mode 100644
index 0000000000..036cf7d8dd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-containing-block-absolute-001.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: layout' element should contain absolute position elements.</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+ <link rel="match" href="contain-paint-containing-block-absolute-001-ref.html">
+ <style>
+ #a {
+ contain: layout;
+ width: 100px;
+ height: 100px;
+ background: red;
+ margin: 50px;
+ }
+ #b {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ </style>
+</head>
+<body>
+ <div id="a">
+ <div>
+ <div id="b"></div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-containing-block-fixed-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-containing-block-fixed-001.html
new file mode 100644
index 0000000000..979d71d406
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-containing-block-fixed-001.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: layout' element should contain fixed position elements.</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+ <link rel="match" href="contain-paint-containing-block-fixed-001-ref.html">
+ <style>
+ #a {
+ contain: layout;
+ width: 100px;
+ height: 100px;
+ background: red;
+ margin: 50px;
+ }
+ #b {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ </style>
+</head>
+<body>
+ <div id="a">
+ <div>
+ <div id="b"></div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-dynamic-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-dynamic-001.html
new file mode 100644
index 0000000000..428d2b9d4d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-dynamic-001.html
@@ -0,0 +1,228 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Dynamic change to layout containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1765615">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta name="assert" content="Verify layout containment is properly updated after dynamic change to the contain property.">
+<style>
+ /* Selectors for contain */
+ #none .wrapper {
+ contain: none;
+ }
+ #layout .wrapper {
+ contain: layout;
+ }
+ #none_to_layout .wrapper {
+ contain: none;
+ }
+ #layout_to_none .wrapper {
+ contain: layout;
+ }
+
+ /* Selectors for testing absolute/fixed positioned elements */
+ #top_spacer {
+ height: 100px;
+ background: lightgray;
+ }
+ .absolute_pos {
+ position: absolute;
+ top: 42px;
+ }
+ .fixed_pos {
+ position: fixed;
+ top: 42px;
+ }
+
+ /* Selectors for testing baseline */
+ .flex {
+ display: inline-flex;
+ align-items: baseline;
+ }
+
+ /* Selectors for testing IFC (floats) */
+ .floatleft {
+ float: left;
+ }
+ .clearleft {
+ clear: left;
+ }
+
+ /* Selectors for testing IFC (margin collapsing) */
+ .blockmargin {
+ margin: 25px 0;
+ }
+ .wrapper.blockmargin {
+ background: lightgray;
+ }
+
+ .rect {
+ background: black;
+ width: 50px;
+ height: 100px;
+ }
+</style>
+<body>
+ <div id="log"></div>
+
+ <div id="top_spacer"></div>
+
+ <div id="none">
+ <div class="wrapper">
+ <div class="absolute_pos"></div>
+ <div class="fixed_pos"></div>
+ </div>
+ <div class="flex">
+ <div class="rect"></div>
+ <div class="wrapper rect">X</div>
+ </div>
+ <div>
+ <div class="floatleft rect"></div>
+ <div class="wrapper">
+ <div class="clearleft rect"></div>
+ </div>
+ </div>
+ <div>
+ <div class="wrapper blockmargin">
+ <div class="rect blockmargin"></div>
+ </div>
+ </div>
+ </div>
+
+ <div id="layout">
+ <div class="wrapper">
+ <div class="absolute_pos"></div>
+ <div class="fixed_pos"></div>
+ </div>
+ <div class="flex">
+ <div class="rect"></div>
+ <div class="wrapper rect">X</div>
+ </div>
+ <div>
+ <div class="floatleft rect"></div>
+ <div class="wrapper">
+ <div class="clearleft rect"></div>
+ </div>
+ </div>
+ <div>
+ <div class="wrapper blockmargin">
+ <div class="rect blockmargin"></div>
+ </div>
+ </div>
+ </div>
+
+ <div id="none_to_layout">
+ <div class="wrapper">
+ <div class="absolute_pos"></div>
+ <div class="fixed_pos"></div>
+ </div>
+ <div class="flex">
+ <div class="rect"></div>
+ <div class="wrapper rect">X</div>
+ </div>
+ <div>
+ <div class="floatleft rect"></div>
+ <div class="wrapper">
+ <div class="clearleft rect"></div>
+ </div>
+ </div>
+ <div>
+ <div class="wrapper blockmargin">
+ <div class="rect blockmargin"></div>
+ </div>
+ </div>
+ </div>
+
+ <div id="layout_to_none">
+ <div class="wrapper">
+ <div class="absolute_pos"></div>
+ <div class="fixed_pos"></div>
+ </div>
+ <div class="flex">
+ <div class="rect"></div>
+ <div class="wrapper rect">X</div>
+ </div>
+ <div>
+ <div class="floatleft rect"></div>
+ <div class="wrapper">
+ <div class="clearleft rect"></div>
+ </div>
+ </div>
+ <div>
+ <div class="wrapper blockmargin">
+ <div class="rect blockmargin"></div>
+ </div>
+ </div>
+ </div>
+
+ <script>
+ function verifyLayoutContainment(id, applied) {
+ let container = document.getElementById(id);
+ let wrappers = container.getElementsByClassName("wrapper");
+
+ // To verify the containment box establishes an absolute positioning
+ // containing block and a fixed positioning containing block, we test
+ // positions of absolutely/fixed positioned children (a bit below the
+ // containment box rather than a bit below the top of the viewport).
+ let containingBlockTop = wrappers[0].getBoundingClientRect().top;
+ let absTop = container.getElementsByClassName("absolute_pos")[0]
+ .getBoundingClientRect().top;
+ assert_equals(absTop > containingBlockTop, applied, "absolute positioning containing block");
+ let fixedTop = container.getElementsByClassName("fixed_pos")[0]
+ .getBoundingClientRect().top;
+ assert_equals(fixedTop > containingBlockTop, applied, "fixed positioning containing block");
+
+ // To verify the containment box suppresses baseline, we verify that
+ // the two items in the flex container are properly aligned.
+ let item1 = wrappers[1];
+ let item2 = item1.previousElementSibling;
+ let aligned = Math.abs(item1.getBoundingClientRect().top - item2.getBoundingClientRect().top) <= 1;
+ assert_equals(aligned, applied, "vertical baseline suppressed");
+
+ // To verify the containment box establishes an independent formatting
+ // context, we test position the clear: left div with respect to the
+ // float: left div.
+ let floatLeft = wrappers[2].previousElementSibling;
+ let clearLeft = wrappers[2].firstElementChild;
+ let clearNextToFloat = Math.abs(floatLeft.getBoundingClientRect().top - clearLeft.getBoundingClientRect().top) <= 1;
+ assert_equals(clearNextToFloat, applied, "independent formatting context (floats)");
+
+ // In addition, we verify that the margin inside the containment box
+ // are not collapsed.
+ let IFCWithMargin = wrappers[3];
+ let childWithMargin = IFCWithMargin.firstElementChild;
+ let marginCollapsed = Math.abs(IFCWithMargin.getBoundingClientRect().height - childWithMargin.getBoundingClientRect().height) <= 1;
+ assert_equals(!marginCollapsed, applied, "independent formatting context (margins collapsing)");
+ }
+
+ function setContain(id, value) {
+ let container = document.getElementById(id);
+ Array.from(container.getElementsByClassName("wrapper"))
+ .forEach(element => element.style.contain = value);
+ }
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ verifyLayoutContainment("none", /* applied=*/false);
+ }, "contain: none");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ verifyLayoutContainment("layout", /* applied=*/true);
+ }, "contain: layout");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ setContain("none_to_layout", "layout");
+ verifyLayoutContainment("none_to_layout", /* applied=*/true)
+ }, "switching contain from none to layout");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ setContain("layout_to_none", "none");
+ verifyLayoutContainment("layout_to_none", /* applied=*/false);
+ }, "switching contain from layout to none");
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-dynamic-004-ref.html b/testing/web-platform/tests/css/css-contain/contain-layout-dynamic-004-ref.html
new file mode 100644
index 0000000000..40923d836c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-dynamic-004-ref.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<title>Dynamic change to layout containment (reference)</title>
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+
+<style>
+ div {
+ font: 25px/1 Ahem;
+ }
+ #wrapper {
+ width: 15em;
+ background: lightgray;
+ }
+ .containment {
+ contain: layout;
+ }
+ .float {
+ box-sizing: border-box;
+ border: 1px solid black;
+ }
+ .left {
+ float: left;
+ width: 1em;
+ height: 2em;
+ }
+ .right {
+ float: right;
+ width: 1em;
+ height: 3em;
+ }
+</style>
+
+<body>
+ <p>PASS if the boxes with dark colors are NOT floating next to the boxes with
+ light colors.</p>
+ <div id="wrapper">
+ <div>
+ <div id="container" class="containment">
+ <div><div class="float left" style="background: lightblue"></div></div>
+ <div class="float right" style="background: lightyellow"></div>
+ <div>XX XXX XXXX X</div>
+ </div>
+ <div class="float left" style="background: blue"></div>
+ <div>
+ <div>
+ <div><div class="float right" style="background: yellow"></div></div>
+ <div>XXX XXXXXX XXXX XX XX</div>
+ </div>
+ <div>XXXX XXXXX XX</div>
+ </div>
+ <div>XXX XXX XX XXXX</div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-dynamic-004.html b/testing/web-platform/tests/css/css-contain/contain-layout-dynamic-004.html
new file mode 100644
index 0000000000..d3c9eb6860
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-dynamic-004.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>Dynamic change to layout containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1874826">
+<meta name="assert" content="Verify floats are properly displayed after dynamic change to layout containment.">
+<link rel="match" href="contain-layout-dynamic-004-ref.html">
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+
+<style>
+ div {
+ font: 25px/1 Ahem;
+ }
+ #wrapper {
+ width: 15em;
+ background: lightgray;
+ }
+ .containment {
+ contain: layout;
+ }
+ .float {
+ box-sizing: border-box;
+ border: 1px solid black;
+ }
+ .left {
+ float: left;
+ width: 1em;
+ height: 2em;
+ }
+ .right {
+ float: right;
+ width: 1em;
+ height: 3em;
+ }
+</style>
+
+<body>
+ <p>PASS if the boxes with dark colors are NOT floating next to the boxes with
+ light colors.</p>
+ <div id="wrapper">
+ <div>
+ <div id="container">
+ <div><div class="float left" style="background: lightblue"></div></div>
+ <div class="float right" style="background: lightyellow"></div>
+ <div>XX XXX XXXX X</div>
+ </div>
+ <div class="float left" style="background: blue"></div>
+ <div>
+ <div>
+ <div><div class="float right" style="background: yellow"></div></div>
+ <div>XXX XXXXXX XXXX XX XX</div>
+ </div>
+ <div>XXXX XXXXX XX</div>
+ </div>
+ <div>XXX XXX XX XXXX</div>
+ </div>
+ </div>
+ <script>
+ window.addEventListener("load", async () => {
+ container.classList.add('containment');
+ await waitForAtLeastOneFrame();
+ takeScreenshot();
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-dynamic-005-ref.html b/testing/web-platform/tests/css/css-contain/contain-layout-dynamic-005-ref.html
new file mode 100644
index 0000000000..3c2e6cf2e4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-dynamic-005-ref.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<title>Dynamic change to layout containment (reference)</title>
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+
+<style>
+ div {
+ font: 25px/1 Ahem;
+ }
+ #wrapper {
+ width: 15em;
+ background: lightgray;
+ }
+ .containment {
+ contain: layout;
+ }
+ .float {
+ box-sizing: border-box;
+ border: 1px solid black;
+ }
+ .left {
+ float: left;
+ width: 1em;
+ height: 2em;
+ }
+ .right {
+ float: right;
+ width: 1em;
+ height: 3em;
+ }
+</style>
+
+<body>
+ <p>PASS if the boxes with dark colors are floating next to the boxes with
+ light colors.</p>
+ <div id="wrapper">
+ <div>
+ <div id="container">
+ <div><div class="float left" style="background: lightblue"></div></div>
+ <div class="float right" style="background: lightyellow"></div>
+ <div>XX XXX XXXX X</div>
+ </div>
+ <div class="float left" style="background: blue"></div>
+ <div>
+ <div>
+ <div><div class="float right" style="background: yellow"></div></div>
+ <div>XXX XXXXXX XXXX XX XX</div>
+ </div>
+ <div>XXXX XXXXX XX</div>
+ </div>
+ <div>XXX XXX XX XXXX</div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-dynamic-005.html b/testing/web-platform/tests/css/css-contain/contain-layout-dynamic-005.html
new file mode 100644
index 0000000000..a430ae5181
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-dynamic-005.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>Dynamic change to layout containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1874826">
+<meta name="assert" content="Verify floats are properly displayed after dynamic change to layout containment.">
+<link rel="match" href="contain-layout-dynamic-005-ref.html">
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+
+<style>
+ div {
+ font: 25px/1 Ahem;
+ }
+ #wrapper {
+ width: 15em;
+ background: lightgray;
+ }
+ .containment {
+ contain: layout;
+ }
+ .float {
+ box-sizing: border-box;
+ border: 1px solid black;
+ }
+ .left {
+ float: left;
+ width: 1em;
+ height: 2em;
+ }
+ .right {
+ float: right;
+ width: 1em;
+ height: 3em;
+ }
+</style>
+
+<body>
+ <p>PASS if the boxes with dark colors are floating next to the boxes with
+ light colors.</p>
+ <div id="wrapper">
+ <div>
+ <div id="container" class="containment">
+ <div><div class="float left" style="background: lightblue"></div></div>
+ <div class="float right" style="background: lightyellow"></div>
+ <div>XX XXX XXXX X</div>
+ </div>
+ <div class="float left" style="background: blue"></div>
+ <div>
+ <div>
+ <div><div class="float right" style="background: yellow"></div></div>
+ <div>XXX XXXXXX XXXX XX XX</div>
+ </div>
+ <div>XXXX XXXXX XX</div>
+ </div>
+ <div>XXX XXX XX XXXX</div>
+ </div>
+ </div>
+ <script>
+ window.addEventListener("load", async () => {
+ container.classList.remove('containment');
+ await waitForAtLeastOneFrame();
+ takeScreenshot();
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-flexbox-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-flexbox-001.html
new file mode 100644
index 0000000000..2b206edb57
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-flexbox-001.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment on flexbox container</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="reference/contain-layout-flexbox-001-ref.html">
+<meta name=assert content="Layout containment does apply to flexbox containers, thus their baseline is the same than if they don't have contents.">
+<style>
+div {
+ display: inline-flex;
+ border: 5px solid green;
+ contain: layout;
+ color: transparent;
+ width: 0;
+ height: 0;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the bottom, and then the word "after".</p>
+before<div>f</div>after
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-formatting-context-float-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-formatting-context-float-001.html
new file mode 100644
index 0000000000..3486f63999
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-formatting-context-float-001.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: layout' should contain floats as a formatting context.</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-layout">
+ <link rel="match" href="contain-paint-formatting-context-float-001-ref.html">
+ <style>
+ #left {
+ float: left;
+ height: 50px;
+ width: 10px;
+ background: blue;
+ }
+ #a {
+ contain: layout;
+ background: red;
+ margin: 10px;
+ width: 50px;
+ height: 50px;
+ }
+ #b {
+ clear: left;
+ width: 50px;
+ height: 50px;
+ background: green;
+ }
+ </style>
+</head>
+<body>
+ <div id="left"></div>
+ <div id="a">
+ <div id="b"></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-formatting-context-margin-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-layout-formatting-context-margin-001-ref.html
new file mode 100644
index 0000000000..5a6d653862
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-formatting-context-margin-001-ref.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Test</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ #a {
+ background: blue;
+ margin: 10px;
+ width: 50px;
+ height: 50px;
+ }
+ #b {
+ width: 50px;
+ height: 40px;
+ background: green;
+ }
+ #b-padding {
+ height: 10px;
+ }
+ #c {
+ width: 50px;
+ height: 10px;
+ background: lightblue;
+ }
+ </style>
+</head>
+<body>
+ <div id="a">
+ <div id="b-padding"></div>
+ <div id="b"></div>
+ <div id="c"></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-formatting-context-margin-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-formatting-context-margin-001.html
new file mode 100644
index 0000000000..3b8f9caa75
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-formatting-context-margin-001.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: layout' with a vertical margin child. Margin collapse should not occur, and neither should overflow clipping.</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-layout">
+ <link rel="match" href="contain-layout-formatting-context-margin-001-ref.html">
+ <style>
+ #a {
+ contain:layout;
+ background: blue;
+ margin: 10px;
+ width: 50px;
+ height: 50px;
+ }
+ #b {
+ width: 50px;
+ height: 40px;
+ background: green;
+ margin-top: 10px;
+ }
+ #c {
+ background: lightblue;
+ width: 50px;
+ height: 10px;
+ }
+ </style>
+</head>
+<body>
+ <div id="a">
+ <div id="b"></div>
+ <div id="c"></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-grid-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-grid-001.html
new file mode 100644
index 0000000000..a6bcc4dbc2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-grid-001.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment on grid container</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="reference/contain-layout-grid-001-ref.html">
+<meta name=assert content="Layout containment does apply to grid containers, thus their baseline is the same than if they don't have contents.">
+<style>
+div {
+ display: inline-grid;
+ border: 5px solid green;
+ contain: layout;
+ color: transparent;
+ width: 0;
+ height: 0;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the bottom, and then the word "after".</p>
+before<div>g</div>after
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-ifc-022.html b/testing/web-platform/tests/css/css-contain/contain-layout-ifc-022.html
new file mode 100644
index 0000000000..1b66fe347e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-ifc-022.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: layout' and creation of an independent formating context: text no longer flowing around a float</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+ <link rel="match" href="reference/contain-layout-ifc-022-ref.html">
+
+ <meta content="This test checks that an element with 'contain: layout' will make such element create its own formatting context. In this test, the element with 'contain: layout' acts as if it has its own formatting context independent from div#floated-left element. In other words, the div#with-contain-layout is no longer required to flow its content around the div#floated-left element and current line boxes next to the float are no longer shortened to make room for the margin box of the float." name="assert">
+
+ <style>
+ div
+ {
+ color: transparent;
+ font-size: 16px;
+ padding: 8px;
+ }
+
+ div#floated-left
+ {
+ background-color: blue;
+ float: left;
+ margin: 8px;
+ width: 6em;
+ }
+
+ div#with-contain-layout
+ {
+ background-color: orange;
+ contain: layout;
+ width: 12em;
+ }
+ </style>
+
+ <p>Test passes if the orange rectangle and blue rectangle do not overlap.
+
+ <!--
+
+ or
+
+ <p>Test passes if the orange rectangle and blue rectangle are side by side.
+
+ or
+
+ <p>Test passes if the orange rectangle and blue rectangle are apart from each other.
+
+ -->
+
+ <div id="floated-left">Some text in a blue rectangle.</div>
+
+ <div id="with-contain-layout">Some text in an orange rectangle. Some text in an orange rectangle. Some text in an orange rectangle.</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-ib-split-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-ib-split-001-ref.html
new file mode 100644
index 0000000000..eb787424ed
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-ib-split-001-ref.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <style>
+ .abspos-box {
+ position: absolute;
+ width: 200px;
+ height: 200px;
+ }
+
+ /* The boxes should stack in the order that I've listed their CSS classes
+ here. The class names' first word (outside/before/inside/after) refers
+ to the boxes' DOM position, and "background"/"midground"/"foreground"
+ refers to their z-index values. */
+
+ .before-IB-background {
+ background: darkmagenta;
+ z-index: -1;
+ top: 50px;
+ left: 50px;
+ }
+ .after-IB-background {
+ background: magenta;
+ z-index: -1;
+ top: 70px;
+ left: 70px;
+ }
+ .outside-span-midground {
+ background: darkkhaki;
+ top: 90px;
+ left: 90px;
+ }
+ .inside-IB-midground {
+ background: khaki;
+ top: 110px;
+ left: 110px;
+ }
+ .before-IB-foreground {
+ background: darkcyan;
+ z-index: 1;
+ top: 130px;
+ left: 130px;
+ }
+ .after-IB-foreground {
+ background: cyan;
+ z-index: 1;
+ top: 150px;
+ left: 150px;
+ }
+ </style>
+</head>
+<body>
+ <!-- The expectation here is that 'abspos-box' elements will all interact in
+ the same top-level stacking context. That means the box ordering should
+ be (back to front): darkmagenta/magenta/darkkhaki/khaki/darkcyan/cyan,
+ with the boxes stacked (visually) from top-left to bottom-right. -->
+
+ <div class="abspos-box outside-span-midground"></div>
+
+ <!-- Note: this file is identical to the testcase,
+ except for the lack of "contain: layout" on this span. -->
+ <span>
+ <div class="abspos-box before-IB-background"></div>
+ <div class="abspos-box before-IB-foreground"></div>
+ <!-- This unstyled div crates the IB split: -->
+ <div>
+ <div class="abspos-box inside-IB-midground"></div>
+ </div>
+ <div class="abspos-box after-IB-background"></div>
+ <div class="abspos-box after-IB-foreground"></div>
+ </span>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-ib-split-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-ib-split-001.html
new file mode 100644
index 0000000000..d9f976deb8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-ib-split-001.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: layout' should have no effect on non-atomic inline
+ (including its block part, if there's a block-in-inline split)</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-layout">
+ <link rel="match" href="contain-layout-ignored-cases-ib-split-001-ref.html">
+ <style>
+ .abspos-box {
+ position: absolute;
+ width: 200px;
+ height: 200px;
+ }
+
+ /* The boxes should stack in the order that I've listed their CSS classes
+ here. The class names' first word (outside/before/inside/after) refers
+ to the boxes' DOM position, and "background"/"midground"/"foreground"
+ refers to their z-index values. */
+
+ .before-IB-background {
+ background: darkmagenta;
+ z-index: -1;
+ top: 50px;
+ left: 50px;
+ }
+ .after-IB-background {
+ background: magenta;
+ z-index: -1;
+ top: 70px;
+ left: 70px;
+ }
+ .outside-span-midground {
+ background: darkkhaki;
+ top: 90px;
+ left: 90px;
+ }
+ .inside-IB-midground {
+ background: khaki;
+ top: 110px;
+ left: 110px;
+ }
+ .before-IB-foreground {
+ background: darkcyan;
+ z-index: 1;
+ top: 130px;
+ left: 130px;
+ }
+ .after-IB-foreground {
+ background: cyan;
+ z-index: 1;
+ top: 150px;
+ left: 150px;
+ }
+ </style>
+</head>
+<body>
+ <!-- The expectation here is that 'abspos-box' elements will all interact in
+ the same top-level stacking context. That means the box ordering should
+ be (back to front): darkmagenta/magenta/darkkhaki/khaki/darkcyan/cyan,
+ with the boxes stacked (visually) from top-left to bottom-right. -->
+
+ <div class="abspos-box outside-span-midground"></div>
+
+ <span style="contain: layout">
+ <div class="abspos-box before-IB-background"></div>
+ <div class="abspos-box before-IB-foreground"></div>
+ <!-- This unstyled div crates the IB split: -->
+ <div>
+ <div class="abspos-box inside-IB-midground"></div>
+ </div>
+ <div class="abspos-box after-IB-background"></div>
+ <div class="abspos-box after-IB-foreground"></div>
+ </span>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-001.html
new file mode 100644
index 0000000000..bd2f4cb817
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-001.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: layout' should not create a stacking context when no principle box is generated.</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-layout">
+ <link rel="match" href="contain-paint-ignored-cases-no-principal-box-001-ref.html">
+ <style>
+ div {
+ position: relative;
+ width: 100px;
+ }
+ #div1,
+ #div3 {
+ background-color: #cfc;
+ height: 100px;
+ }
+ #div1 {
+ z-index: 5;
+ }
+ #div2 {
+ display: contents;
+ contain: layout;
+ background-color: #fdd;
+ height: 100px;
+ top: -20px;
+ }
+ #div2_1 {
+ background-color: #ffc;
+ z-index: 6;
+ top: -10px;
+ height: 100px;
+ }
+ #div2_2 {
+ z-index: 3;
+ position: absolute;
+ top: -15px;
+ width: 40px;
+ height: 300px;
+ background-color: #ddf;
+ }
+ #div3 {
+ z-index: 2;
+ top: -50px;
+ }
+ </style>
+</head>
+<body>
+ <div id="div1"></div>
+
+ <div id="div2">
+ <div id="div2_1"></div>
+
+ <div id="div2_2"></div>
+ </div>
+
+ <div id="div3"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-002-ref.html b/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-002-ref.html
new file mode 100644
index 0000000000..44cd7c109e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-002-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ #a {
+ display: contents;
+ width: 100px;
+ height: 100px;
+ background: green;
+ margin: 50px;
+ }
+ #b {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ </style>
+</head>
+<body>
+ <div id="a">
+ <div>
+ <div id="b"></div>
+ </div>
+ </div>
+</body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-002.html b/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-002.html
new file mode 100644
index 0000000000..de2edfb58f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-002.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: layout' element should not contain absolute/fixed position elements when no principal box is generated.</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+ <link rel="match" href="contain-layout-ignored-cases-no-principal-box-002-ref.html">
+ <style>
+ #a {
+ contain: layout;
+ display: contents;
+ width: 100px;
+ height: 100px;
+ background: red;
+ margin: 50px;
+ }
+ #b {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ </style>
+</head>
+<body>
+ <div id="a">
+ <div>
+ <div id="b"></div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-003-ref.html b/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-003-ref.html
new file mode 100644
index 0000000000..46f028c058
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-003-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ #a {
+ display: contents;
+ width: 100px;
+ height: 100px;
+ background: red;
+ margin: 50px;
+ }
+ #b {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ </style>
+</head>
+<body>
+ <div id="a">
+ <div>
+ <div id="b"></div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-003.html b/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-003.html
new file mode 100644
index 0000000000..d40a021156
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-ignored-cases-no-principal-box-003.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: layout' element should not contain absolute/fixed position elements when no principal box is generated.</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+ <link rel="match" href="contain-layout-ignored-cases-no-principal-box-003-ref.html">
+ <style>
+ #a {
+ contain: layout;
+ display: contents;
+ width: 100px;
+ height: 100px;
+ background: red;
+ margin: 50px;
+ }
+ #b {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ </style>
+</head>
+<body>
+ <div id="a">
+ <div>
+ <div id="b"></div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-independent-formatting-context-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-independent-formatting-context-001.html
new file mode 100644
index 0000000000..94c88bc49c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-independent-formatting-context-001.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment independent formatting context</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="reference/contain-paint-independent-formatting-context-001-ref.html">
+<meta name=assert content="Layout containment elements establish an independent formatting context. The test checks that this feature of layout containment applies to blocks.">
+<style>
+.wrapper {
+ border: solid thick;
+ margin: 1em;
+}
+</style>
+<p>Test passes if it has the same output than the reference.</p>
+<div class="wrapper">
+ <div style="margin: 1em 0; contain: layout;">
+ <div style="margin: 1em 0;">This text should have 2em top and bottom margins (margins do not collapse).</div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-independent-formatting-context-002.html b/testing/web-platform/tests/css/css-contain/contain-layout-independent-formatting-context-002.html
new file mode 100644
index 0000000000..8491e3d28f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-independent-formatting-context-002.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment independent formatting context</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="reference/contain-paint-independent-formatting-context-001-ref.html">
+<meta name=assert content="Layout containment elements establish an independent formatting context. The test checks that this feature of layout containment applies to inline blocks.">
+<style>
+.wrapper {
+ border: solid thick;
+ margin: 1em;
+}
+</style>
+<p>Test passes if it has the same output than the reference.</p>
+<div class="wrapper">
+ <span style="display: inline-block; margin: 1em 0; vertical-align: top; contain: layout;">
+ <div style="margin: 1em 0;">This text should have 2em top and bottom margins (margins do not collapse).</div>
+ </span>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-independent-formatting-context-003.html b/testing/web-platform/tests/css/css-contain/contain-layout-independent-formatting-context-003.html
new file mode 100644
index 0000000000..a10afd3cde
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-independent-formatting-context-003.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment independent formatting context</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="reference/contain-paint-independent-formatting-context-003-ref.html">
+<meta name=assert content="Layout containment elements establish an independent formatting context. The test checks that this feature of paint containment does not appliy to inline elements.">
+<style>
+.wrapper {
+ border: solid thick;
+ margin: 1em;
+}
+</style>
+<p>Test passes if it has the same output than the reference.</p>
+<div class="wrapper">
+ <span style="margin: 1em 0; contain: layout;">
+ <div style="margin: 1em 0;">This text should have 1em top and bottom margins.</div>
+ </span>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-013.html b/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-013.html
new file mode 100644
index 0000000000..ca11f42087
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-013.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: layout' and ink overflow</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+ <link rel="match" href="reference/contain-layout-ink-overflow-013-ref.html">
+
+ <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its contents must be treated as ink overflow. In this test, the content overflows the div#inner. If such content was treated as 'overflow: visible', then the div#outer would 'pick up' such content and would make it reachable and accessible via its own generated scrollbar. But the overflowed content must be treated as ink overflow and is therefore treated as a graphical effect that is beyond the scrolling mechanism and outside the scrolling mechanism." name="assert">
+
+ <style>
+ div#outer
+ {
+ font-family: monospace;
+ font-size: 100px;
+ height: 3em;
+ line-height: 1.5; /* computes to 150px */
+ width: 4ch;
+
+ overflow: scroll;
+ }
+
+ div#inner
+ {
+ color: red;
+ contain: layout;
+ width: 0;
+ }
+ </style>
+
+ <body onload="document.getElementById('outer').scrollLeft = 4000;">
+
+ <p>Test passes if there is no red.
+
+ <div id="outer">
+ <div id="inner">&nbsp;&nbsp;&nbsp;&nbsp;FAIL</div>
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-014.html b/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-014.html
new file mode 100644
index 0000000000..cbb752d625
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-014.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: layout' and ink overflow</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+ <link rel="match" href="reference/contain-layout-ink-overflow-014-ref.html">
+
+ <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its contents must be treated as ink overflow. In this test, the content overflows the div#inner. If such content was treated as 'overflow: visible', then the div#outer would 'pick up' such content and would make it reachable and accessible via its own generated scrollbar. But the overflowed content must be treated as ink overflow and is therefore treated as a graphical effect that is beyond the scrolling mechanism and outside the scrolling mechanism." name="assert">
+
+ <style>
+ div#outer
+ {
+ font-family: monospace;
+ font-size: 100px;
+ height: 2.8ch;
+ line-height: 1.5; /* computes to 150px */
+ width: 4ch;
+
+ overflow: scroll;
+ }
+
+ div#inner
+ {
+ color: red;
+ contain: layout;
+ height: 0;
+ }
+ </style>
+
+ <!--
+
+ 150px : height of 1 line box
+
+ -->
+
+ <body onload="document.getElementById('outer').scrollLeft = 250; document.getElementById('outer').scrollTop = 150;">
+
+ <p>Test passes if there is no red.
+
+ <div id="outer">
+ <div id="inner">&nbsp;<br>FAIL</div>
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-015.html b/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-015.html
new file mode 100644
index 0000000000..0eaaf9ab43
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-015.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: layout' and ink overflow</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+ <link rel="match" href="reference/contain-layout-ink-overflow-015-ref.html">
+
+ <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its contents must be treated as ink overflow. In this test, the content overflows the div#inner. If such content was treated as 'overflow: visible', then the div#outer would 'pick up' such content and would make it reachable and accessible via its own generated scrollbar. But the overflowed content must be treated as ink overflow and is therefore treated as a graphical effect that is beyond the scrolling mechanism and outside the scrolling mechanism." name="assert">
+
+ <style>
+ div#outer
+ {
+ font-family: monospace;
+ font-size: 100px;
+ height: 2.8ch;
+ line-height: 1.5; /* computes to 150px */
+ width: 4ch;
+
+ overflow: auto;
+ }
+
+ div#inner
+ {
+ color: red;
+ contain: layout;
+ width: 0;
+ }
+ </style>
+
+ <body onload="document.getElementById('outer').scrollLeft = 4000;">
+
+ <p>Test passes if there is no red.
+
+ <div id="outer">
+ <div id="inner">&nbsp;&nbsp;&nbsp;&nbsp;FAIL</div>
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-016.html b/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-016.html
new file mode 100644
index 0000000000..e4ade9d7a4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-016.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: layout' and ink overflow</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+ <link rel="match" href="reference/contain-layout-ink-overflow-015-ref.html">
+
+ <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its contents must be treated as ink overflow. In this test, the content overflows the div#inner. If such content was treated as 'overflow: visible', then the div#outer would 'pick up' such content and would make it reachable and accessible via its own generated scrollbar. But the overflowed content must be treated as ink overflow and is therefore treated as a graphical effect that is beyond the scrolling mechanism and outside the scrolling mechanism." name="assert">
+
+ <style>
+ div#outer
+ {
+ font-family: monospace;
+ font-size: 100px;
+ height: 2.8ch;
+ line-height: 1.5; /* computes to 150px */
+ width: 4ch;
+
+ overflow: auto;
+ }
+
+ div#inner
+ {
+ color: red;
+ contain: layout;
+ height: 0;
+ }
+ </style>
+
+ <!--
+
+ 150px : height of 1 line box
+
+ -->
+
+ <body onload="document.getElementById('outer').scrollLeft = 250; document.getElementById('outer').scrollTop = 150;">
+
+ <p>Test passes if there is no red.
+
+ <div id="outer">
+ <div id="inner">&nbsp;<br>FAIL</div>
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-017.html b/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-017.html
new file mode 100644
index 0000000000..d6b6f83b3a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-017.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: layout' and ink overflow</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+ <link rel="match" href="reference/contain-layout-ink-overflow-014-ref.html">
+
+ <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its contents must be treated as ink overflow. In this test, the content overflows the div#inner. If such content was treated as 'overflow: visible', then the div#outer would 'pick up' such content and would make it reachable and accessible via its own generated scrollbar. But the overflowed content must be treated as ink overflow and is therefore treated as a graphical effect that is beyond the scrolling mechanism and outside the scrolling mechanism." name="assert">
+
+ <style>
+ div#outer
+ {
+ font-family: monospace;
+ font-size: 100px;
+ height: 2.8ch;
+ line-height: 1.5; /* computes to 150px */
+ width: 4ch;
+
+ overflow: scroll;
+ }
+
+ div#inner
+ {
+ color: red;
+ contain: layout;
+ height: 0;
+ width: 0;
+ }
+ </style>
+
+ <!--
+
+ 150px : height of 1 line box
+
+ -->
+
+ <body onload="document.getElementById('outer').scrollLeft = 4000; document.getElementById('outer').scrollTop = 150;">
+
+ <p>Test passes if there is no red.
+
+ <div id="outer">
+ <div id="inner"><br>FAIL</div>
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-018.html b/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-018.html
new file mode 100644
index 0000000000..bf00128bbb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-018.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: layout' and ink overflow</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+ <link rel="match" href="reference/contain-layout-ink-overflow-015-ref.html">
+
+ <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its contents must be treated as ink overflow. In this test, the content overflows the div#inner. If such content was treated as 'overflow: visible', then the div#outer would 'pick up' such content and would make it reachable and accessible via its own generated scrollbar. But the overflowed content must be treated as ink overflow and is therefore treated as a graphical effect that is beyond the scrolling mechanism and outside the scrolling mechanism." name="assert">
+
+ <style>
+ div#outer
+ {
+ font-family: monospace;
+ font-size: 100px;
+ height: 2.8ch;
+ line-height: 1.5; /* computes to 150px */
+ width: 4ch;
+
+ overflow: auto;
+ }
+
+ div#inner
+ {
+ color: red;
+ contain: layout;
+ height: 0;
+ width: 0;
+ }
+ </style>
+
+ <!--
+
+ 150px : height of 1 line box
+
+ -->
+
+ <body onload="document.getElementById('outer').scrollLeft = 4000; document.getElementById('outer').scrollTop = 150;">
+
+ <p>Test passes if there is no red.
+
+ <div id="outer">
+ <div id="inner"><br>FAIL</div>
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-019.html b/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-019.html
new file mode 100644
index 0000000000..d4909aa70f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-019.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Test: 'contain: layout' on element that overflows and its parent has 'overflow: scroll'</title>
+
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+ <link rel="match" href="reference/contain-layout-ink-overflow-019-ref.html">
+
+ <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its overflowing content must be treated as ink overflow. Such overflowing content therefore can not be reached and can not be accessed by the scrollbars or by the scrolling mechanism of the parent of such element. In this test, the parent has 'overflow: scroll'." name="assert">
+
+ <style>
+ div
+ {
+ height: 100px;
+ width: 100px;
+ }
+
+ /* this means that each and all 4 div's use the same definite height and width */
+
+ div#parent-with-overflow-scroll
+ {
+ overflow: scroll;
+ }
+
+ div#contain
+ {
+ contain: layout;
+ }
+
+ div#pass
+ {
+ background-color: green;
+ }
+
+ div#fail
+ {
+ background-color: red;
+ }
+ </style>
+
+ <!--
+
+ 25px : height of a very tall horizontal scrollbar
+ +
+ 100px : height of div#fail
+ =======
+ 125px
+
+ -->
+
+ <body onload="document.getElementById('parent-with-overflow-scroll').scrollLeft = 100; document.getElementById('parent-with-overflow-scroll').scrollTop = 125;">
+
+ <p>Test passes if there is a filled green square <strong>with 2 scroll bars</strong> and if there is <strong>no red</strong>.
+
+ <div id="parent-with-overflow-scroll">
+
+ <div id="contain">
+
+ <div id="pass"></div>
+
+ <div id="fail"></div>
+
+ </div>
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-020.html b/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-020.html
new file mode 100644
index 0000000000..2ed9062eb4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-ink-overflow-020.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Test: 'contain: layout' on element that overflows and its parent has 'overflow: auto'</title>
+
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+ <link rel="match" href="reference/contain-layout-ink-overflow-020-ref.html">
+
+ <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its overflowing content must be treated as ink overflow. Such overflowing content therefore can not be reached and can not be accessed by the scrollbars or by the scrolling mechanism of the parent of such element. In this test, the parent has 'overflow: auto' and therefore will not create scrollbars or a scrolling mechanism because the ink overflow is not a scrollable region for the parent." name="assert">
+
+ <style>
+ div
+ {
+ height: 100px;
+ width: 100px;
+ }
+
+ /* this means that each and all 4 div's use the same definite height and width */
+
+ div#parent-with-overflow-auto
+ {
+ overflow: auto;
+ }
+
+ div#contain
+ {
+ contain: layout;
+ }
+
+ div#pass
+ {
+ background-color: green;
+ }
+
+ div#fail
+ {
+ background-color: red;
+ }
+ </style>
+
+ <!--
+
+ 25px : height of a very tall horizontal scrollbar
+ +
+ 100px : height of div#fail
+ =======
+ 125px
+
+ -->
+
+ <body onload="document.getElementById('parent-with-overflow-auto').scrollLeft = 100; document.getElementById('parent-with-overflow-auto').scrollTop = 125;">
+
+ <p>Test passes if there is a filled green square, <strong>no scrollbar around it</strong> and <strong>no red</strong>.
+
+ <div id="parent-with-overflow-auto">
+
+ <div id="contain">
+
+ <div id="pass"></div>
+
+ <div id="fail"></div>
+
+ </div>
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-overflow-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-layout-overflow-001-ref.html
new file mode 100644
index 0000000000..61825fd454
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-overflow-001-ref.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .outer {
+ height: 100px;
+ width: 100px;
+ }
+ .auto {
+ overflow: auto;
+ }
+ .inner-sm {
+ height: 50px;
+ width: 50px;
+ background: lightblue;
+ }
+ .inner-lg-1 {
+ height: 95px;
+ width: 95px;
+ background: lightblue;
+ }
+ .inner-lg-2 {
+ height: 200px;
+ width: 200px;
+ }
+ .pass {
+ background: green;
+ }
+ .border {
+ border: 5px solid green;
+ }
+
+ </style>
+</head>
+<body>
+ <div class="outer">
+ <div class="inner-sm"></div>
+ </div>
+ <br>
+
+ <div class="outer auto">
+ <div class="inner-lg-2 pass">
+ </div>
+ </div>
+ <br>
+
+ <div class="inner-sm border">
+ <div class="inner-lg-1">
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-overflow-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-overflow-001.html
new file mode 100644
index 0000000000..5bf984e2bf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-overflow-001.html
@@ -0,0 +1,66 @@
+
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: layout' should force all overflow to be ink overflow.</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-layout">
+ <link rel="match" href="contain-layout-overflow-001-ref.html">
+ <style>
+ .contain {
+ contain: layout;
+ }
+ .outer {
+ height: 100px;
+ width: 100px;
+ }
+ .auto {
+ overflow: auto;
+ }
+ .inner-sm {
+ height: 50px;
+ width: 50px;
+ background: lightblue;
+ }
+ .inner-lg {
+ height: 200px;
+ width: 200px;
+ background: lightblue;
+ }
+ .pass {
+ background: green;
+ }
+ .fail {
+ background: red;
+ }
+ .border {
+ border: 5px solid green;
+ }
+ </style>
+</head>
+<body>
+ <!--CSS Test: Elements with contain:layout that do not produce scrollable overflow should paint as if containment were not applied. -->
+ <div class="outer">
+ <div class="inner-sm contain"></div>
+ </div>
+ <br>
+
+ <!--CSS Test: Layout-contained elements that overflow their container and have children who overflow should produce the same amount of scrollable overflow as if there were no children. -->
+ <div class="outer auto">
+ <div class="inner-lg contain">
+ <div class="inner-lg pass"></div>
+ <div class="inner-lg fail"></div>
+ </div>
+ </div>
+ <br>
+
+ <!--CSS Test: Layout-contained elements that do not overflow their container, but have children who overflow, should not allow their children to affect the scrollable overflow regions of their parent. -->
+ <div class="outer auto">
+ <div class="inner-sm contain border">
+ <div class="inner-lg">
+ </div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-overflow-002-ref.html b/testing/web-platform/tests/css/css-contain/contain-layout-overflow-002-ref.html
new file mode 100644
index 0000000000..ba1c600d50
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-overflow-002-ref.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .outer {
+ height: 100px;
+ width: 100px;
+ }
+ .auto {
+ overflow: auto;
+ }
+ .inner-sm {
+ height: 50px;
+ width: 50px;
+ background: lightblue;
+ }
+ .inner-lg-1 {
+ height: 95px;
+ width: 95px;
+ float:left;
+ background: lightblue;
+ }
+ .inner-lg-2 {
+ height: 200px;
+ width: 200px;
+ float:left;
+ }
+ .pass {
+ background: green;
+ }
+ .border {
+ border: 5px solid green;
+ }
+
+ </style>
+</head>
+<body>
+ <div class="outer">
+ <div class="inner-sm" style="float:left;"></div>
+ </div>
+ <br>
+
+ <div class="outer auto">
+ <div class="inner-lg-2 pass">
+ </div>
+ </div>
+ <br>
+
+ <div class="inner-sm border">
+ <div class="inner-lg-1">
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-overflow-002.html b/testing/web-platform/tests/css/css-contain/contain-layout-overflow-002.html
new file mode 100644
index 0000000000..4929dc5d33
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-overflow-002.html
@@ -0,0 +1,67 @@
+
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: layout' should force all overflow to be ink overflow (including when the overflow comes from floated descendants)</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-layout">
+ <link rel="match" href="contain-layout-overflow-002-ref.html">
+ <style>
+ .contain {
+ contain: layout;
+ }
+ .float { float: left; }
+ .outer {
+ height: 100px;
+ width: 100px;
+ }
+ .auto {
+ overflow: auto;
+ }
+ .inner-sm {
+ height: 50px;
+ width: 50px;
+ background: lightblue;
+ }
+ .inner-lg {
+ height: 200px;
+ width: 200px;
+ background: lightblue;
+ }
+ .pass {
+ background: green;
+ }
+ .fail {
+ background: red;
+ }
+ .border {
+ border: 5px solid green;
+ }
+ </style>
+</head>
+<body>
+ <!--CSS Test: Elements with contain:layout that do not produce scrollable overflow should paint as if containment were not applied. -->
+ <div class="outer">
+ <div class="inner-sm contain float"></div>
+ </div>
+ <br>
+
+ <!--CSS Test: Layout-contained elements that overflow their container and have children who overflow should produce the same amount of scrollable overflow as if there were no children. -->
+ <div class="outer auto">
+ <div class="inner-lg contain">
+ <div class="inner-lg pass float"></div>
+ <div class="inner-lg fail float"></div>
+ </div>
+ </div>
+ <br>
+
+ <!--CSS Test: Layout-contained elements that do not overflow their container, but have children who overflow, should not allow their children to affect the scrollable overflow regions of their parent. -->
+ <div class="outer auto">
+ <div class="inner-sm contain border">
+ <div class="inner-lg float">
+ </div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-size-003.html b/testing/web-platform/tests/css/css-contain/contain-layout-size-003.html
new file mode 100644
index 0000000000..50b5f0b65c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-size-003.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: a block with 'contain: layout size' alongside a float</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+ <link rel="match" href="reference/contain-layout-size-003-ref.html">
+
+
+ <style>
+ div
+ {
+ color: transparent;
+ font-size: 16px;
+ padding: 8px;
+ }
+
+ div#floated-left
+ {
+ background-color: blue;
+ float: left;
+ margin: 8px;
+ width: 6em;
+ }
+
+ div#with-contain-layout-size
+ {
+ background-color: orange;
+ width: 12em;
+
+ contain: layout size;
+ }
+ </style>
+
+ <p>Test passes if the orange rectangle and blue rectangle do not overlap.
+
+ <div id="floated-left">Some text in a blue rectangle.</div>
+
+ <div id="with-contain-layout-size">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore.</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-stacking-context-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-stacking-context-001.html
new file mode 100644
index 0000000000..4ec3bcee6f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-stacking-context-001.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: layout' with stacking contents. Z-index is defined only for siblings and children.</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css2/visuren.html#x43">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-layout">
+ <link rel="match" href="contain-paint-stacking-context-001-ref.html">
+ <style>
+ div {
+ position: relative;
+ width: 100px;
+ }
+ #div1,
+ #div3 {
+ background-color: #cfc;
+ }
+ #div1 {
+ z-index: 5;
+ }
+ #div2 {
+ contain: layout;
+ background-color: #fdd;
+ height: 100px;
+ top: -20px;
+ }
+ #div2_1 {
+ background-color: #ffc;
+ z-index: 6;
+ top: -10px;
+ }
+ #div2_2 {
+ z-index: 3;
+ position: absolute;
+ top: -15px;
+ width: 40px;
+ height: 100px;
+ background-color: #ddf;
+ }
+ #div3 {
+ z-index: 2;
+ top: -50px;
+ }
+ </style>
+</head>
+<body>
+ <div id="div1">
+ <br/><br/>
+ </div>
+
+ <div id="div2">
+ <div id="div2_1">
+ <br/><br/>
+ </div>
+
+ <div id="div2_2">
+ </div>
+ </div>
+
+ <div id="div3">
+ <br/><br/>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-suppress-baseline-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-layout-suppress-baseline-001-ref.html
new file mode 100644
index 0000000000..e1a478acd6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-suppress-baseline-001-ref.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <style>
+ .flexBaselineCheck {
+ display: flex;
+ border: 1px solid black;
+ height: 100px;
+ }
+ .flexBaselineCheck > * {
+ border: 2px solid teal;
+
+ /* In the testcase, the (baseline-aligned) items should all have their
+ bottom borders aligned with the 80px-tall canvas. In other words, their
+ bottom borders should all be 20px away from the bottom of their flex
+ container. Here in the reference case, we just use "flex-end" alignment
+ plus a hardcoded 20px margin-bottom to produce a precise reference
+ for what that should look like. */
+ align-self: flex-end;
+ margin-bottom: 20px;
+ }
+ canvas {
+ background: purple;
+ width: 20px;
+ height: 80px;
+ box-sizing: border-box;
+ }
+ .flex {
+ display: flex;
+ }
+ .grid {
+ display: grid;
+ }
+ .multicol {
+ column-count: 2;
+ }
+ </style>
+</head>
+<body>
+ <div class="flexBaselineCheck">
+ <canvas></canvas>
+ <div>block</div>
+ <fieldset><legend>leg</legend>fieldset</fieldset>
+ <div class="flex">flex</div>
+ <div class="grid">grid</div>
+ <div class="multicol">multi<br>col</div>
+ <details open><summary>summary</summary>details</details>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-suppress-baseline-001.html b/testing/web-platform/tests/css/css-contain/contain-layout-suppress-baseline-001.html
new file mode 100644
index 0000000000..b023cfdf96
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-suppress-baseline-001.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: layout' should make elements behave as if they have no baseline</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-layout">
+ <link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#valdef-align-items-baseline">
+ <link rel="match" href="contain-layout-suppress-baseline-001-ref.html">
+ <style>
+ .flexBaselineCheck {
+ display: flex;
+ border: 1px solid black;
+ height: 100px;
+ }
+ .flexBaselineCheck > * {
+ contain: layout;
+ border: 2px solid teal;
+ align-self: baseline;
+ }
+ canvas {
+ background: purple;
+ width: 20px;
+ height: 80px;
+ box-sizing: border-box;
+ }
+ .flex {
+ display: flex;
+ }
+ .grid {
+ display: grid;
+ }
+ .multicol {
+ column-count: 2;
+ }
+ </style>
+</head>
+<body>
+ <div class="flexBaselineCheck">
+ <!-- This canvas just exists to establish a precise, far-down baseline
+ alignment position: -->
+ <canvas></canvas>
+ <!-- "contain:layout" should force all the elements below to behave as if
+ they have no baseline. That means they all should *synthesize* a
+ baseline from their border-box edge, in order to participate in flex
+ item baseline alignment (to honor the outer flex container's
+ "align-items:baseline"). So, the expectation here is that all of these
+ elements' border-bottom edges should be aligned. -->
+ <div>block</div>
+ <fieldset><legend>leg</legend>fieldset</fieldset>
+ <div class="flex">flex</div>
+ <div class="grid">grid</div>
+ <div class="multicol">multi<br>col</div>
+ <details open><summary>summary</summary>details</details>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-suppress-baseline-002-ref.html b/testing/web-platform/tests/css/css-contain/contain-layout-suppress-baseline-002-ref.html
new file mode 100644
index 0000000000..0587c90c35
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-suppress-baseline-002-ref.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <style>
+ .flexBaselineCheck {
+ display: flex;
+ border: 1px solid black;
+ }
+ .flexBaselineCheck > * {
+ border: 2px solid teal;
+ /* In the testcase, the (baseline-aligned) items should all have their
+ bottom borders aligned with the 50px-tall canvas. In other words, their
+ bottom borders should all be aligned at the bottom of their flex
+ container, separated from the bottom by only by their margin-end
+ distance. Here in the reference case, we just use "flex-end" alignment
+ (plus the same amount of margin) to produce a precise reference for what
+ that should look like. */
+ align-self: flex-end;
+ margin: 2px;
+ }
+ canvas {
+ background: purple;
+ width: 20px;
+ height: 50px;
+ box-sizing: border-box;
+ }
+ </style>
+</head>
+<body>
+ <div class="flexBaselineCheck">
+ <canvas></canvas>
+ <button>btn</button>
+ <input type="button" value="i-btn">
+ <input type="submit" value="i-sub">
+ </div>
+
+ <div class="flexBaselineCheck">
+ <canvas></canvas>
+ <input type="text" value="text">
+ <input type="number" value="0">
+ </div>
+
+ <div class="flexBaselineCheck">
+ <canvas></canvas>
+ <input type="date">
+ <input type="time">
+ </div>
+
+ <div class="flexBaselineCheck">
+ <canvas></canvas>
+ <input type="file">
+ <textarea>textarea</textarea>
+ </div>
+
+ <div class="flexBaselineCheck">
+ <canvas></canvas>
+ <select><option>dropdown</option></select>
+ <select multiple style="max-height:40px"><option>multi</option></select>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-layout-suppress-baseline-002.html b/testing/web-platform/tests/css/css-contain/contain-layout-suppress-baseline-002.html
new file mode 100644
index 0000000000..a370386ede
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-layout-suppress-baseline-002.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: layout' should make elements behave as if they have no baseline</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-layout">
+ <link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#valdef-align-items-baseline">
+ <link rel="match" href="contain-layout-suppress-baseline-002-ref.html">
+ <style>
+ .flexBaselineCheck {
+ display: flex;
+ border: 1px solid black;
+ }
+ .flexBaselineCheck > * {
+ contain: layout;
+ border: 2px solid teal;
+ align-self: baseline;
+ margin: 2px;
+ }
+ canvas {
+ background: purple;
+ width: 20px;
+ height: 50px;
+ box-sizing: border-box;
+ }
+ </style>
+</head>
+<body>
+ <div class="flexBaselineCheck">
+ <!-- This canvas just exists to establish a precise, far-down baseline
+ alignment position: -->
+ <canvas></canvas>
+ <!-- "contain:layout" should force all the elements below to behave as if
+ they have no baseline. That means they all should *synthesize* a
+ baseline from their border-box edge, in order to participate in flex
+ item baseline alignment (to honor the outer flex container's
+ "align-items:baseline"). So, the expectation here is that all of these
+ elements' border-bottom edges should be aligned. -->
+ <button>btn</button>
+ <input type="button" value="i-btn">
+ <input type="submit" value="i-sub">
+ </div>
+
+ <!-- Same as above, but with different form controls:
+ (split into multiple flex containers so as not to be too wide): -->
+ <div class="flexBaselineCheck">
+ <canvas></canvas>
+ <input type="text" value="text">
+ <input type="number" value="0">
+ </div>
+
+ <div class="flexBaselineCheck">
+ <canvas></canvas>
+ <input type="date">
+ <input type="time">
+ </div>
+
+ <div class="flexBaselineCheck">
+ <canvas></canvas>
+ <input type="file">
+ <textarea>textarea</textarea>
+ </div>
+
+ <div class="flexBaselineCheck">
+ <canvas></canvas>
+ <select><option>dropdown</option></select>
+ <select multiple style="max-height:40px"><option>multi</option></select>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-001.html b/testing/web-platform/tests/css/css-contain/contain-paint-001.html
new file mode 100644
index 0000000000..ca2eb6e6f9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-001.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment use the padding edge</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="paint containment clips at the padding edge, not content edge, and takes corner clipping into account">
+ <link rel="match" href="reference/contain-paint-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ padding: 50px;
+ border-radius: 100px;
+ contain: paint;
+}
+div::before {
+ content:"";
+ display: block;
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+div::after {
+ content:"";
+ display: block;
+ background: red;
+ width: 50px;
+ height: 50px;
+ margin-top: 38px;
+ margin-left: -50px;
+}
+</style>
+
+<p>Test passes if there is a green square in a rounded blue box, and no red.
+<div></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-002.html b/testing/web-platform/tests/css/css-contain/contain-paint-002.html
new file mode 100644
index 0000000000..6f495f5617
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-002.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on non-atomic inlines</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="paint containment does not apply to non atomic inlines">
+ <link rel="match" href="../reference/pass_if_pass_below.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+
+<style>
+span {
+ contain: paint;
+ width: 0; /* Because if the test fails, the span may get blockified, and which would make wide enough to hold the PASS */
+}
+span::after {
+ content: "PASS";
+ position: absolute;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div><span></span></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-004.html b/testing/web-platform/tests/css/css-contain/contain-paint-004.html
new file mode 100644
index 0000000000..d37676dda9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-004.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment applies to the principal box for list items</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="paint containment applies to the principal box, which for list items excludes the list marker">
+ <link rel="match" href="../reference/nothing.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+
+<style>
+li { contain: paint; }
+</style>
+
+<p>There should be nothing below.</p>
+<ol>
+ <li>
+ <li>
+ <li>
+ <li>
+ <li>
+ <li>
+</ol>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-005.html b/testing/web-platform/tests/css/css-contain/contain-paint-005.html
new file mode 100644
index 0000000000..a6817be517
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-005.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on ruby-base</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="paint containment does not apply to ruby-base">
+ <link rel="match" href="../reference/pass_if_pass_below.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+
+<style>
+rb {
+ contain: paint;
+ display: ruby-base;
+ width: 0; /* Because if the test fails, this may get blockified, and which could make wide enough to hold the PASS */
+}
+rb::after {
+ content: "PASS";
+ position: absolute;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div><ruby><rb></rb></ruby></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-006.html b/testing/web-platform/tests/css/css-contain/contain-paint-006.html
new file mode 100644
index 0000000000..b04a78f998
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-006.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on ruby-base-container</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="paint containment does not apply to ruby-base-container">
+ <link rel="match" href="../reference/pass_if_pass_below.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+
+<style>
+rbc {
+ contain: paint;
+ display: ruby-base-container;
+ width: 0; /* Because if the test fails, this may get blockified, and which could make wide enough to hold the PASS */
+}
+rbc::after {
+ content: "PASS";
+ position: absolute;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div><ruby><rbc></rbc></ruby></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-007.html b/testing/web-platform/tests/css/css-contain/contain-paint-007.html
new file mode 100644
index 0000000000..b02bd535b7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-007.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on ruby-text-container</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="paint containment does not apply to ruby-text-container">
+ <link rel="match" href="reference/contain-paint-007-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+
+<style>
+rtc {
+ contain: paint;
+ display: ruby-text-container;
+ width: 0; /* Because if the test fails, this may get blockified, and which could make wide enough to hold the PASS */
+ font-size: 1rem;
+}
+rtc::after {
+ content: "PASS";
+ position: absolute;
+}
+</style>
+
+<p>This test passes if you can see the word PASS below.
+<div><ruby><rtc></rtc></ruby></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-008.html b/testing/web-platform/tests/css/css-contain/contain-paint-008.html
new file mode 100644
index 0000000000..ab1ba6beab
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-008.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on ruby-text</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="paint containment does not apply to ruby-text">
+ <link rel="match" href="reference/contain-paint-008-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+
+<style>
+rt {
+ contain: paint;
+ display: ruby-text;
+ font-size: 1rem;
+ font-family: monospace;
+}
+rt::after {
+ content: "PASS";
+
+ /* Doing the following instead of position:absolute to move it out into the area that would be
+ clipped because Firefox clips absolutely positioned content of rt even in builds without
+ support for css containment.
+ Since this technique works also, there's no need to trigger a false negative.
+ */
+ position: relative;
+ left: 4ch;
+}
+</style>
+
+<p>This test passes if you can see the word PASS below.
+<div><ruby><rt></rt></ruby></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-009.html b/testing/web-platform/tests/css/css-contain/contain-paint-009.html
new file mode 100644
index 0000000000..34ca8d72b5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-009.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment absolutely positioned descendants</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert content="Paint containment makes an element to act as containing block for absolutely positioned descendants.">
+<style>
+#contain-paint {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ background: red;
+}
+
+#abspos {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="contain-paint">
+ <div id="abspos"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-010.html b/testing/web-platform/tests/css/css-contain/contain-paint-010.html
new file mode 100644
index 0000000000..13f4a9395c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-010.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment fixed positioned descendants</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert content="Paint containment makes an element to act as containing block for fixed positioned descendants.">
+<style>
+#contain-paint {
+ contain: paint;
+ width: 100px;
+ height: 50px;
+ background: red;
+}
+
+#fixed {
+ position: fixed;
+ bottom: 0;
+ right: 0;
+ background: green;
+ width: 100px;
+ height: 50px;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="contain-paint">
+ <div id="fixed"></div>
+</div>
+<div id="contain-paint" style="display: inline-block">
+ <div id="fixed"></div>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-011.html b/testing/web-platform/tests/css/css-contain/contain-paint-011.html
new file mode 100644
index 0000000000..d18a667025
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-011.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment absolutely positioned descendants</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert content="Paint containment doesn't apply to non-atomic inline elements so they don't act as containing block for absolutely positioned descendants.">
+<style>
+#containing-block {
+ position: relative;
+ background: red;
+ width: 100px;
+ height: 100px;
+}
+
+#contain-paint {
+ contain: paint;
+}
+
+#abspos {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ background: green;
+ width: 100%;
+ height: 100%;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="containing-block">
+ <span id="contain-paint">
+ <div id="abspos"></div>
+ </span>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-012.html b/testing/web-platform/tests/css/css-contain/contain-paint-012.html
new file mode 100644
index 0000000000..471726a99c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-012.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment fixed positioned descendants</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert content="Paint containment doesn't apply to non-atomic inline elements so they don't act as containing block for fixed positioned descendants.">
+<style>
+#containing-block {
+ transform: translateX(0);
+ background: red;
+ width: 100px;
+ height: 100px;
+}
+
+#contain-paint {
+ contain: paint;
+}
+
+#fixed {
+ position: fixed;
+ bottom: 0;
+ right: 0;
+ background: green;
+ width: 100%;
+ height: 100%;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="containing-block">
+ <span id="contain-paint">
+ <div id="fixed"></div>
+ </span>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-014.html b/testing/web-platform/tests/css/css-contain/contain-paint-014.html
new file mode 100644
index 0000000000..ee6bc7876f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-014.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment on table-cell</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="../reference/nothing.html">
+<meta name=assert content="Paint containment does apply to table-cell elements.">
+<style>
+div {
+ display: table-cell;
+ contain: paint;
+}
+span {
+ position: absolute;
+}
+</style>
+
+<p>There should be nothing below.</p>
+<div><span>FAIL</span></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-015.html b/testing/web-platform/tests/css/css-contain/contain-paint-015.html
new file mode 100644
index 0000000000..702bfb62b1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-015.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment on table-row-group</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="../reference/pass_if_pass_below.html">
+<meta name=assert content="Paint containment doesn't apply to table-row-group elements.">
+<style>
+div {
+ display: table-row-group;
+ contain: paint;
+}
+span {
+ position: absolute;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div><span>PASS</span></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-016.html b/testing/web-platform/tests/css/css-contain/contain-paint-016.html
new file mode 100644
index 0000000000..cb16009e11
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-016.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment on table-header-group</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="../reference/pass_if_pass_below.html">
+<meta name=assert content="Paint containment doesn't apply to table-header-group elements.">
+<style>
+div {
+ display: table-header-group;
+ contain: paint;
+}
+span {
+ position: absolute;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div><span>PASS</span></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-017.html b/testing/web-platform/tests/css/css-contain/contain-paint-017.html
new file mode 100644
index 0000000000..d1e57d4d5c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-017.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment on table-footer-group</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="../reference/pass_if_pass_below.html">
+<meta name=assert content="Paint containment doesn't apply to table-footer-group elements.">
+<style>
+div {
+ display: table-footer-group;
+ contain: paint;
+}
+span {
+ position: absolute;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div><span>PASS</span></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-018.html b/testing/web-platform/tests/css/css-contain/contain-paint-018.html
new file mode 100644
index 0000000000..f4b92dab87
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-018.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment on table-row</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="../reference/pass_if_pass_below.html">
+<meta name=assert content="Paint containment doesn't apply to table-row elements.">
+<style>
+div {
+ display: table-row;
+ contain: paint;
+}
+span {
+ position: absolute;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div><span>PASS</span></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-019.html b/testing/web-platform/tests/css/css-contain/contain-paint-019.html
new file mode 100644
index 0000000000..90c5a8f054
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-019.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment on table-caption</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="../reference/nothing.html">
+<meta name=assert content="Paint containment does apply to table-caption elements.">
+<style>
+div {
+ display: table-caption;
+ contain: paint;
+}
+span {
+ position: absolute;
+}
+</style>
+
+<p>There should be nothing below.</p>
+<div><span>FAIL</span></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-020.html b/testing/web-platform/tests/css/css-contain/contain-paint-020.html
new file mode 100644
index 0000000000..44a62172ed
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-020.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment stacking context</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="../reference/pass_if_pass_below.html">
+<meta name=assert content="Paint containment elements create a stacking context.">
+<style>
+div {
+ contain: paint;
+ background: white;
+}
+span {
+ position: relative;
+ z-index: -1;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div><span>PASS</span></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-021.html b/testing/web-platform/tests/css/css-contain/contain-paint-021.html
new file mode 100644
index 0000000000..c1f145245d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-021.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment stacking context</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="../reference/nothing.html">
+<meta name=assert content="Elements in which paint containment doesn't apply, do not create a stacking context.">
+<style>
+rt {
+ display: ruby-text;
+ contain: paint;
+ background: white;
+ overflow: hidden;
+}
+span {
+ position: relative;
+ z-index: -1;
+}
+</style>
+
+<p>There should be nothing below.</p>
+<ruby><rt><span>FAIL</span></rt></ruby>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-022.html b/testing/web-platform/tests/css/css-contain/contain-paint-022.html
new file mode 100644
index 0000000000..91b3884d46
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-022.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' and absolutely positioned descendants</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="reference/contain-paint-022-ref.html">
+
+ <meta content="This test checks that paint containment applies to atomic inline elements and then they act as containing block for absolutely positioned descendants." name="assert">
+
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ div#incorrect-containing-block
+ {
+ color: transparent;
+ font-family: Ahem;
+ font-size: 100px;
+ height: 2em;
+ line-height: 1;
+ position: relative;
+ width: 2em;
+ }
+
+ div#correct-containing-block
+ {
+ background-color: red;
+ contain: paint;
+ display: inline-block;
+ height: 1em;
+ width: 1em;
+ }
+
+ div#abspos
+ {
+ background-color: green;
+ height: 1em;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 1em;
+ }
+ </style>
+
+ <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+ <div id="incorrect-containing-block">
+
+ AB C<div id="correct-containing-block">
+
+ <div id="abspos"></div>
+
+ </div>
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-023.html b/testing/web-platform/tests/css/css-contain/contain-paint-023.html
new file mode 100644
index 0000000000..695dc4e778
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-023.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' and absolutely positioned descendants</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+ <meta content="This test checks that paint containment applies to atomic inline elements so that they can act as containing block for absolutely positioned descendants." name="assert">
+
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ div#rel-pos-red
+ {
+ background-image: url("support/pattern-gg-gr-100x100.png");
+ color: green;
+ font-family: Ahem;
+ font-size: 50px;
+ height: 2em;
+ line-height: 1;
+ position: relative;
+ width: 2em;
+ }
+
+ div#containing-block
+ {
+ contain: paint;
+ display: inline-block;
+ height: 50%;
+ vertical-align: top;
+ width: 50%;
+ }
+
+ div#abspos
+ {
+ background-color: green;
+ height: 50px;
+ position: absolute;
+ left: 0px;
+ width: 50px;
+ }
+ </style>
+
+ <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+ <div id="rel-pos-red">
+
+ AB C<div id="containing-block">
+
+ <div id="abspos"></div>
+
+ </div>
+
+ </div>
+
+ <!--
+
+ |--------|
+ | A B |
+ | .---|
+ | C |c-b|
+ |----|---|
+
+ -->
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-024.html b/testing/web-platform/tests/css/css-contain/contain-paint-024.html
new file mode 100644
index 0000000000..ea92aeb43b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-024.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' and absolutely positioned descendants</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+ <meta content="This test checks that paint containment does not apply to non-atomic inline elements so they do not act as containing block for absolutely positioned descendants." name="assert">
+
+ <style>
+ div#correct-containing-block
+ {
+ background-color: red;
+ height: 100px;
+ position: relative;
+ width: 100px;
+ }
+
+ div#incorrect-containing-block
+ {
+ contain: paint;
+ display: inline;
+ }
+
+ div#abspos
+ {
+ background-color: green;
+ bottom: 0;
+ height: 100%;
+ position: absolute;
+ right: 0;
+ width: 100%;
+ }
+ </style>
+
+ <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+ <div id="correct-containing-block">
+
+ <div id="incorrect-containing-block">
+
+ <div id="abspos"></div>
+
+ </div>
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-025.html b/testing/web-platform/tests/css/css-contain/contain-paint-025.html
new file mode 100644
index 0000000000..0a41b62b2c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-025.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment stacking context</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="../reference/nothing.html">
+<meta name=assert content="Elements in which paint containment doesn't apply, do not create a stacking context.">
+<style>
+div {
+ display: inline;
+ contain: paint;
+ background: white;
+}
+span {
+ position: relative;
+ z-index: -1;
+}
+</style>
+
+<p>There should be nothing below.</p>
+<div><span>FAIL</span></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-026.html b/testing/web-platform/tests/css/css-contain/contain-paint-026.html
new file mode 100644
index 0000000000..f6da8679f0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-026.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment and box-shadow</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert content="Paint containment should clip box-shadow effect on child.">
+<style>
+#contain-paint {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ background: red;
+}
+
+#child {
+ background: green;
+ box-shadow: 0 0 100px 100px red;
+ width: 100px;
+ height: 100px;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="contain-paint">
+ <div id="child"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-047.html b/testing/web-platform/tests/css/css-contain/contain-paint-047.html
new file mode 100644
index 0000000000..7fdc4a8f0d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-047.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' and clipping at padding edge</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="reference/contain-paint-047-ref.html">
+
+ <meta content="This test checks that an element with 'contain: paint' that has its content overflowing will clip at padding edge." name="assert">
+
+
+ <style>
+ div
+ {
+ color: green;
+ contain: paint;
+ font-family: monospace;
+ font-size: 100px;
+ width: 4ch;
+ }
+
+ span
+ {
+ background-color: red;
+ color: yellow;
+ }
+ </style>
+
+ <p>Test passes if there is <strong>no red</strong>.
+
+ <div>PASS<span>FAIL</span></div>
+
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-048.html b/testing/web-platform/tests/css/css-contain/contain-paint-048.html
new file mode 100644
index 0000000000..870484e575
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-048.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' and clipping at padding edge</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="reference/ref-if-there-is-no-red.xht">
+
+ <meta content="This test checks that an element with 'contain: paint' that has its content overflowing will clip at padding edge." name="assert">
+
+ <style>
+ div
+ {
+ color: red;
+ contain: paint;
+ font-size: 100px;
+ width: 0;
+ }
+
+ </style>
+
+ <p>Test passes if there is <strong>no red</strong>.
+
+ <div>FAIL</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-049.html b/testing/web-platform/tests/css/css-contain/contain-paint-049.html
new file mode 100644
index 0000000000..49cdc9beca
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-049.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset="utf8">
+<title>CSS Containment Test: Scrolling overflow works when paint is contained"</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<meta name="assert" content="Scrolling overflow works when paint is contained.">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+#container {
+ width: 100px;
+ height: 100px;
+ overflow: auto;
+ contain: paint;
+}
+.content {
+ position: absolute;
+ height: 500%;
+ width: 100%;
+}
+</style>
+
+<div id="container">
+ <div class="content">
+ </div>
+</div>
+
+<script>
+ test(() => {
+ container.scrollTo(0, 100);
+ assert_equals(container.scrollTop, 100);
+ }, "Scrolling overflow works when paint is contained");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-050-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-050-ref.html
new file mode 100644
index 0000000000..ebb631432d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-050-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>CSS Containment Test: Scrolling overflow works when paint is contained"</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<meta name="assert" content="Scrolling overflow works when paint is contained.">
+
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+
+<style>
+.content {
+ height: 100vh;
+ width: 100%;
+}
+</style>
+
+<body>
+ <div class="content"></div>
+
+<script>
+waitForAtLeastOneFrame().then(() => {
+ document.body.scrollTop = 100;
+ takeScreenshot();
+});
+</script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-050.html b/testing/web-platform/tests/css/css-contain/contain-paint-050.html
new file mode 100644
index 0000000000..a25e126921
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-050.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>CSS Containment Test: Scrolling overflow works when paint is contained"</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="contain-paint-050-ref.html">
+<meta name="assert" content="Scrolling overflow works when paint is contained.">
+
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+
+<style>
+body {
+ contain: paint;
+}
+.content {
+ height: 100vh;
+ width: 100%;
+}
+</style>
+
+<body>
+ <div class="content"></div>
+
+<script>
+waitForAtLeastOneFrame().then(() => {
+ document.body.scrollTop = 100;
+ takeScreenshot();
+});
+</script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-baseline-001.html b/testing/web-platform/tests/css/css-contain/contain-paint-baseline-001.html
new file mode 100644
index 0000000000..c44444dd05
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-baseline-001.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment and baselines</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=assert content="contain:paint does not suppress baseline alignment">
+ <link rel="match" href="reference/contain-baseline-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+
+<style>
+div {
+ display: inline-block;
+ height: 5px;
+ background: blue;
+ width: 50px;
+ contain: paint;
+ color: transparent;
+ font-size: 100px;
+}
+</style>
+
+<p>Test passes if there are two, not one, blue lines below.</p>
+<div></div><div>a</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-cell-001.html b/testing/web-platform/tests/css/css-contain/contain-paint-cell-001.html
new file mode 100644
index 0000000000..5a4a7a4e69
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-cell-001.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' applies to 'table-cell' elements</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="reference/contain-paint-047-ref.html">
+
+ <meta content="This test checks that the paint containment applies to table-cell elements. Therefore the content of the table-cell element should be clipped to the padding edge of its principal box." name="assert">
+
+ <style>
+ div#table
+ {
+ display: table;
+ font-family: monospace;
+ font-size: 100px;
+ table-layout: fixed;
+ width: 4ch;
+ }
+
+ div.column
+ {
+ display: table-column;
+ }
+
+ div#middle-column
+ {
+ width: 4ch;
+ }
+
+ div.row
+ {
+ display: table-row;
+ }
+
+ div.cell
+ {
+ background-color: white;
+ display: table-cell;
+ }
+
+ div#contain
+ {
+ color: green;
+ contain: paint;
+ }
+
+ span
+ {
+ background-color: red;
+ color: yellow;
+ }
+ </style>
+
+ <p>Test passes if there is <strong>no red</strong>.
+
+ <div id="table">
+
+ <div class="column"></div><div class="column" id="middle-column"></div><div class="column"></div>
+
+ <div class="row"><div class="cell"></div><div class="cell"></div><div class="cell"></div></div>
+
+ <div class="row"><div class="cell"></div><div class="cell" id="contain">PASS<span>FAIL</span></div><div class="cell"></div></div>
+
+ <div class="row"><div class="cell"></div><div class="cell"></div><div class="cell"></div></div>
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-cell-002.html b/testing/web-platform/tests/css/css-contain/contain-paint-cell-002.html
new file mode 100644
index 0000000000..f670700388
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-cell-002.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' and table-cell elements</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="reference/contain-paint-047-ref.html">
+
+ <meta content="This test checks that the paint containment applies to table-cell elements. Therefore the content of the table-cell element should be clipped to the padding edge of its principal box." name="assert">
+
+ <style>
+ table
+ {
+ border-spacing: 0px;
+ /* to help reuse an already created reference file */
+ font-family: monospace;
+ font-size: 100px;
+ table-layout: fixed;
+ width: 4ch;
+ }
+
+ td
+ {
+ padding: 0px;
+ /* to help reuse an already created reference file */
+ }
+
+ col#middle-column
+ {
+ width: 4ch;
+ }
+
+ td#test
+ {
+ color: green;
+ contain: paint;
+ }
+
+ span
+ {
+ background-color: red;
+ color: yellow;
+ }
+ </style>
+
+ <p>Test passes if there is <strong>no red</strong>.
+
+ <table>
+
+ <col><col id="middle-column"><col>
+
+ <tr><td><td><td>
+
+ <tr><td><td id="test">PASS<span>FAIL</span><td>
+
+ <tr><td><td><td>
+
+ </table>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-change-opacity.html b/testing/web-platform/tests/css/css-contain/contain-paint-change-opacity.html
new file mode 100644
index 0000000000..4fe3f439b5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-change-opacity.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#contain-property">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; background: red">
+ <div id="container" style="contain: paint; opacity: 0.1">
+ <div style="height: 100px; background: green; position: relative"></div>
+ </div>
+</div>
+<script>
+waitForAtLeastOneFrame().then(() => {
+ container.style.opacity = 1;
+ takeScreenshot();
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-001-ref.html
new file mode 100644
index 0000000000..629cb939e0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-001-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <style>
+ #a {
+ width: 150px;
+ height: 150px;
+ background: green;
+ margin: 25px;
+ }
+ </style>
+</head>
+<body>
+ <div id="a"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-001.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-001.html
new file mode 100644
index 0000000000..6637e08393
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-001.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: paint' with various overflowing block descendants.</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-clip-001-ref.html">
+ <style>
+ .root {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ background: blue;
+ margin: 25px;
+ padding: 25px;
+ }
+ .a {
+ width: 100px;
+ height: 200px;
+ background: red;
+ }
+ .b {
+ width: 150px;
+ height: 150px;
+ background: green;
+ position: relative;
+ top: -25px;
+ left: -25px;
+ }
+ .background {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 200px;
+ height: 200px;
+ background: red;
+ z-index: -1;
+ }
+ .foreground {
+ position: absolute;
+ top: -25px;
+ left: -25px;
+ width: 150px;
+ height: 150px;
+ border: 25px solid red;
+ z-index: 1;
+ }
+ </style>
+</head>
+<body>
+ <div class="root">
+ <div class="a">
+ <div class="b"></div>
+ <!--These two absolutely positioned elements are checking that all sides are-->
+ <!--clipped. They also test that clipping is done correctly on absolutely-->
+ <!--positioned elements.-->
+ <div class="background"></div>
+ <div class="foreground"></div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-002-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-002-ref.html
new file mode 100644
index 0000000000..3baefff57c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-002-ref.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <style>
+ .root {
+ overflow: hidden;
+ width: 100px;
+ height: 100px;
+ background: green;
+ margin: 25px;
+ padding: 10px;
+ border-radius: 4em;
+ }
+ </style>
+</head>
+<body>
+ <div class="root">
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA This text should
+ be clipped to the box. Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed
+ nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum.
+ Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa.
+ Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora
+ torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales
+ ligula in libero.
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-002.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-002.html
new file mode 100644
index 0000000000..ba16325b97
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-002.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: paint' with overflowing text contents inside a rounded rectangle box.</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-clip-002-ref.html">
+ <style>
+ .root {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ background: green;
+ margin: 25px;
+ padding: 10px;
+ border-radius: 4em;
+ }
+ </style>
+</head>
+<body>
+ <div class="root">
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA This text should
+ be clipped to the box. Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed
+ nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum.
+ Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa.
+ Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora
+ torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales
+ ligula in libero.
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-003-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-003-ref.html
new file mode 100644
index 0000000000..425844ae47
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-003-ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <style>
+ .root {
+ overflow-x: scroll;
+ overflow-y: scroll;
+ width: 100px;
+ height: 100px;
+ background: green;
+ margin: 25px;
+ padding: 25px;
+ }
+ </style>
+</head>
+<body>
+ <div class="root">
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA This text should
+ be clipped to the box. Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed
+ nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum.
+ Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa.
+ Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora
+ torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales
+ ligula in libero.
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-003.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-003.html
new file mode 100644
index 0000000000..30a7335f15
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-003.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: paint' with overflowing text contents, and 'overflow-y: scroll'.</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-clip-003-ref.html">
+ <style>
+ .root {
+ contain: paint;
+ overflow-y: scroll;
+ width: 100px;
+ height: 100px;
+ background: green;
+ margin: 25px;
+ padding: 25px;
+ }
+ </style>
+</head>
+<body>
+ <div class="root">
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA This text should
+ be clipped to the box. Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed
+ nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum.
+ Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa.
+ Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora
+ torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales
+ ligula in libero.
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-004-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-004-ref.html
new file mode 100644
index 0000000000..0861c68cbe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-004-ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <style>
+ .root {
+ overflow-y: scroll;
+ overflow-x: scroll;
+ width: 100px;
+ height: 100px;
+ background: green;
+ margin: 25px;
+ padding: 25px;
+ }
+ </style>
+</head>
+<body>
+ <div class="root">
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA This text should
+ be clipped to the box. Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed
+ nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum.
+ Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa.
+ Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora
+ torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales
+ ligula in libero.
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-004.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-004.html
new file mode 100644
index 0000000000..709f191e85
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-004.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: paint' with overflowing text contents, and 'overflow-x: scroll'.</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-clip-004-ref.html">
+ <style>
+ .root {
+ contain: paint;
+ overflow-x: scroll;
+ width: 100px;
+ height: 100px;
+ background: green;
+ margin: 25px;
+ padding: 25px;
+ }
+ </style>
+</head>
+<body>
+ <div class="root">
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA This text should
+ be clipped to the box. Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed
+ nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum.
+ Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa.
+ Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora
+ torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales
+ ligula in libero.
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-005.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-005.html
new file mode 100644
index 0000000000..fce4a89fbb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-005.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: paint' on li with overflowing text contents and
+ bullet, and 'overflow-y: scroll'.</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-clip-003-ref.html">
+ <style>
+ ul {
+ padding: 0;
+ margin: 0;
+ }
+ .root {
+ contain: paint;
+ overflow-y: scroll;
+ width: 100px;
+ height: 100px;
+ background: green;
+ margin: 25px;
+ padding: 25px;
+ }
+ ::marker { font-family: inherit; }
+ </style>
+</head>
+<body>
+ <ul>
+ <li class="root">
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA This text should
+ be clipped to the box. Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam.
+ Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis
+ ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris
+ massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu
+ ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur
+ sodales ligula in libero.
+ </li>
+ </ul>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-006-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-006-ref.html
new file mode 100644
index 0000000000..ecd22b307a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-006-ref.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <style>
+ .root {
+ width: 100px;
+ height: 100px;
+ background: green;
+ margin: 25px;
+ padding: 25px;
+ overflow: hidden;
+ overflow-clip-box: content-box;
+ }
+ </style>
+</head>
+<body>
+ <div class="root">
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA This text should
+ be clipped to the content box. Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed
+ nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum.
+ Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa.
+ Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora
+ torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales
+ ligula in libero.
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-006.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-006.html
new file mode 100644
index 0000000000..a4d6835a16
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-006.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: paint' with overflowing text contents while "overflow-clip-box: content-box" enabled.</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-clip-006-ref.html">
+ <style>
+ .root {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ background: green;
+ margin: 25px;
+ padding: 25px;
+ overflow-clip-box: content-box;
+ }
+ </style>
+</head>
+<body>
+ <div class="root">
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA This text should
+ be clipped to the content box. Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed
+ nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum.
+ Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa.
+ Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora
+ torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales
+ ligula in libero.
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-011.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-011.html
new file mode 100644
index 0000000000..d9b9052f4b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-011.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' and clipping descendants at padding edge</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+ <meta content="This test checks that the paint of the descendant (a red square image) and its geometry is clipped to the padding edge of the element's principal box." name="assert">
+
+ <!--
+
+ contain-paint-clip-011: content overflows horizontally, principal box has no padding
+
+ contain-paint-clip-012: content overflows vertically, principal box has no padding
+
+ contain-paint-clip-013: content overflows horizontally, principal box has horizontal padding
+
+ contain-paint-clip-014: content overflows vertically, principal box has vertical padding
+
+ contain-paint-clip-015: content overflow horizontally, principal box has horizontal padding and corner clipping is involved
+
+ contain-paint-clip-016: content overflow vertically, principal box has vertical padding and corner clipping is involved
+
+ contain-paint-clip-017: principal box has horizontal and vertical padding, generated ::before content is inside top-right corner
+
+ contain-paint-clip-018: principal box has horizontal and vertical padding, generated ::after content is inside top-left corner
+
+ -->
+
+
+ <style>
+ div
+ {
+ width: 100px;
+ }
+
+ div#red-overlapped-test
+ {
+ background-color: red;
+ contain: paint;
+ }
+
+ img
+ {
+ vertical-align: bottom;
+ }
+
+ div#green-overlapping-reference
+ {
+ background-color: green;
+ bottom: 100px;
+ height: 100px;
+ position: relative;
+ }
+ </style>
+
+ <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+ <div id="red-overlapped-test"><img src="support/swatch-red.png" width="200" height="100" alt="Image download support must be enabled"></div>
+
+ <div id="green-overlapping-reference"></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-012.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-012.html
new file mode 100644
index 0000000000..090aa1586c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-012.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' and clipping descendants at padding edge</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+ <meta content="This test checks that the paint of the descendant (a red square image) and its geometry is clipped to the padding edge of the element's principal box." name="assert">
+
+ <!--
+
+ contain-paint-clip-011: content overflows horizontally, principal box has no padding
+
+ contain-paint-clip-012: content overflows vertically, principal box has no padding
+
+ contain-paint-clip-013: content overflows horizontally, principal box has horizontal padding
+
+ contain-paint-clip-014: content overflows vertically, principal box has vertical padding
+
+ contain-paint-clip-015: content overflow horizontally, principal box has horizontal padding and corner clipping is involved
+
+ contain-paint-clip-016: content overflow vertically, principal box has vertical padding and corner clipping is involved
+
+ contain-paint-clip-017: principal box has horizontal and vertical padding, generated ::before content is inside top-right corner
+
+ contain-paint-clip-018: principal box has horizontal and vertical padding, generated ::after content is inside top-left corner
+
+ -->
+
+
+ <style>
+ div
+ {
+ height: 100px;
+ width: 100px;
+ }
+
+ div#red-overlapped-test
+ {
+ background-color: red;
+ contain: paint;
+ }
+
+ img
+ {
+ vertical-align: bottom;
+ }
+
+ div#green-overlapping-reference
+ {
+ background-color: green;
+ bottom: 100px;
+ position: relative;
+ }
+ </style>
+
+ <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+ <div id="red-overlapped-test"><img src="support/swatch-red.png" width="100" height="200" alt="Image download support must be enabled"></div>
+
+ <div id="green-overlapping-reference"></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-013.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-013.html
new file mode 100644
index 0000000000..7c539bf93d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-013.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' and clipping descendants at padding edge</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+ <meta content="This test checks that the paint of the descendant (a red square image) and its geometry is clipped to the padding edge of the element's principal box." name="assert">
+
+ <!--
+
+ contain-paint-clip-011: content overflows horizontally, principal box has no padding
+
+ contain-paint-clip-012: content overflows vertically, principal box has no padding
+
+ contain-paint-clip-013: content overflows horizontally, principal box has horizontal padding
+
+ contain-paint-clip-014: content overflows vertically, principal box has vertical padding
+
+ contain-paint-clip-015: content overflow horizontally, principal box has horizontal padding and corner clipping is involved
+
+ contain-paint-clip-016: content overflow vertically, principal box has vertical padding and corner clipping is involved
+
+ contain-paint-clip-017: principal box has horizontal and vertical padding, generated ::before content is inside top-right corner
+
+ contain-paint-clip-018: principal box has horizontal and vertical padding, generated ::after content is inside top-left corner
+
+ -->
+
+
+ <style>
+ div#red-overlapped-test
+ {
+ background-color: red;
+ contain: paint;
+ padding: 0px 25px;
+ width: 50px;
+ }
+
+ img
+ {
+ vertical-align: bottom;
+ }
+
+ div#green-overlapping-reference
+ {
+ background-color: green;
+ bottom: 100px;
+ height: 100px;
+ position: relative;
+ width: 100px;
+ }
+ </style>
+
+ <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+ <div id="red-overlapped-test"><img src="support/swatch-red.png" width="175" height="100" alt="Image download support must be enabled"></div>
+
+ <div id="green-overlapping-reference"></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-014.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-014.html
new file mode 100644
index 0000000000..296187f36a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-014.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' and clipping descendants at padding edge</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+ <meta content="This test checks that the paint of the descendant (a red square image) and its geometry is clipped to the padding edge of the element's principal box." name="assert">
+
+ <!--
+
+ contain-paint-clip-011: content overflows horizontally, principal box has no padding
+
+ contain-paint-clip-012: content overflows vertically, principal box has no padding
+
+ contain-paint-clip-013: content overflows horizontally, principal box has horizontal padding
+
+ contain-paint-clip-014: content overflows vertically, principal box has vertical padding
+
+ contain-paint-clip-015: content overflow horizontally, principal box has horizontal padding and corner clipping is involved
+
+ contain-paint-clip-016: content overflow vertically, principal box has vertical padding and corner clipping is involved
+
+ contain-paint-clip-017: principal box has horizontal and vertical padding, generated ::before content is inside top-right corner
+
+ contain-paint-clip-018: principal box has horizontal and vertical padding, generated ::after content is inside top-left corner
+
+ -->
+
+
+ <style>
+ div#red-overlapped-test
+ {
+ background-color: red;
+ contain: paint;
+ height: 50px;
+ padding: 25px 0px;
+ width: 100px;
+ }
+
+ img
+ {
+ vertical-align: bottom;
+ }
+
+ div#green-overlapping-reference
+ {
+ background-color: green;
+ bottom: 100px;
+ height: 100px;
+ position: relative;
+ width: 100px;
+ }
+ </style>
+
+ <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+ <div id="red-overlapped-test"><img src="support/swatch-red.png" width="100" height="175" alt="Image download support must be enabled"></div>
+
+ <div id="green-overlapping-reference"></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-015.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-015.html
new file mode 100644
index 0000000000..9519015a53
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-015.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' and clipping descendants at padding edge</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="reference/contain-paint-clip-015-ref.html">
+ <!--
+ This test fails in Chromium 66.0.3359.117
+ -->
+
+ <meta content="This test checks that the paint of the descendant (a red square image) and its geometry is clipped to the padding edge of the element's principal box, taking corner clipping into account." name="assert">
+ <meta name="fuzzy" content="maxDifference=0-99; totalPixels=0-410"/>
+
+ <!--
+
+ contain-paint-clip-011: content overflows horizontally, principal box has no padding
+
+ contain-paint-clip-012: content overflows vertically, principal box has no padding
+
+ contain-paint-clip-013: content overflows horizontally, principal box has horizontal padding
+
+ contain-paint-clip-014: content overflows vertically, principal box has vertical padding
+
+ contain-paint-clip-015: content overflow horizontally, principal box has horizontal padding and corner clipping is involved
+
+ contain-paint-clip-016: content overflow vertically, principal box has vertical padding and corner clipping is involved
+
+ contain-paint-clip-017: principal box has horizontal and vertical padding, generated ::before content is inside top-right corner
+
+ contain-paint-clip-018: principal box has horizontal and vertical padding, generated ::after content is inside top-left corner
+
+ -->
+
+
+ <style>
+ div
+ {
+ border-radius: 50%;
+ height: 50px;
+ width: 50px;
+ }
+
+ div#red-container-circle
+ {
+ background-color: red;
+ contain: paint;
+ padding: 25px;
+ }
+
+ img
+ {
+ vertical-align: bottom;
+ }
+
+ div#green-overlapping-reference
+ {
+ background-color: green;
+ bottom: 100px;
+ height: 100px;
+ position: relative;
+ width: 100px;
+ }
+ </style>
+
+ <p>Test passes if there is a filled green circle and <strong>no red</strong>.
+
+ <div id="red-container-circle"><img src="support/swatch-red.png" width="175" height="100" alt="Image download support must be enabled"></div>
+
+ <div id="green-overlapping-reference"></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-016.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-016.html
new file mode 100644
index 0000000000..e141561357
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-016.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' and clipping descendants at padding edge</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="reference/contain-paint-clip-015-ref.html">
+ <!--
+ This test fails in Chromium 66.0.3359.117
+ -->
+
+ <meta content="This test checks that the paint of the descendant (a red square image) and its geometry is clipped to the padding edge of the element's principal box, taking corner clipping into account." name="assert">
+ <meta name="fuzzy" content="maxDifference=0-99;totalPixels=0-410">
+
+ <!--
+
+ contain-paint-clip-011: content overflows horizontally, principal box has no padding
+
+ contain-paint-clip-012: content overflows vertically, principal box has no padding
+
+ contain-paint-clip-013: content overflows horizontally, principal box has horizontal padding
+
+ contain-paint-clip-014: content overflows vertically, principal box has vertical padding
+
+ contain-paint-clip-015: content overflow horizontally, principal box has horizontal padding and corner clipping is involved
+
+ contain-paint-clip-016: content overflow vertically, principal box has vertical padding and corner clipping is involved
+
+ contain-paint-clip-017: principal box has horizontal and vertical padding, generated ::before content is inside top-right corner
+
+ contain-paint-clip-018: principal box has horizontal and vertical padding, generated ::after content is inside top-left corner
+
+ -->
+
+
+ <style>
+ div#red-container-circle
+ {
+ background-color: red;
+ border-radius: 50%;
+ contain: paint;
+ height: 50px;
+ padding: 25px 0px;
+ width: 100px;
+ }
+
+ img
+ {
+ vertical-align: bottom;
+ }
+
+ div#green-overlapping-reference
+ {
+ background-color: green;
+ border-radius: 50%;
+ bottom: 100px;
+ height: 100px;
+ position: relative;
+ width: 100px;
+ }
+ </style>
+
+ <p>Test passes if there is a filled green circle and <strong>no red</strong>.
+
+ <div id="red-container-circle"><img src="support/swatch-red.png" width="100" height="175" alt="Image download support must be enabled"></div>
+
+ <div id="green-overlapping-reference"></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-017.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-017.html
new file mode 100644
index 0000000000..a6f427516e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-017.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' and clipping at padding edge (generated ::before content)</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="reference/contain-paint-clip-015-ref.html">
+
+ <meta content="This test checks that the paint containment of an element clips at its padding edge. In this test, the generated element (a red square image) is located outside the content edge, into what would have been the padding belt of the element." name="assert">
+
+ <!--
+
+ contain-paint-clip-011: content overflows horizontally, principal box has no padding
+
+ contain-paint-clip-012: content overflows vertically, principal box has no padding
+
+ contain-paint-clip-013: content overflows horizontally, principal box has horizontal padding
+
+ contain-paint-clip-014: content overflows vertically, principal box has vertical padding
+
+ contain-paint-clip-015: content overflow horizontally, principal box has horizontal padding and corner clipping is involved
+
+ contain-paint-clip-016: content overflow vertically, principal box has vertical padding and corner clipping is involved
+
+ contain-paint-clip-017: principal box has horizontal and vertical padding, generated ::before content is inside top-right corner
+
+ contain-paint-clip-018: principal box has horizontal and vertical padding, generated ::after content is inside top-left corner
+
+ -->
+
+
+ <style>
+ div
+ {
+ background-color: green;
+ border-radius: 100px;
+ contain: paint;
+ height: 50px;
+ padding: 25px;
+ width: 50px;
+ }
+
+ div::before
+ {
+ background-color: red;
+ content: "";
+ display: block;
+ height: 18px;
+ margin-left: 61px;
+ margin-top: -28px;
+ width: 18px;
+ }
+ </style>
+
+ <p>Test passes if there is a filled green circle and <strong>no red</strong>.
+
+ <div></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-018.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-018.html
new file mode 100644
index 0000000000..5b36a06e17
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-018.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' and clipping at padding edge (generated ::after content)</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="reference/contain-paint-clip-015-ref.html">
+
+ <meta content="This test checks that the paint containment of an element clips at its padding edge. In this test, the generated element (a red square image) is located outside the content edge, into what would have been the padding belt of the element." name="assert">
+
+ <!--
+
+ contain-paint-clip-011: content overflows horizontally, principal box has no padding
+
+ contain-paint-clip-012: content overflows vertically, principal box has no padding
+
+ contain-paint-clip-013: content overflows horizontally, principal box has horizontal padding
+
+ contain-paint-clip-014: content overflows vertically, principal box has vertical padding
+
+ contain-paint-clip-015: content overflow horizontally, principal box has horizontal padding and corner clipping is involved
+
+ contain-paint-clip-016: content overflow vertically, principal box has vertical padding and corner clipping is involved
+
+ contain-paint-clip-017: principal box has horizontal and vertical padding, generated ::before content is inside top-right corner
+
+ contain-paint-clip-018: principal box has horizontal and vertical padding, generated ::after content is inside top-left corner
+
+ -->
+
+
+ <style>
+ div
+ {
+ background-color: green;
+ border-radius: 100px;
+ contain: paint;
+ height: 50px;
+ padding: 25px;
+ width: 50px;
+ }
+
+ div::after
+ {
+ background-color: red;
+ content: "";
+ display: block;
+ height: 18px;
+ margin-left: -29px;
+ margin-top: -28px;
+ width: 18px;
+ }
+ </style>
+
+ <p>Test passes if there is a filled green circle and <strong>no red</strong>.
+
+ <div></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-clip-019.html b/testing/web-platform/tests/css/css-contain/contain-paint-clip-019.html
new file mode 100644
index 0000000000..34b12642db
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-clip-019.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+
+<meta charset="UTF-8">
+
+<title>CSS Containment Test: 'contain: paint' and clipping prevents scrollbars</title>
+
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+<link rel="match" href="reference/contain-paint-clip-019-ref.html">
+
+<meta content="This test checks that the paint containment of an element clips contents.
+ It should also prevent layout overflow from being propagated to ancestors." name="assert">
+
+<style>
+ #container {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ }
+ #green {
+ background-color: green;
+ width: 100px;
+ height: 100px;
+ }
+ #red {
+ background-color: red;
+ width: 100px;
+ height: 10000px;
+ }
+</style>
+
+<p>Test passes if there there is a green square. No red and no scrollbars should be visible.</p>
+
+<div id="container">
+ <div id="green"></div>
+ <div id="red"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-containing-block-absolute-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-containing-block-absolute-001-ref.html
new file mode 100644
index 0000000000..8861d19f88
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-containing-block-absolute-001-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <style>
+ #a {
+ width: 100px;
+ height: 100px;
+ background: green;
+ margin: 50px;
+ }
+ </style>
+</head>
+<body>
+ <div id="a"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-containing-block-absolute-001.html b/testing/web-platform/tests/css/css-contain/contain-paint-containing-block-absolute-001.html
new file mode 100644
index 0000000000..dd46c313db
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-containing-block-absolute-001.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: paint' element should contain absolute position elements.</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-containing-block-absolute-001-ref.html">
+ <style>
+ #a {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ background: red;
+ margin: 50px;
+ }
+ #b {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ </style>
+</head>
+<body>
+ <div id="a">
+ <div>
+ <div id="b"></div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-containing-block-fixed-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-containing-block-fixed-001-ref.html
new file mode 100644
index 0000000000..8861d19f88
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-containing-block-fixed-001-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <style>
+ #a {
+ width: 100px;
+ height: 100px;
+ background: green;
+ margin: 50px;
+ }
+ </style>
+</head>
+<body>
+ <div id="a"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-containing-block-fixed-001.html b/testing/web-platform/tests/css/css-contain/contain-paint-containing-block-fixed-001.html
new file mode 100644
index 0000000000..6fa52a5eb4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-containing-block-fixed-001.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: paint' element should contain fixed position elements.</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-containing-block-fixed-001-ref.html">
+ <style>
+ #a {
+ contain: paint;
+ width: 100px;
+ height: 100px;
+ background: red;
+ margin: 50px;
+ }
+ #b {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ </style>
+</head>
+<body>
+ <div id="a">
+ <div>
+ <div id="b"></div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-001.html b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-001.html
new file mode 100644
index 0000000000..899b5643c1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-001.html
@@ -0,0 +1,199 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Dynamic change to paint containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1765615">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta name="assert" content="Verify paint containment is properly updated after dynamic change to the contain property.">
+<style>
+ /* Selectors for contain */
+ #none .wrapper {
+ contain: none;
+ }
+ #paint .wrapper {
+ contain: paint;
+ }
+ #none_to_paint .wrapper {
+ contain: none;
+ }
+ #paint_to_none .wrapper {
+ contain: paint;
+ }
+
+ /* Selectors for testing absolute/fixed positioned elements */
+ #top_spacer {
+ height: 100px;
+ background: lightgray;
+ }
+ .absolute_pos {
+ position: absolute;
+ top: 42px;
+ }
+ .fixed_pos {
+ position: fixed;
+ top: 42px;
+ }
+
+ /* Selectors for testing IFC (floats) */
+ .floatleft {
+ float: left;
+ }
+ .clearleft {
+ clear: left;
+ }
+
+ /* Selectors for testing IFC (margin collapsing) */
+ .blockmargin {
+ margin: 25px 0;
+ }
+ .wrapper.blockmargin {
+ background: lightgray;
+ }
+
+ .rect {
+ background: black;
+ width: 50px;
+ height: 100px;
+ }
+</style>
+<body>
+ <div id="log"></div>
+
+ <div id="top_spacer"></div>
+
+ <div id="none">
+ <div class="wrapper">
+ <div class="absolute_pos"></div>
+ <div class="fixed_pos"></div>
+ </div>
+ <div>
+ <div class="floatleft rect"></div>
+ <div class="wrapper">
+ <div class="clearleft rect"></div>
+ </div>
+ </div>
+ <div>
+ <div class="wrapper blockmargin">
+ <div class="rect blockmargin"></div>
+ </div>
+ </div>
+ </div>
+
+ <div id="paint">
+ <div class="wrapper">
+ <div class="absolute_pos"></div>
+ <div class="fixed_pos"></div>
+ </div>
+ <div>
+ <div class="floatleft rect"></div>
+ <div class="wrapper">
+ <div class="clearleft rect"></div>
+ </div>
+ </div>
+ <div>
+ <div class="wrapper blockmargin">
+ <div class="rect blockmargin"></div>
+ </div>
+ </div>
+ </div>
+
+ <div id="none_to_paint">
+ <div class="wrapper">
+ <div class="absolute_pos"></div>
+ <div class="fixed_pos"></div>
+ </div>
+ <div>
+ <div class="floatleft rect"></div>
+ <div class="wrapper">
+ <div class="clearleft rect"></div>
+ </div>
+ </div>
+ <div>
+ <div class="wrapper blockmargin">
+ <div class="rect blockmargin"></div>
+ </div>
+ </div>
+ </div>
+
+ <div id="paint_to_none">
+ <div class="wrapper">
+ <div class="absolute_pos"></div>
+ <div class="fixed_pos"></div>
+ </div>
+ <div>
+ <div class="floatleft rect"></div>
+ <div class="wrapper">
+ <div class="clearleft rect"></div>
+ </div>
+ </div>
+ <div>
+ <div class="wrapper blockmargin">
+ <div class="rect blockmargin"></div>
+ </div>
+ </div>
+ </div>
+
+ <script>
+ function verifyPaintContainment(id, applied) {
+ let container = document.getElementById(id);
+ let wrappers = container.getElementsByClassName("wrapper");
+
+ // To verify the containment box establishes an absolute positioning
+ // containing block and a fixed positioning containing block, we test
+ // positions of absolutely/fixed positioned children (a bit below the
+ // containment box rather than a bit below the top of the viewport).
+ let containingBlockTop = wrappers[0].getBoundingClientRect().top;
+ let absTop = container.getElementsByClassName("absolute_pos")[0]
+ .getBoundingClientRect().top;
+ assert_equals(absTop > containingBlockTop, applied, "absolute positioning containing block");
+ let fixedTop = container.getElementsByClassName("fixed_pos")[0]
+ .getBoundingClientRect().top;
+ assert_equals(fixedTop > containingBlockTop, applied, "fixed positioning containing block");
+
+ // To verify the containment box establishes an independent formatting
+ // context, we test position the clear: left div with respect to the
+ // float: left div.
+ let floatLeft = wrappers[1].previousElementSibling;
+ let clearLeft = wrappers[1].firstElementChild;
+ let clearNextToFloat = Math.abs(floatLeft.getBoundingClientRect().top - clearLeft.getBoundingClientRect().top) <= 1;
+ assert_equals(clearNextToFloat, applied, "independent formatting context");
+
+ // In addition, we verify that the margin inside the containment box
+ // are not collapsed.
+ let IFCWithMargin = wrappers[2];
+ let childWithMargin = IFCWithMargin.firstElementChild;
+ let marginCollapsed = Math.abs(IFCWithMargin.getBoundingClientRect().height - childWithMargin.getBoundingClientRect().height) <= 1;
+ assert_equals(!marginCollapsed, applied, "independent formatting context (margins collapsing)");
+ }
+
+ function setContain(id, value) {
+ let container = document.getElementById(id);
+ Array.from(container.getElementsByClassName("wrapper"))
+ .forEach(element => element.style.contain = value);
+ }
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ verifyPaintContainment("none", /* applied=*/false);
+ }, "contain: none");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ verifyPaintContainment("paint", /* applied=*/true);
+ }, "contain: paint");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ setContain("none_to_paint", "paint");
+ verifyPaintContainment("none_to_paint", /* applied=*/true)
+ }, "switching contain from none to paint");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ setContain("paint_to_none", "none");
+ verifyPaintContainment("paint_to_none", /* applied=*/false);
+ }, "switching contain from paint to none");
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-002-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-002-ref.html
new file mode 100644
index 0000000000..58473c8649
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-002-ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<title>Dynamic change to paint containment (reference)</title>
+
+<style>
+ #container {
+ width: 100px;
+ height: 100px;
+ background: green;
+ contain: paint;
+ }
+ #overflowing {
+ width: 400px;
+ height: 100px;
+ }
+ .square {
+ display: inline-block;
+ width: 50px;
+ height: 50px;
+ margin: 5px;
+ }
+ .red {
+ background: red;
+ }
+</style>
+
+<body>
+ <p>PASS if you see a green square and no red.</p>
+ <div id="container">
+ <div id="overflowing"><div class="square"></div><div class="square"></div><div class="red square"></div></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-002.html b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-002.html
new file mode 100644
index 0000000000..0096e83d5b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-002.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>Dynamic change to paint containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1765615">
+<meta name="assert" content="Verify paint containment is properly updated after dynamic change to the contain property.">
+<link rel="match" href="contain-paint-dynamic-002-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+
+<style>
+ #container {
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ #overflowing {
+ width: 400px;
+ height: 100px;
+ }
+ .square {
+ display: inline-block;
+ width: 50px;
+ height: 50px;
+ margin: 5px;
+ }
+ .red {
+ background: red;
+ }
+</style>
+
+<body>
+ <p>PASS if you see a green square and no red.</p>
+ <div id="container">
+ <div id="overflowing"><div class="square"></div><div class="square"></div><div class="red square"></div></div>
+ </div>
+ <script>
+ window.addEventListener("TestRendered", async () => {
+ container.style.contain = "paint";
+ await waitForAtLeastOneFrame();
+ takeScreenshot();
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-003-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-003-ref.html
new file mode 100644
index 0000000000..b30f32d9c3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-003-ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<title>Dynamic change to paint containment (reference)</title>
+
+<style>
+ #container {
+ width: 100px;
+ height: 100px;
+ background: green;
+ contain: none;
+ }
+ #overflowing {
+ width: 400px;
+ height: 100px;
+ }
+ .square {
+ display: inline-block;
+ width: 50px;
+ height: 50px;
+ margin: 5px;
+ }
+ .green {
+ background: green;
+ }
+</style>
+
+<body>
+ <p>PASS if you see <em>two</em> green squares.</p>
+ <div id="container">
+ <div id="overflowing"><div class="square"></div><div class="square"></div><div class="red square"></div></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-003.html b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-003.html
new file mode 100644
index 0000000000..e7fcbac0e6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-003.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>Dynamic change to paint containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1765615">
+<meta name="assert" content="Verify paint containment is properly updated after dynamic change to the contain property.">
+<link rel="match" href="contain-paint-dynamic-003-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+
+<style>
+ #container {
+ width: 100px;
+ height: 100px;
+ background: green;
+ contain: paint;
+ }
+ #overflowing {
+ width: 400px;
+ height: 100px;
+ }
+ .square {
+ display: inline-block;
+ width: 50px;
+ height: 50px;
+ margin: 5px;
+ }
+ .green {
+ background: green;
+ }
+</style>
+
+<body>
+ <p>PASS if you see <em>two</em> green squares.</p>
+ <div id="container">
+ <div id="overflowing"><div class="square"></div><div class="square"></div><div class="red square"></div></div>
+ </div>
+ <script>
+ window.addEventListener("TestRendered", async () => {
+ container.style.contain = "none";
+ await waitForAtLeastOneFrame();
+ takeScreenshot();
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-004-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-004-ref.html
new file mode 100644
index 0000000000..02f3d94ee9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-004-ref.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<title>Dynamic change to paint containment (reference)</title>
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+
+<style>
+ div {
+ font: 25px/1 Ahem;
+ }
+ #wrapper {
+ width: 15em;
+ background: lightgray;
+ }
+ .containment {
+ contain: paint;
+ }
+ .float {
+ box-sizing: border-box;
+ border: 1px solid black;
+ }
+ .left {
+ float: left;
+ width: 1em;
+ height: 2em;
+ }
+ .right {
+ float: right;
+ width: 1em;
+ height: 3em;
+ }
+</style>
+
+<body>
+ <p>PASS if the boxes with dark colors are NOT floating next to the boxes with
+ light colors.</p>
+ <div id="wrapper">
+ <div>
+ <div id="container" class="containment">
+ <div><div class="float left" style="background: lightblue"></div></div>
+ <div class="float right" style="background: lightyellow"></div>
+ <div>XX XXX XXXX X</div>
+ </div>
+ <div class="float left" style="background: blue"></div>
+ <div>
+ <div>
+ <div><div class="float right" style="background: yellow"></div></div>
+ <div>XXX XXXXXX XXXX XX XX</div>
+ </div>
+ <div>XXXX XXXXX XX</div>
+ </div>
+ <div>XXX XXX XX XXXX</div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-004.html b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-004.html
new file mode 100644
index 0000000000..8e286db8b1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-004.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>Dynamic change to paint containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1874826">
+<meta name="assert" content="Verify floats are properly displayed after dynamic change to paint containment.">
+<link rel="match" href="contain-paint-dynamic-004-ref.html">
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+
+<style>
+ div {
+ font: 25px/1 Ahem;
+ }
+ #wrapper {
+ width: 15em;
+ background: lightgray;
+ }
+ .containment {
+ contain: paint;
+ }
+ .float {
+ box-sizing: border-box;
+ border: 1px solid black;
+ }
+ .left {
+ float: left;
+ width: 1em;
+ height: 2em;
+ }
+ .right {
+ float: right;
+ width: 1em;
+ height: 3em;
+ }
+</style>
+
+<body>
+ <p>PASS if the boxes with dark colors are NOT floating next to the boxes with
+ light colors.</p>
+ <div id="wrapper">
+ <div>
+ <div id="container">
+ <div><div class="float left" style="background: lightblue"></div></div>
+ <div class="float right" style="background: lightyellow"></div>
+ <div>XX XXX XXXX X</div>
+ </div>
+ <div class="float left" style="background: blue"></div>
+ <div>
+ <div>
+ <div><div class="float right" style="background: yellow"></div></div>
+ <div>XXX XXXXXX XXXX XX XX</div>
+ </div>
+ <div>XXXX XXXXX XX</div>
+ </div>
+ <div>XXX XXX XX XXXX</div>
+ </div>
+ </div>
+ <script>
+ window.addEventListener("load", async () => {
+ container.classList.add('containment');
+ await waitForAtLeastOneFrame();
+ takeScreenshot();
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-005-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-005-ref.html
new file mode 100644
index 0000000000..1d1ce904fc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-005-ref.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<title>Dynamic change to paint containment (reference)</title>
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+
+<style>
+ div {
+ font: 25px/1 Ahem;
+ }
+ #wrapper {
+ width: 15em;
+ background: lightgray;
+ }
+ .containment {
+ contain: paint;
+ }
+ .float {
+ box-sizing: border-box;
+ border: 1px solid black;
+ }
+ .left {
+ float: left;
+ width: 1em;
+ height: 2em;
+ }
+ .right {
+ float: right;
+ width: 1em;
+ height: 3em;
+ }
+</style>
+
+<body>
+ <p>PASS if the boxes with dark colors are floating next to the boxes with
+ light colors.</p>
+ <div id="wrapper">
+ <div>
+ <div id="container">
+ <div><div class="float left" style="background: lightblue"></div></div>
+ <div class="float right" style="background: lightyellow"></div>
+ <div>XX XXX XXXX X</div>
+ </div>
+ <div class="float left" style="background: blue"></div>
+ <div>
+ <div>
+ <div><div class="float right" style="background: yellow"></div></div>
+ <div>XXX XXXXXX XXXX XX XX</div>
+ </div>
+ <div>XXXX XXXXX XX</div>
+ </div>
+ <div>XXX XXX XX XXXX</div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-005.html b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-005.html
new file mode 100644
index 0000000000..bedac635ce
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-dynamic-005.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>Dynamic change to paint containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1874826">
+<meta name="assert" content="Verify floats are properly displayed after dynamic change to paint containment.">
+<link rel="match" href="contain-paint-dynamic-005-ref.html">
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+
+<style>
+ div {
+ font: 25px/1 Ahem;
+ }
+ #wrapper {
+ width: 15em;
+ background: lightgray;
+ }
+ .containment {
+ contain: paint;
+ }
+ .float {
+ box-sizing: border-box;
+ border: 1px solid black;
+ }
+ .left {
+ float: left;
+ width: 1em;
+ height: 2em;
+ }
+ .right {
+ float: right;
+ width: 1em;
+ height: 3em;
+ }
+</style>
+
+<body>
+ <p>PASS if the boxes with dark colors are floating next to the boxes with
+ light colors.</p>
+ <div id="wrapper">
+ <div>
+ <div id="container" class="containment">
+ <div><div class="float left" style="background: lightblue"></div></div>
+ <div class="float right" style="background: lightyellow"></div>
+ <div>XX XXX XXXX X</div>
+ </div>
+ <div class="float left" style="background: blue"></div>
+ <div>
+ <div>
+ <div><div class="float right" style="background: yellow"></div></div>
+ <div>XXX XXXXXX XXXX XX XX</div>
+ </div>
+ <div>XXXX XXXXX XX</div>
+ </div>
+ <div>XXX XXX XX XXXX</div>
+ </div>
+ </div>
+ <script>
+ window.addEventListener("load", async () => {
+ container.classList.remove('containment');
+ await waitForAtLeastOneFrame();
+ takeScreenshot();
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-formatting-context-float-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-formatting-context-float-001-ref.html
new file mode 100644
index 0000000000..ceff7f4569
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-formatting-context-float-001-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <style>
+ #left {
+ float: left;
+ height: 50px;
+ width: 10px;
+ background: blue;
+ }
+ #a {
+ background: green;
+ margin: 10px;
+ width: 50px;
+ height: 50px;
+ }
+ </style>
+</head>
+<body>
+ <div id="left"></div>
+ <div id="a"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-formatting-context-float-001.html b/testing/web-platform/tests/css/css-contain/contain-paint-formatting-context-float-001.html
new file mode 100644
index 0000000000..95242072b1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-formatting-context-float-001.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: paint' should contain floats as a formatting context.</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-formatting-context-float-001-ref.html">
+ <style>
+ #left {
+ float: left;
+ height: 50px;
+ width: 10px;
+ background: blue;
+ }
+ #a {
+ contain: paint;
+ background: red;
+ margin: 10px;
+ width: 50px;
+ height: 50px;
+ }
+ #b {
+ clear: left;
+ width: 50px;
+ height: 50px;
+ background: green;
+ }
+ </style>
+</head>
+<body>
+ <div id="left"></div>
+ <div id="a">
+ <div id="b"></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-formatting-context-margin-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-formatting-context-margin-001-ref.html
new file mode 100644
index 0000000000..1976f71bf5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-formatting-context-margin-001-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Test</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <style>
+ #a {
+ background: blue;
+ margin: 10px;
+ width: 50px;
+ height: 50px;
+ }
+ #b {
+ width: 50px;
+ height: 40px;
+ background: green;
+ }
+ #b-padding {
+ height: 10px;
+ }
+ </style>
+</head>
+<body>
+ <div id="a">
+ <div id="b-padding"></div>
+ <div id="b"></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-formatting-context-margin-001.html b/testing/web-platform/tests/css/css-contain/contain-paint-formatting-context-margin-001.html
new file mode 100644
index 0000000000..ebf88866a9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-formatting-context-margin-001.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: paint' with a vertical margin child. Margin collapse should not occur.</title>
+ <link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-formatting-context-margin-001-ref.html">
+ <style>
+ #a {
+ contain: paint;
+ background: blue;
+ margin: 10px;
+ width: 50px;
+ height: 50px;
+ }
+ #b {
+ width: 50px;
+ height: 40px;
+ background: green;
+ margin-top: 10px;
+ }
+ #c {
+ background: red;
+ width: 50px;
+ height: 10px;
+ }
+ </style>
+</head>
+<body>
+ <div id="a">
+ <div id="b"></div>
+ <div id="c"></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-ifc-011.html b/testing/web-platform/tests/css/css-contain/contain-paint-ifc-011.html
new file mode 100644
index 0000000000..992a0377ad
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-ifc-011.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' and margin collapsing</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="reference/contain-paint-ifc-011-ref.html">
+
+ <meta content="This test checks that a block element with 'contain: paint' establishes a new block formatting context which is independent and separate from others. This causes margin collapsing to be ineffective among vertically-adjacent boxes. In this test, the top margin of parent boxes and top margin of their respective first in-flow child do not collapse. Also, in this test, the bottom margin of the last in-flow child of boxes and bottom margin of their respective parent boxes do not collapse." name="assert">
+
+ <style>
+ div
+ {
+ contain: paint;
+ margin: 30px 0px;
+ }
+
+ div#grand-grand-parent-orange
+ {
+ background-color: orange;
+ }
+
+ div#grand-parent-blue
+ {
+ background-color: blue;
+ }
+
+ div#parent-lime
+ {
+ background-color: lime;
+ }
+
+ div#collapse-through-child /* margin collapsing through element */
+ {
+ contain: none;
+ }
+ </style>
+
+ <p>Test passes if there are 5 horizontal stripes across the page in this order (from top to bottom): an orange stripe, a blue stripe, a bright green stripe, a blue stripe and then an orange stripe.
+
+ <div id="grand-grand-parent-orange">
+
+ <div id="grand-parent-blue">
+
+ <div id="parent-lime">
+
+ <div id="collapse-through-child"></div>
+
+ </div>
+
+ </div>
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ib-split-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ib-split-001-ref.html
new file mode 100644
index 0000000000..8a698b9d2c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ib-split-001-ref.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <style>
+ .abspos-box {
+ position: absolute;
+ width: 200px;
+ height: 200px;
+ }
+
+ /* The boxes should stack in the order that I've listed their CSS classes
+ here. The class names' first word (outside/before/inside/after) refers
+ to the boxes' DOM position, and "background"/"midground"/"foreground"
+ refers to their z-index values. */
+
+ .before-IB-background {
+ background: darkmagenta;
+ z-index: -1;
+ top: 50px;
+ left: 50px;
+ }
+ .after-IB-background {
+ background: magenta;
+ z-index: -1;
+ top: 70px;
+ left: 70px;
+ }
+ .outside-span-midground {
+ background: darkkhaki;
+ top: 90px;
+ left: 90px;
+ }
+ .inside-IB-midground {
+ background: khaki;
+ top: 110px;
+ left: 110px;
+ }
+ .before-IB-foreground {
+ background: darkcyan;
+ z-index: 1;
+ top: 130px;
+ left: 130px;
+ }
+ .after-IB-foreground {
+ background: cyan;
+ z-index: 1;
+ top: 150px;
+ left: 150px;
+ }
+ </style>
+</head>
+<body>
+ <!-- The expectation here is that 'abspos-box' elements will all interact in
+ the same top-level stacking context. That means the box ordering should
+ be (back to front): darkmagenta/magenta/darkkhaki/khaki/darkcyan/cyan,
+ with the boxes stacked (visually) from top-left to bottom-right. -->
+
+ <div class="abspos-box outside-span-midground"></div>
+
+ <!-- Note: this file is identical to the testcase,
+ except for the lack of "contain: paint" on this span. -->
+ <span>
+ <div class="abspos-box before-IB-background"></div>
+ <div class="abspos-box before-IB-foreground"></div>
+ <!-- This unstyled div crates the IB split: -->
+ <div>
+ <div class="abspos-box inside-IB-midground"></div>
+ </div>
+ <div class="abspos-box after-IB-background"></div>
+ <div class="abspos-box after-IB-foreground"></div>
+ </span>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ib-split-001.html b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ib-split-001.html
new file mode 100644
index 0000000000..eb21a2d460
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ib-split-001.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: paint' should have no effect on non-atomic inline
+ (including its block part, if there's a block-in-inline split)</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-ignored-cases-ib-split-001-ref.html">
+ <style>
+ .abspos-box {
+ position: absolute;
+ width: 200px;
+ height: 200px;
+ }
+
+ /* The boxes should stack in the order that I've listed their CSS classes
+ here. The class names' first word (outside/before/inside/after) refers
+ to the boxes' DOM position, and "background"/"midground"/"foreground"
+ refers to their z-index values. */
+
+ .before-IB-background {
+ background: darkmagenta;
+ z-index: -1;
+ top: 50px;
+ left: 50px;
+ }
+ .after-IB-background {
+ background: magenta;
+ z-index: -1;
+ top: 70px;
+ left: 70px;
+ }
+ .outside-span-midground {
+ background: darkkhaki;
+ top: 90px;
+ left: 90px;
+ }
+ .inside-IB-midground {
+ background: khaki;
+ top: 110px;
+ left: 110px;
+ }
+ .before-IB-foreground {
+ background: darkcyan;
+ z-index: 1;
+ top: 130px;
+ left: 130px;
+ }
+ .after-IB-foreground {
+ background: cyan;
+ z-index: 1;
+ top: 150px;
+ left: 150px;
+ }
+ </style>
+</head>
+<body>
+ <!-- The expectation here is that 'abspos-box' elements will all interact in
+ the same top-level stacking context. That means the box ordering should
+ be (back to front): darkmagenta/magenta/darkkhaki/khaki/darkcyan/cyan,
+ with the boxes stacked (visually) from top-left to bottom-right. -->
+
+ <div class="abspos-box outside-span-midground"></div>
+
+ <span style="contain: paint">
+ <div class="abspos-box before-IB-background"></div>
+ <div class="abspos-box before-IB-foreground"></div>
+ <!-- This unstyled div crates the IB split: -->
+ <div>
+ <div class="abspos-box inside-IB-midground"></div>
+ </div>
+ <div class="abspos-box after-IB-background"></div>
+ <div class="abspos-box after-IB-foreground"></div>
+ </span>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-internal-table-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-internal-table-001-ref.html
new file mode 100644
index 0000000000..d23678941e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-internal-table-001-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset=utf-8>
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <style>
+ tr {
+ z-index: 10;
+ }
+ th {
+ background-color: blue;
+ padding-left: 50px;
+ }
+ caption {
+ position: fixed;
+ background-color: yellow;
+ z-index: 2;
+ }
+ </style>
+ </head>
+ <body>
+ <table>
+ <caption>PASS</caption>
+ <tr>
+ <th>&emsp;</th>
+ </tr>
+ </table>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-internal-table-001a.html b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-internal-table-001a.html
new file mode 100644
index 0000000000..6e3bdbd273
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-internal-table-001a.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on internal table elements except table-cell.</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-ignored-cases-internal-table-001-ref.html">
+ <meta name="assert" content="Paint containment should not apply to internal table elements except table-cell. This test testes only the tr element, and confirms contain:paint does not create a stacking context.">
+ <style>
+ tr {
+ contain: paint;
+ z-index: 10;
+ }
+ th {
+ background-color: blue;
+ padding-left: 50px;
+ }
+ caption {
+ position: fixed;
+ background-color: yellow;
+ z-index: 2;
+ }
+ </style>
+ </head>
+ <body>
+ <table>
+ <caption>PASS</caption>
+ <tr>
+ <th>&emsp;</th>
+ </tr>
+ </table>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-internal-table-001b.html b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-internal-table-001b.html
new file mode 100644
index 0000000000..e531eb6ca3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-internal-table-001b.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on internal table elements except table-cell.</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-ignored-cases-internal-table-001-ref.html">
+ <meta name="assert" content="Paint containment should not apply to internal table elements except table-cell. This test testes only the tbody element, and confirms contain:paint does not create a stacking context.">
+ <style>
+ tbody {
+ contain: paint;
+ z-index: 10;
+ }
+ th {
+ background-color: blue;
+ padding-left: 50px;
+ }
+ caption {
+ position: fixed;
+ background-color: yellow;
+ z-index: 2;
+ }
+ </style>
+ </head>
+ <body>
+ <table>
+ <caption>PASS</caption>
+ <tbody>
+ <tr>
+ <th>&emsp;</th>
+ </tr>
+ </tbody>
+ </table>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-no-principal-box-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-no-principal-box-001-ref.html
new file mode 100644
index 0000000000..b4513709e5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-no-principal-box-001-ref.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <style>
+ div {
+ position: relative;
+ width: 100px;
+ }
+ #div1,
+ #div3 {
+ background-color: #cfc;
+ height: 100px;
+ }
+ #div1 {
+ z-index: 5;
+ }
+ #div2 {
+ display: contents;
+ background-color: #fdd;
+ height: 100px;
+ top: -20px;
+ }
+ #div2_1 {
+ background-color: #ffc;
+ z-index: 6;
+ top: -10px;
+ height: 100px;
+ }
+ #div2_2 {
+ z-index: 3;
+ position: absolute;
+ top: -15px;
+ width: 40px;
+ height: 300px;
+ background-color: #ddf;
+ }
+ #div3 {
+ z-index: 2;
+ top: -50px;
+ }
+ </style>
+</head>
+<body>
+ <div id="div1"></div>
+
+ <div id="div2">
+ <div id="div2_1"></div>
+
+ <div id="div2_2"></div>
+ </div>
+
+ <div id="div3"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-no-principal-box-001.html b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-no-principal-box-001.html
new file mode 100644
index 0000000000..4b9c907209
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-no-principal-box-001.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: paint' with 'display: contents'.</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-ignored-cases-no-principal-box-001-ref.html">
+ <meta name="assert" content="Contain:paint should have no effect when no principle box is generated.">
+ <style>
+ div {
+ position: relative;
+ width: 100px;
+ }
+ #div1,
+ #div3 {
+ background-color: #cfc;
+ height: 100px;
+ }
+ #div1 {
+ z-index: 5;
+ }
+ #div2 {
+ display: contents;
+ contain: paint;
+ background-color: #fdd;
+ height: 100px;
+ top: -20px;
+ }
+ #div2_1 {
+ background-color: #ffc;
+ z-index: 6;
+ top: -10px;
+ height: 100px;
+ }
+ #div2_2 {
+ z-index: 3;
+ position: absolute;
+ top: -15px;
+ width: 40px;
+ height: 300px;
+ background-color: #ddf;
+ }
+ #div3 {
+ z-index: 2;
+ top: -50px;
+ }
+ </style>
+</head>
+<body>
+ <div id="div1"></div>
+
+ <div id="div2">
+ <div id="div2_1"></div>
+
+ <div id="div2_2"></div>
+ </div>
+
+ <div id="div3"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ruby-containing-block-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ruby-containing-block-001-ref.html
new file mode 100644
index 0000000000..5df0b24629
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ruby-containing-block-001-ref.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<html lang=en>
+ <head>
+ <meta charset=utf-8>
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <style>
+ rb,
+ rbc,
+ rt,
+ rtc {
+ background-color: yellow;
+ font-size: 2em;
+ }
+ rbc {
+ display: ruby-base-container;
+ }
+ .contained {
+ width: 50px;
+ height: 10px;
+ background-color: blue;
+ top: 0;
+ left: 0;
+ position: fixed;
+ }
+ .wrapper {
+ display: inline-block;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="wrapper"><ruby><rt>&emsp;<div class="contained"></div></rt></ruby></div>
+ <div class="wrapper"><ruby><rtc>&emsp;<div class="contained"></div></rtc></ruby></div>
+ <div class="wrapper"><ruby><rb>&emsp;<div class="contained"></div></rb></ruby></div>
+ <div class="wrapper"><ruby><rbc>&emsp;<div class="contained"></div></rbc></ruby></div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ruby-containing-block-001.html b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ruby-containing-block-001.html
new file mode 100644
index 0000000000..08fa9555a6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ruby-containing-block-001.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<html lang=en>
+ <head>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on internal ruby elements.</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-ignored-cases-ruby-containing-block-001-ref.html">
+ <meta name="assert" content="Paint containment should not apply to ruby base, ruby base container, ruby text, and ruby text container. This test confirms contain:paint does not act as a containing block for fixed positioned descendants.">
+ <style>
+ rb,
+ rbc,
+ rt,
+ rtc {
+ contain: paint;
+ background-color: yellow;
+ font-size: 2em;
+ }
+ rbc {
+ display: ruby-base-container;
+ }
+ .contained {
+ width: 50px;
+ height: 10px;
+ background-color: blue;
+ top: 0;
+ left: 0;
+ position: fixed;
+ }
+ .wrapper {
+ display: inline-block;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="wrapper"><ruby><rt>&emsp;<div class="contained"></div></rt></ruby></div>
+ <div class="wrapper"><ruby><rtc>&emsp;<div class="contained"></div></rtc></ruby></div>
+ <div class="wrapper"><ruby><rb>&emsp;<div class="contained"></div></rb></ruby></div>
+ <div class="wrapper"><ruby><rbc>&emsp;<div class="contained"></div></rbc></ruby></div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ruby-stacking-and-clipping-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ruby-stacking-and-clipping-001-ref.html
new file mode 100644
index 0000000000..02f7a40665
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ruby-stacking-and-clipping-001-ref.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<html lang=en>
+ <head>
+ <meta charset=utf-8>
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <style>
+ div {
+ position: relative;
+ }
+ rbc {
+ display: ruby-base-container;
+ }
+ .contained {
+ z-index: 5;
+ width: 70px;
+ height: 10px;
+ background-color: blue;
+ margin-left: -25px;
+ }
+ .background {
+ display: inline-block;
+ background-color: yellow;
+ height: 50px;
+ width: 50px;
+ position: fixed;
+ z-index: 2;
+ }
+ .group {
+ display: inline-block;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="group">
+ <div class="background"></div>
+ <ruby><rb>&emsp;<div class="contained"></div></rb></ruby>
+ </div>
+ <div class="group">
+ <div class="background"></div>
+ <ruby><rbc>&emsp;<div class="contained"></div></rbc></ruby>
+ </div>
+ <div class="group">
+ <div class="background"></div>
+ <ruby><rt>&emsp;<div class="contained"></div></rt></ruby>
+ </div>
+ <div class="group">
+ <div class="background"></div>
+ <ruby><rtc>&emsp;<div class="contained"></div></rtc></ruby>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ruby-stacking-and-clipping-001.html b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ruby-stacking-and-clipping-001.html
new file mode 100644
index 0000000000..756035518d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-ignored-cases-ruby-stacking-and-clipping-001.html
@@ -0,0 +1,60 @@
+<!doctype html>
+<html lang=en>
+ <head>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on internal ruby elements.</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-ignored-cases-ruby-stacking-and-clipping-001-ref.html">
+ <meta name="assert" content="Paint containment should not apply to ruby base, ruby base container, ruby text, and ruby text container. This test confirms that contain:paint does not create a stacking context and does not apply overflow clipping.">
+ <style>
+ div {
+ position: relative;
+ }
+ rb,
+ rbc,
+ rt,
+ rtc {
+ contain: paint;
+ }
+ rbc {
+ display: ruby-base-container;
+ }
+ .contained {
+ z-index: 5;
+ width: 70px;
+ height: 10px;
+ background-color: blue;
+ margin-left: -25px;
+ }
+ .background {
+ background-color: yellow;
+ height: 50px;
+ width: 50px;
+ position: fixed;
+ z-index: 2;
+ }
+ .group {
+ display: inline-block;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="group">
+ <div class="background"></div>
+ <ruby><rb>&emsp;<div class="contained"></div></rb></ruby>
+ </div>
+ <div class="group">
+ <div class="background"></div>
+ <ruby><rbc>&emsp;<div class="contained"></div></rbc></ruby>
+ </div>
+ <div class="group">
+ <div class="background"></div>
+ <ruby><rt>&emsp;<div class="contained"></div></rt></ruby>
+ </div>
+ <div class="group">
+ <div class="background"></div>
+ <ruby><rtc>&emsp;<div class="contained"></div></rtc></ruby>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-independent-formatting-context-001.html b/testing/web-platform/tests/css/css-contain/contain-paint-independent-formatting-context-001.html
new file mode 100644
index 0000000000..e4c06a992b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-independent-formatting-context-001.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment independent formatting context</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="reference/contain-paint-independent-formatting-context-001-ref.html">
+<meta name=assert content="Paint containment elements establish an independent formatting context. The test checks that this feature of paint containment applies to blocks.">
+<style>
+.wrapper {
+ border: solid thick;
+ margin: 1em;
+}
+</style>
+<p>Test passes if it has the same output than the reference.</p>
+<div class="wrapper">
+ <div style="margin: 1em 0; contain: paint;">
+ <div style="margin: 1em 0;">This text should have 2em top and bottom margins (margins do not collapse).</div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-independent-formatting-context-002.html b/testing/web-platform/tests/css/css-contain/contain-paint-independent-formatting-context-002.html
new file mode 100644
index 0000000000..353196970c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-independent-formatting-context-002.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment independent formatting context</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="reference/contain-paint-independent-formatting-context-001-ref.html">
+<meta name=assert content="Paint containment elements establish an independent formatting context. The test checks that this feature of paint containment applies to inline blocks.">
+<style>
+.wrapper {
+ border: solid thick;
+ margin: 1em;
+}
+</style>
+<p>Test passes if it has the same output than the reference.</p>
+<div class="wrapper">
+ <span style="display: inline-block; margin: 1em 0; contain: paint;">
+ <div style="margin: 1em 0;">This text should have 2em top and bottom margins (margins do not collapse).</div>
+ </span>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-independent-formatting-context-003.html b/testing/web-platform/tests/css/css-contain/contain-paint-independent-formatting-context-003.html
new file mode 100644
index 0000000000..fe1f7f2775
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-independent-formatting-context-003.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment independent formatting context</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="reference/contain-paint-independent-formatting-context-003-ref.html">
+<meta name=assert content="Paint containment elements establish an independent formatting context. The test checks that this feature of paint containment does not appliy to inline elements.">
+<style>
+.wrapper {
+ border: solid thick;
+ margin: 1em;
+}
+</style>
+<p>Test passes if it has the same output than the reference.</p>
+<div class="wrapper">
+ <span style="margin: 1em 0; contain: paint;">
+ <div style="margin: 1em 0;">This text should have 1em top and bottom margins.</div>
+ </span>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-size-001.html b/testing/web-platform/tests/css/css-contain/contain-paint-size-001.html
new file mode 100644
index 0000000000..2546b2b9aa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-size-001.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint size' and table caption</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+ <link rel="match" href="reference/contain-paint-size-001-ref.html">
+
+
+ <style>
+ table
+ {
+ table-layout: fixed;
+ width: 206px;
+ }
+
+ caption
+ {
+ background-color: red;
+ border: green solid 1em;
+ color: red;
+ contain: paint size;
+ font-size: 20px;
+ }
+ </style>
+
+ <p>Test passes if there is a short horizontal green stripe and <strong>no red</strong>.
+
+ <table>
+
+ <caption>FAIL FAIL FAIL FAIL FAIL FAIL</caption>
+
+ <tr><td>&nbsp;<td>&nbsp;
+
+ <tr><td>&nbsp;<td>&nbsp;
+
+ </table>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-size-002.html b/testing/web-platform/tests/css/css-contain/contain-paint-size-002.html
new file mode 100644
index 0000000000..18d03e7f52
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-size-002.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint size' and block box</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+ <link rel="match" href="reference/contain-paint-size-001-ref.html">
+
+
+ <style>
+ div
+ {
+ background-color: red;
+ border: green solid 1em;
+ color: red;
+ contain: paint size;
+ font-size: 20px;
+ width: 166px;
+ }
+ </style>
+
+ <p>Test passes if there is a short horizontal green stripe and <strong>no red</strong>.
+
+ <div>FAIL FAIL FAIL FAIL FAIL FAIL</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-size-003.html b/testing/web-platform/tests/css/css-contain/contain-paint-size-003.html
new file mode 100644
index 0000000000..2d21664065
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-size-003.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: a block with 'contain: paint size' alongside a float</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+ <link rel="match" href="reference/contain-layout-size-003-ref.html">
+
+
+ <style>
+ div
+ {
+ color: transparent;
+ font-size: 16px;
+ padding: 8px;
+ }
+
+ div#floated-left
+ {
+ background-color: blue;
+ float: left;
+ margin: 8px;
+ width: 6em;
+ }
+
+ div#with-contain-paint-size
+ {
+ background-color: orange;
+ width: 12em;
+
+ contain: paint size;
+ }
+ </style>
+
+ <p>Test passes if the orange rectangle and blue rectangle do not overlap.
+
+ <div id="floated-left">Some text in a blue rectangle.</div>
+
+ <div id="with-contain-paint-size">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore.</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-stacking-context-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-paint-stacking-context-001-ref.html
new file mode 100644
index 0000000000..c7553716ab
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-stacking-context-001-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+ <style>
+ div {
+ position: relative;
+ width: 100px;
+ }
+ #div1,
+ #div3 {
+ background-color: #cfc;
+ }
+ #div1 {
+ z-index: 5;
+ }
+ #div2 {
+ z-index: 1;
+ background-color: #fdd;
+ height: 100px;
+ top: -20px;
+ }
+ #div2_1 {
+ background-color: #ffc;
+ z-index: 6;
+ top: -10px;
+ }
+ #div2_2 {
+ z-index: 3;
+ position: absolute;
+ top: -15px;
+ width: 40px;
+ height: 100px;
+ background-color: #ddf;
+ }
+ #div3 {
+ z-index: 2;
+ top: -50px;
+ }
+ </style>
+</head>
+<body>
+ <div id="div1">
+ <br/><br/>
+ </div>
+
+ <div id="div2">
+ <div id="div2_1">
+ <br/><br/>
+ </div>
+
+ <div id="div2_2">
+ </div>
+ </div>
+
+ <div id="div3">
+ <br/><br/>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-stacking-context-001a.html b/testing/web-platform/tests/css/css-contain/contain-paint-stacking-context-001a.html
new file mode 100644
index 0000000000..71102b6c73
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-stacking-context-001a.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: paint' with stacking contents. Z-index is defined only for siblings and children.</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+
+ <link rel="help" href="https://drafts.csswg.org/css2/visuren.html#x43">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-stacking-context-001-ref.html">
+ <style>
+ div {
+ position: relative;
+ width: 100px;
+ }
+ #div1,
+ #div3 {
+ background-color: #cfc;
+ }
+ #div1 {
+ z-index: 5;
+ }
+ #div2 {
+ contain: paint;
+ background-color: #fdd;
+ height: 100px;
+ top: -20px;
+ }
+ #div2_1 {
+ background-color: #ffc;
+ z-index: 6;
+ top: -10px;
+ }
+ #div2_2 {
+ z-index: 3;
+ position: absolute;
+ top: -15px;
+ width: 40px;
+ height: 100px;
+ background-color: #ddf;
+ }
+ #div3 {
+ z-index: 2;
+ top: -50px;
+ }
+ </style>
+</head>
+<body>
+ <div id="div1">
+ <br/><br/>
+ </div>
+
+ <div id="div2">
+ <div id="div2_1">
+ <br/><br/>
+ </div>
+
+ <div id="div2_2">
+ </div>
+ </div>
+
+ <div id="div3">
+ <br/><br/>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-stacking-context-001b.html b/testing/web-platform/tests/css/css-contain/contain-paint-stacking-context-001b.html
new file mode 100644
index 0000000000..0c4d3323bf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-stacking-context-001b.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'will-change: contain' with stacking contents. Z-index is defined only for siblings and children.</title>
+ <link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
+
+ <link rel="help" href="https://drafts.csswg.org/css2/visuren.html#x43">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel="match" href="contain-paint-stacking-context-001-ref.html">
+ <style>
+ div {
+ position: relative;
+ width: 100px;
+ }
+ #div1,
+ #div3 {
+ background-color: #cfc;
+ }
+ #div1 {
+ z-index: 5;
+ }
+ #div2 {
+ will-change: contain;
+ background-color: #fdd;
+ height: 100px;
+ top: -20px;
+ }
+ #div2_1 {
+ background-color: #ffc;
+ z-index: 6;
+ top: -10px;
+ }
+ #div2_2 {
+ z-index: 3;
+ position: absolute;
+ top: -15px;
+ width: 40px;
+ height: 100px;
+ background-color: #ddf;
+ }
+ #div3 {
+ z-index: 2;
+ top: -50px;
+ }
+ </style>
+</head>
+<body>
+ <div id="div1">
+ <br/><br/>
+ </div>
+
+ <div id="div2">
+ <div id="div2_1">
+ <br/><br/>
+ </div>
+
+ <div id="div2_2">
+ </div>
+ </div>
+
+ <div id="div3">
+ <br/><br/>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-table-001.html b/testing/web-platform/tests/css/css-contain/contain-paint-table-001.html
new file mode 100644
index 0000000000..0622a1cbd2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-table-001.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' applies to 'table' elements</title>
+
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="reference/contain-paint-047-ref.html">
+
+ <meta content="This test checks that paint containment applies to table elements. Therefore the content of the table element should be clipped to the padding edge of its principal box." name="assert">
+
+ <style>
+ div#table
+ {
+ display: table;
+ font-family: monospace;
+ font-size: 100px;
+ table-layout: fixed;
+ width: 4ch;
+ contain: paint;
+ }
+
+ div.cell
+ {
+ display: table-cell;
+ color: green;
+ }
+ span
+ {
+ background-color: red;
+ color: yellow;
+ }
+ </style>
+
+ <p>Test passes if there is <strong>no red</strong>.
+
+ <div id="table">
+ <div class="cell">PASS<span>FAIL</span></div>
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-paint-table-002.html b/testing/web-platform/tests/css/css-contain/contain-paint-table-002.html
new file mode 100644
index 0000000000..2d51f91f03
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-paint-table-002.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: paint' applies to 'table' elements</title>
+
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+ <link rel="match" href="reference/contain-paint-047-ref.html">
+
+ <meta content="This test checks that paint containment applies to table elements. Therefore the content of the table element (including its caption) should be clipped to the padding edge of its principal box." name="assert">
+
+ <style>
+ div#table
+ {
+ display: table;
+ font-family: monospace;
+ font-size: 100px;
+ table-layout: fixed;
+ width: 4ch;
+ contain: paint;
+ }
+ div.caption
+ {
+ display: table-caption;
+ color: green;
+ /* We have to limit the width of the caption here, or else the caption's
+ intrinsic width (including the "FAIL" span) would "prop up" the width
+ of the table to be a size that'd be larger than its specified width.
+ Really, we want the table to be *only* 4 characters wide (as wide as
+ the text "PASS"), with "FAIL" overflowing and getting clipped by
+ "contain:paint" on the table wrapper box. */
+ width: 4ch;
+ }
+ span
+ {
+ background-color: red;
+ color: yellow;
+ }
+ </style>
+
+ <p>Test passes if there is <strong>no red</strong>.
+
+ <div id="table">
+ <div class="caption">
+ PASS<span>FAIL</span>
+ </div>
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-001.html b/testing/web-platform/tests/css/css-contain/contain-size-001.html
new file mode 100644
index 0000000000..49dfc41601
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-001.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment on non-atomic inlines</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="size containment does not apply to non atomic inlines">
+ <link rel="match" href="reference/pass_if_pass_below_clipped.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-size">
+
+<style>
+div { overflow: hidden; }
+span { contain: size; }
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div><span>PASS</span></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-002.html b/testing/web-platform/tests/css/css-contain/contain-size-002.html
new file mode 100644
index 0000000000..b30b02482d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-002.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment on ruby-base</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="size containment does not to apply ruby-base, which is an internal ruby element">
+ <link rel="match" href="reference/pass_if_pass_below_clipped.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-size">
+ <link rel=help href="https://drafts.csswg.org/css-display-3/#internal-ruby-element">
+
+<style>
+div {
+ overflow: hidden;
+ position: absolute;
+}
+rb {
+ contain: size;
+ display: ruby-base;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div><ruby><rb>PASS</rb></ruby></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-003.html b/testing/web-platform/tests/css/css-contain/contain-size-003.html
new file mode 100644
index 0000000000..95596c9691
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-003.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment on ruby-base-container</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="size containment does not to apply ruby-base-container, which is an internal ruby element">
+ <link rel="match" href="reference/pass_if_pass_below_clipped.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-size">
+ <link rel=help href="https://drafts.csswg.org/css-display-3/#internal-ruby-element">
+
+<style>
+div {
+ overflow: hidden;
+ position: absolute;
+}
+rbc {
+ contain: size;
+ display: ruby-base-container;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div><ruby><rbc>PASS</rbc></ruby></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-004.html b/testing/web-platform/tests/css/css-contain/contain-size-004.html
new file mode 100644
index 0000000000..58277ce1bf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-004.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment on ruby-text-container</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="size containment does not to apply ruby-text-container, which is an internal ruby element">
+ <link rel="match" href="reference/contain-size-004-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-size">
+ <link rel=help href="https://drafts.csswg.org/css-display-3/#internal-ruby-element">
+
+<style>
+div {
+ overflow: hidden;
+ position: absolute;
+}
+rtc {
+ contain: size;
+ display: ruby-text-container;
+ font-size: 1rem;
+}
+</style>
+
+<p>This test passes if you can see the word PASS below.
+<div><ruby><rtc>PASS</rtc></ruby></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-005.html b/testing/web-platform/tests/css/css-contain/contain-size-005.html
new file mode 100644
index 0000000000..139f8a97be
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-005.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment on ruby-text</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="size containment does not to apply ruby-text, which is an internal ruby element">
+ <link rel="match" href="reference/contain-size-005-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-size">
+ <link rel=help href="https://drafts.csswg.org/css-display-3/#internal-ruby-element">
+
+<style>
+div {
+ overflow: hidden;
+ position: absolute;
+}
+rt {
+ contain: size;
+ display: ruby-text;
+ font-size: 1rem;
+}
+</style>
+
+<p>This test passes if you can see the word PASS below.
+<div><ruby><rt>PASS</rt></ruby></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-006.html b/testing/web-platform/tests/css/css-contain/contain-size-006.html
new file mode 100644
index 0000000000..f5a5faa49d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-006.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on table-cell</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/pass_if_pass_below_clipped.html">
+<meta name=assert content="Size containment doesn't apply to table-cell elements.">
+<style>
+div {
+ display: table-cell;
+ contain: size;
+ overflow: hidden;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div>PASS</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-007.html b/testing/web-platform/tests/css/css-contain/contain-size-007.html
new file mode 100644
index 0000000000..4d4bce8e92
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-007.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on table-row-group</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/pass_if_pass_below_clipped.html">
+<meta name=assert content="Size containment doesn't apply to table-row-group elements.">
+<style>
+div {
+ display: table-row-group;
+ contain: size;
+}
+section {
+ overflow: hidden;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<section>
+<div>PASS</div>
+<section>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-008.html b/testing/web-platform/tests/css/css-contain/contain-size-008.html
new file mode 100644
index 0000000000..63deea8199
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-008.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on table-header-group</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/pass_if_pass_below_clipped.html">
+<meta name=assert content="Size containment doesn't apply to table-header-group elements.">
+<style>
+div {
+ display: table-header-group;
+ contain: size;
+}
+section {
+ overflow: hidden;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<section>
+<div>PASS</div>
+</section>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-009.html b/testing/web-platform/tests/css/css-contain/contain-size-009.html
new file mode 100644
index 0000000000..a285d5e2b3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-009.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on table-footer-group</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/pass_if_pass_below_clipped.html">
+<meta name=assert content="Size containment doesn't apply to table-footer-group elements.">
+<style>
+div {
+ display: table-footer-group;
+ contain: size;
+}
+section {
+ overflow: hidden;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<section>
+<div>PASS</div>
+</section>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-010.html b/testing/web-platform/tests/css/css-contain/contain-size-010.html
new file mode 100644
index 0000000000..0061894ce0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-010.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on table-row</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/pass_if_pass_below_clipped.html">
+<meta name=assert content="Size containment doesn't apply to table-row elements.">
+<style>
+div {
+ display: table-row;
+ contain: size;
+}
+section {
+ overflow: hidden;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<section>
+<div>PASS</div>
+</section>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-011.html b/testing/web-platform/tests/css/css-contain/contain-size-011.html
new file mode 100644
index 0000000000..f2a146938e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-011.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on table-caption</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="../reference/nothing.html">
+<meta name=assert content="Size containment does apply to table-caption elements.">
+<style>
+div {
+ display: table-caption;
+ contain: size;
+ overflow: hidden;
+}
+</style>
+
+<p>There should be nothing below.</p>
+<div>FAIL</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-012.html b/testing/web-platform/tests/css/css-contain/contain-size-012.html
new file mode 100644
index 0000000000..5c8e4f0370
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-012.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on display:table</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/pass_if_pass_below_clipped.html">
+<meta name=assert content="Size containment doesn't apply to table boxes.">
+<style>
+div {
+ display: table;
+ contain: size;
+ overflow: hidden;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div>PASS</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-012b.html b/testing/web-platform/tests/css/css-contain/contain-size-012b.html
new file mode 100644
index 0000000000..e52f345785
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-012b.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on display:inline-table</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/pass_if_pass_below_clipped.html">
+<meta name=assert content="Size containment doesn't apply to inline-table boxes.">
+<style>
+div {
+ display: inline-table;
+ contain: size;
+ overflow: hidden;
+}
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div>PASS</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-013.html b/testing/web-platform/tests/css/css-contain/contain-size-013.html
new file mode 100644
index 0000000000..4d1cbc403b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-013.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment replaced elements intrinsic size</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert content="This test checks that intrinsic size of replaced elements with 'contain: size' is zero.">
+<style>
+img {
+ background: green;
+ padding: 50px;
+ contain: size;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<img src="/css/support/60x60-red.png" alt="Image download support must be enabled" />
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-021.html b/testing/web-platform/tests/css/css-contain/contain-size-021.html
new file mode 100644
index 0000000000..199849e8ad
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-021.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: size' applies to inline-block (basic)</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+ <link rel="match" href="reference/contain-size-021-ref.html">
+
+ <meta content="This test checks that when laying out an inline-block element with 'contain: size', the inline-block element must be treated as if it would have no contents. In this test, the inline-block element has 1 image and no in-flow block descendant." name="assert">
+
+ <!--
+
+ contain-size-021: inline-block with 1 image and no in-flow block descendant: width comparison
+
+ contain-size-022: inline-block with 1 image and no in-flow block descendant: height comparison
+
+ contain-size-023: inline-block with text and no in-flow block descendant: width comparison
+
+ contain-size-024: inline-block with text and no in-flow block descendant: height comparison
+
+ contain-size-025: inline-block and 2 in-flow block descendants made of images: width comparison
+
+ contain-size-026: inline-block and 2 in-flow block descendants made of images: height comparison
+
+ contain-size-027: inline-block and 2 in-flow block descendants made of text: width comparison
+
+ contain-size-028: inline-block and 2 in-flow block descendants made of text: height comparison
+
+ -->
+
+ <style>
+ div#inline-block-blue-test
+ {
+ background-color: blue;
+ contain: size;
+ display: inline-block;
+ padding: 50px;
+ }
+
+ div#orange-reference
+ {
+ background-color: orange;
+ height: 100px;
+ width: 100px;
+ }
+ </style>
+
+ <p>This test passes if the painted blue area is <strong>exactly as wide as</strong> the orange square.
+
+ <div>
+ <div id="inline-block-blue-test"><img src="support/blue50wBy46h.png" alt="Image download support must be enabled"></div>
+ </div>
+
+ <div id="orange-reference"></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-023.html b/testing/web-platform/tests/css/css-contain/contain-size-023.html
new file mode 100644
index 0000000000..f83a10d85c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-023.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: size' applies to inline-block (basic)</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+ <link rel="match" href="reference/contain-size-023-ref.html">
+
+ <meta content="This test checks that when laying out an inline-block element with 'contain: size', the inline-block element must be treated as if it would have no contents. In this test, the inline-block element has text and no in-flow block descendant." name="assert">
+
+ <!--
+
+ contain-size-021: inline-block with 1 image and no in-flow block descendant: width comparison
+
+ contain-size-022: inline-block with 1 image and no in-flow block descendant: height comparison
+
+ contain-size-023: inline-block with text and no in-flow block descendant: width comparison
+
+ contain-size-024: inline-block with text and no in-flow block descendant: height comparison
+
+ contain-size-025: inline-block and 2 in-flow block descendants made of images: width comparison
+
+ contain-size-026: inline-block and 2 in-flow block descendants made of images: height comparison
+
+ contain-size-027: inline-block and 2 in-flow block descendants made of text: width comparison
+
+ contain-size-028: inline-block and 2 in-flow block descendants made of text: height comparison
+
+ -->
+
+ <style>
+ div.inline-block
+ {
+ display: inline-block;
+ }
+
+ div#blue-test
+ {
+ background-color: blue;
+ color: transparent;
+ contain: size;
+ font-size: 100px;
+ padding: 50px;
+ }
+
+ div#orange-reference
+ {
+ background-color: orange;
+ height: 100px;
+ width: 100px;
+ }
+ </style>
+
+ <p>This test passes if the painted blue area is <strong>exactly as wide as</strong> the orange square.
+
+ <div>
+ <div id="blue-test" class="inline-block">B</div>
+ </div>
+
+ <div>
+ <div id="orange-reference" class="inline-block"></div>
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-025.html b/testing/web-platform/tests/css/css-contain/contain-size-025.html
new file mode 100644
index 0000000000..3eb4b15961
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-025.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: size' applies to inline-block</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+ <link rel="match" href="reference/contain-size-025-ref.html">
+
+ <meta content="This test checks that when laying out an inline-block element with 'contain: size', the inline-block element must be treated as if it would have no contents. In this test, the inline-block element has 2 in-flow block descendants made of images." name="assert">
+
+ <!--
+
+ contain-size-021: inline-block with 1 image and no in-flow block descendant: width comparison
+
+ contain-size-022: inline-block with 1 image and no in-flow block descendant: height comparison
+
+ contain-size-023: inline-block with text and no in-flow block descendant: width comparison
+
+ contain-size-024: inline-block with text and no in-flow block descendant: height comparison
+
+ contain-size-025: inline-block and 2 in-flow block descendants made of images: width comparison
+
+ contain-size-026: inline-block and 2 in-flow block descendants made of images: height comparison
+
+ contain-size-027: inline-block and 2 in-flow block descendants made of text: width comparison
+
+ contain-size-028: inline-block and 2 in-flow block descendants made of text: height comparison
+
+ -->
+
+ <style>
+ div.inline-block
+ {
+ display: inline-block;
+ }
+
+ div#blue-test
+ {
+ background-color: blue;
+ contain: size;
+ padding: 50px;
+ }
+
+ span.block-descendant, img
+ {
+ display: block;
+ }
+
+ div#orange-reference
+ {
+ background-color: orange;
+ height: 100px;
+ width: 100px;
+ }
+ </style>
+
+ <p>This test passes if the painted blue area is <strong>exactly as wide as</strong> the orange square.
+
+ <div>
+ <div id="blue-test" class="inline-block">
+ <span class="block-descendant"><img src="support/blue50wBy25h.png" alt="Image download support must be enabled"></span>
+ <span id="last-line-box" class="block-descendant"><img src="support/blue50wBy25h.png" alt="Image download support must be enabled"></span>
+ </div>
+ </div>
+
+ <div id="orange-reference" class="inline-block"></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-027.html b/testing/web-platform/tests/css/css-contain/contain-size-027.html
new file mode 100644
index 0000000000..8dcff1745f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-027.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: size' applies to inline-block</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+ <link rel="match" href="reference/contain-size-027-ref.html">
+
+ <meta content="This test checks that when laying out an inline-block element with 'contain: size', the inline-block element must be treated as if it would have no contents. In this test, the inline-block element has 2 in-flow block descendants made of text." name="assert">
+
+ <!--
+
+ contain-size-021: inline-block with 1 image and no in-flow block descendant: width comparison
+
+ contain-size-022: inline-block with 1 image and no in-flow block descendant: height comparison
+
+ contain-size-023: inline-block with text and no in-flow block descendant: width comparison
+
+ contain-size-024: inline-block with text and no in-flow block descendant: height comparison
+
+ contain-size-025: inline-block and 2 in-flow block descendants made of images: width comparison
+
+ contain-size-026: inline-block and 2 in-flow block descendants made of images: height comparison
+
+ contain-size-027: inline-block and 2 in-flow block descendants made of text: width comparison
+
+ contain-size-028: inline-block and 2 in-flow block descendants made of text: height comparison
+
+ -->
+
+ <style>
+ div.inline-block
+ {
+ display: inline-block;
+ }
+
+ div#blue-test
+ {
+ background-color: blue;
+ color: transparent;
+ contain: size;
+ font-size: 50px;
+ line-height: 1;
+ padding: 50px;
+ }
+
+ span.block-descendant
+ {
+ display: block;
+ }
+
+ div#orange-reference
+ {
+ background-color: orange;
+ height: 100px;
+ width: 100px;
+ }
+ </style>
+
+ <p>This test passes if the painted blue area is <strong>exactly as wide as</strong> the orange square.
+
+ <div>
+ <div id="blue-test" class="inline-block">
+ <span class="block-descendant">B</span>
+ <span id="last-line-box" class="block-descendant">L</span>
+ </div>
+ </div>
+
+ <div>
+ <div id="orange-reference" class="inline-block"></div>
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-041.html b/testing/web-platform/tests/css/css-contain/contain-size-041.html
new file mode 100644
index 0000000000..93def48c65
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-041.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: size' applies to inline replaced element (basic)</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+ <link rel="match" href="reference/contain-size-025-ref.html">
+
+ <meta content="This test checks that when laying out an inline replaced element with 'contain: size', the inline replaced element must be treated as having an intrinsic width and height of 0." name="assert">
+
+ <style>
+ img#blue-test
+ {
+ background-color: blue;
+ contain: size;
+ padding: 50px;
+ }
+
+ div#orange-reference
+ {
+ background-color: orange;
+ height: 100px;
+ width: 100px;
+ }
+ </style>
+
+ <p>This test passes if the painted blue area is <strong>exactly as wide as</strong> the orange square.
+
+ <div><img id="blue-test" src="support/blue-100x100.png" alt="Image download support must be enabled"></div>
+
+ <div id="orange-reference"></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-042.html b/testing/web-platform/tests/css/css-contain/contain-size-042.html
new file mode 100644
index 0000000000..52c5281b05
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-042.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: size' applies to inline replaced element (basic)</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+ <link rel="match" href="reference/contain-size-022-ref.html">
+
+ <meta content="This test checks that when laying out an inline replaced element with 'contain: size', the inline replaced element must be treated as having an intrinsic width and height of 0." name="assert">
+
+ <style>
+ img#blue-test
+ {
+ background-color: blue;
+ contain: size;
+ padding: 50px;
+ }
+ </style>
+
+ <p>This test passes if the painted blue area is <strong>exactly as tall as</strong> the orange square.
+
+ <div><img id="blue-test" src="support/blue-100x100.png" alt="Image download support must be enabled"> <img id="orange-reference" src="support/swatch-orange.png" width="100" height="100" alt="Image download support must be enabled"></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-051.html b/testing/web-platform/tests/css/css-contain/contain-size-051.html
new file mode 100644
index 0000000000..d1eab897a8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-051.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: size' does not apply to table-cell element</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+ <link rel="match" href="reference/contain-size-051-ref.html">
+
+
+ <style>
+ td
+ {
+ contain: size;
+ font-size: 50px;
+ }
+ </style>
+
+ <p>Test passes if "5678" (without quotes) is readable and if the digits do not overlap each other.
+
+ <table>
+ <tr>
+ <td>5<td>6<td>7<td>8
+ </table>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-052.html b/testing/web-platform/tests/css/css-contain/contain-size-052.html
new file mode 100644
index 0000000000..a4d1afdd85
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-052.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: size' does not apply to table-cell element</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+ <link rel="match" href="reference/contain-size-051-ref.html">
+
+
+ <style>
+ div#table
+ {
+ border-spacing: 2px;
+ display: table;
+ }
+
+ div#table-row
+ {
+ display: table-row;
+ }
+
+ div.table-cell
+ {
+ contain: size;
+ display: table-cell;
+ font-size: 50px;
+ padding: 1px;
+ }
+ </style>
+
+ <p>Test passes if "5678" (without quotes) is readable and if the digits do not overlap each other.
+
+ <div id="table">
+ <div id="table-row">
+ <div class="table-cell">5</div><div class="table-cell">6</div><div class="table-cell">7</div><div class="table-cell">8</div>
+ </div>
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-056.html b/testing/web-platform/tests/css/css-contain/contain-size-056.html
new file mode 100644
index 0000000000..e8c140aded
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-056.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: size' applies to caption element</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+ <link rel="match" href="reference/contain-size-056-ref.html">
+
+
+ <style>
+ table
+ {
+ width: 400px;
+ }
+
+ caption
+ {
+ border: orange solid 3px;
+ color: blue;
+ contain: size;
+ font-size: 32px;
+ }
+ </style>
+
+ <p>Test passes if the words "Table caption" are below a thick orange line. Test fails if, instead of a thick orange line, there is an orange rectangle with the words "Table caption" in it.
+
+ <table>
+ <caption>Table caption</caption>
+ </table>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-061.html b/testing/web-platform/tests/css/css-contain/contain-size-061.html
new file mode 100644
index 0000000000..1738b7f2a0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-061.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: size' applies to block box (basic)</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+ <link rel="match" href="reference/contain-size-061-ref.html">
+
+
+ <style>
+ div
+ {
+ contain: size;
+ font-size: 100px;
+ overflow: hidden;
+ }
+ </style>
+
+ <p>Test passes if the word FAIL is absent.
+
+ <div>FAIL</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-062.html b/testing/web-platform/tests/css/css-contain/contain-size-062.html
new file mode 100644
index 0000000000..10d7d48c95
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-062.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: size' applies to block box (basic)</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+ <link rel="match" href="reference/contain-size-062-ref.html">
+
+
+ <style>
+ div
+ {
+ border: orange solid 3px;
+ color: blue;
+ contain: size;
+ font-size: 32px;
+ width: 400px;
+ }
+ </style>
+
+ <p>Test passes if the words "Text sample" are below a thick orange line. Test fails if, instead of a thick orange line, there is an orange rectangle with the words "Text sample" in it.
+
+ <div>Text sample</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-063.html b/testing/web-platform/tests/css/css-contain/contain-size-063.html
new file mode 100644
index 0000000000..9c843ab7cc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-063.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Containment Test: 'contain: size' affects intrinsic size</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+<link rel="match" href="reference/contain-size-063-ref.html">
+<meta name="asserts" content="the intrinsic size of a size-contained element is treated as 0 in various scenarios involving intrinsic sizing.">
+
+<style>
+.red {
+ background: red;
+}
+.abs {
+ position: absolute;
+}
+.float {
+ float: left;
+}
+.zero {
+ width: 0;
+}
+.contained {
+ contain: size;
+ color: transparent;
+}
+.grid {
+ display: grid;
+ grid: max-content auto / min-content auto;
+}
+table {
+ border-collapse: collapse;
+}
+td {
+ padding: 0;
+}
+</style>
+
+<p>Test passes if there is no red below.
+
+<!-- max content sized-->
+<div class="red abs"><div class="contained">Arbitrary content content<br>that takes up size.<br>Block Layout</div></div>
+
+<!-- max content sized-->
+<div class="red float"><div class="contained">Arbitrary content content<br>that takes up size.<br>Float</div></div>
+
+<!-- min content sized-->
+<div class=zero><div class="red float"><div class="contained">Arbitrary content content<br>that takes up size.<br>Float in narrow wrapper</div></div></div>
+
+<div class="grid red">
+ <div class="red"></div>
+ <div class="contained">Arbitrary content content<br>that takes up size.<br>Grid item giving the first row it's height</div>
+ <div class="contained">Arbitrary content content<br>that takes up size.<br>Grid item giving the first column its width</div>
+</div>
+
+<table class=red>
+ <tr>
+ <td class=red>
+ <td><div class="contained">Arbitrary content content<br>that takes up size.<br>content of a table cell giving the fist row it's height</div>
+ <tr>
+ <td><div class="contained">Arbitrary content content<br>that takes up size.<br>content of a table cell giving the first column it's width</div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-064.html b/testing/web-platform/tests/css/css-contain/contain-size-064.html
new file mode 100644
index 0000000000..043a569eb4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-064.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment: layout in place</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="The size containment box's content (including any pseudo-elements) must be laid out into the now fixed-size size containment box normally.">
+ <link rel="match" href="reference/contain-size-064-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-size">
+
+<style>
+div { font-size: 50px; }
+.red { background: red; }
+.green { background: green; }
+.grid {
+ display: grid;
+ grid-template-columns: min-content max-content;
+}
+#test { contain: size; }
+#test::after { content: "\a0" ; }
+</style>
+
+<p>This test passes if there are two green rectangles and no red.
+
+<div class=grid>
+ <div style="grid-area: 1/1">&nbsp;</div>
+ <div style="grid-area: 1/2"class=red></div><!-- will show if the size containment doesn't result in 0x0-->
+ <div style="grid-area: 1/3"></div>
+
+ <div class=red></div><!-- will show if the size containment doesn't result in 0x0-->
+ <div id=test class="grid red"><!-- will show if the size containment doesn't result in 0x0-->
+ <div>&nbsp;</div>
+ <div class=green></div><!-- won't show unless ::after is inserted and grid tracks are properly sized-->
+ <div class=green></div><!-- won't show unless ::after is inserted and grid tracks are properly sized-->
+ </div>
+</div>
+
+
+
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-baseline-001.html b/testing/web-platform/tests/css/css-contain/contain-size-baseline-001.html
new file mode 100644
index 0000000000..d8436c4508
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-baseline-001.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment and baselines</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=assert content="contain:size does not suppress baseline alignment">
+ <link rel="match" href="reference/contain-baseline-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-size">
+
+<style>
+div {
+ display: inline-block;
+ height: 5px;
+ background: blue;
+ width: 50px;
+ contain: size;
+ color: transparent;
+ font-size: 100px;
+}
+</style>
+
+<p>Test passes if there are two, not one, blue lines below.</p>
+<div></div><div>a</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-block-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-block-001-ref.html
new file mode 100644
index 0000000000..7f13a517a6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-block-001-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .basic {
+ border: 1em solid green;
+ }
+ .height-ref {
+ height: 50px;
+ background: lightblue;
+ }
+ .width-ref {
+ width: 50px;
+ }
+ .floatLBasic-ref {
+ float: left;
+ }
+ .floatLWidth-ref {
+ float: left;
+ width: 50px;
+ }
+ .flexBaselineCheck {
+ display: flex;
+ align-items: baseline;
+ }
+ .innerContents {
+ color: transparent;
+ width: 0;
+ height: 0;
+ }
+ </style>
+</head>
+<body>
+ <div class="basic"></div>
+ <br>
+
+ <div class="basic height-ref"></div>
+ <br>
+
+ <div class="basic height-ref"></div>
+ <br>
+
+ <div class="basic width-ref"></div>
+ <br>
+
+ <div class="basic width-ref"></div>
+ <br>
+
+ <div class="basic floatLBasic-ref"></div>
+ <br>
+
+ <div class="basic floatLWidth-ref"></div>
+ <br>
+
+ <div class="flexBaselineCheck">
+ outside before<div class="basic innerContents">i</div>outside after
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-block-001.html b/testing/web-platform/tests/css/css-contain/contain-size-block-001.html
new file mode 100644
index 0000000000..0ed82ff8fc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-block-001.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on block elements should cause them to be sized as if they had no contents</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-block-001-ref.html">
+ <style>
+ .contain {
+ contain: size;
+ border: 1em solid green;
+ background: red;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ }
+ .minHeight {
+ min-height: 50px;
+ background: lightblue;
+ }
+ .height {
+ height: 50px;
+ background: lightblue;
+ }
+ .maxWidth {
+ max-width: 50px;
+ }
+ .width {
+ width: 50px;
+ }
+ .floatLBasic {
+ float: left;
+ }
+ .floatLWidth {
+ float: left;
+ width: 50px;
+ }
+ .flexBaselineCheck {
+ display: flex;
+ align-items: baseline;
+ }
+ </style>
+</head>
+<body>
+ <!--CSS Test: A size-contained block element with no specified size should render at 0 height regardless of content.-->
+ <div class="contain"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained block element with specified min-height should render at given min-height regardless of content.-->
+ <div class="contain minHeight"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained block element with specified height should render at given height regardless of content.-->
+ <div class="contain height"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained block element with specified max-width should render at given max-width and zero height regardless of content.-->
+ <div class="contain maxWidth"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained block element with specified width should render at given width and zero height regardless of content.-->
+ <div class="contain width"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained floated block element with no specified size should render at 0px by 0px regardless of content.-->
+ <div class="contain floatLBasic"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained floated block element with specified width and no specified height should render at given width and 0 height regardless of content.-->
+ <div class="contain floatLWidth"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained block element should perform baseline alignment regularly.-->
+ <div class="flexBaselineCheck">
+ outside before<div class="contain"><div class="innerContents">inner</div></div>outside after
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-block-002-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-block-002-ref.html
new file mode 100644
index 0000000000..1f41028faa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-block-002-ref.html
@@ -0,0 +1,88 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .basic {
+ overflow: scroll;
+ position: relative;
+ border: 2px solid green;
+ }
+ .height-ref {
+ height: 60px;
+ background: lightblue;
+ }
+ .width-ref {
+ width: 60px;
+ }
+ .floatLBasic-ref {
+ float: left;
+ }
+ .floatLWidth-ref {
+ float: left;
+ width: 60px;
+ }
+ .flexBaselineCheck {
+ display: flex;
+ align-items: baseline;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ position: absolute;
+ }
+ .zeroHeightContents {
+ color: transparent;
+ height: 0px;
+ width: 0px;
+ }
+ </style>
+</head>
+<body>
+ <!-- NOTE: In the reference-case scenarios here, we use the same DOM as in
+ the testcase, and we simply use 'position: absolute' on the descendants
+ wherever the testcase has 'contain: size' on the container. This
+ produces an accurate reference rendering, because out-of-flow content
+ doesn't contribute to the container's sizing, but does create scrollable
+ overflow (i.e. it produces scrollbars of the appropriate size for the
+ amount of overflow). -->
+ <div class="basic"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic height-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic height-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic width-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic width-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic floatLBasic-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic floatLWidth-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="flexBaselineCheck">
+ outside before
+ <div class="basic">
+ <!-- We use the out-of-flow "innerContents" to create the correct
+ amount of scrollable overflow to match the testcase, and we
+ use the smaller in-flow "zeroHeightContents" to provide a
+ baseline that we can use to verify the testcase's baseline
+ alignment position. -->
+ <div class="innerContents">inner</div>
+ <div class="zeroHeightContents">i</div>
+ </div>
+ outside after
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-block-002.html b/testing/web-platform/tests/css/css-contain/contain-size-block-002.html
new file mode 100644
index 0000000000..4dc92103ea
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-block-002.html
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on 'overflow:scroll' block elements should cause them to be sized as if they had no contents</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-block-002-ref.html">
+ <style>
+ .contain {
+ contain: size;
+ overflow: scroll;
+ border: 2px solid green;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ }
+ .minHeight {
+ min-height: 60px;
+ background: lightblue;
+ }
+ .height {
+ height: 60px;
+ background: lightblue;
+ }
+ .maxWidth {
+ max-width: 60px;
+ }
+ .width {
+ width: 60px;
+ }
+ .floatLBasic {
+ float: left;
+ }
+ .floatLWidth {
+ float: left;
+ width: 60px;
+ }
+ .flexBaselineCheck {
+ display: flex;
+ align-items: baseline;
+ }
+ </style>
+</head>
+<body>
+ <!-- NOTE: In all cases below, the expectation is that the size-contained
+ element should be sized as if it had no contents (while honoring
+ whatever sizing properties are provided). -->
+
+ <!--CSS Test: A size-contained scrollable block with no specified size.-->
+ <div class="contain"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained scrollable block with specified min-height -->
+ <div class="contain minHeight"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained scrollable block with specified height -->
+ <div class="contain height"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained scrollable block with specified max-width -->
+ <div class="contain maxWidth"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained scrollable block with specified width -->
+ <div class="contain width"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained floated scrollable block with auto size -->
+ <div class="contain floatLBasic"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained floated scrollable block with
+ specified width -->
+ <div class="contain floatLWidth"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained scrollable block in a
+ baseline-aligning flex container: should size as if it's empty, but
+ still baseline-align using its contents' baseline -->
+ <div class="flexBaselineCheck">
+ outside before
+ <div class="contain">
+ <div class="innerContents">inner</div>
+ </div>
+ outside after
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-block-003-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-block-003-ref.html
new file mode 100644
index 0000000000..2f6ff8322d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-block-003-ref.html
@@ -0,0 +1,88 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .basic {
+ overflow: auto;
+ position: relative;
+ border: 2px solid green;
+ }
+ .height-ref {
+ height: 60px;
+ background: lightblue;
+ }
+ .width-ref {
+ width: 60px;
+ }
+ .floatLBasic-ref {
+ float: left;
+ }
+ .floatLWidth-ref {
+ float: left;
+ width: 60px;
+ }
+ .flexBaselineCheck {
+ display: flex;
+ align-items: baseline;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ position: absolute;
+ }
+ .zeroHeightContents {
+ color: transparent;
+ height: 0px;
+ width: 0px;
+ }
+ </style>
+</head>
+<body>
+ <!-- NOTE: In the reference-case scenarios here, we use the same DOM as in
+ the testcase, and we simply use 'position: absolute' on the descendants
+ wherever the testcase has 'contain: size' on the container. This
+ produces an accurate reference rendering, because out-of-flow content
+ doesn't contribute to the container's sizing, but does create scrollable
+ overflow (i.e. it produces scrollbars of the appropriate size for the
+ amount of overflow). -->
+ <div class="basic"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic height-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic height-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic width-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic width-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic floatLBasic-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic floatLWidth-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="flexBaselineCheck">
+ outside before
+ <div class="basic">
+ <!-- We use the out-of-flow "innerContents" to create the correct
+ amount of scrollable overflow to match the testcase, and we
+ use the smaller in-flow "zeroHeightContents" to provide a
+ baseline that we can use to verify the testcase's baseline
+ alignment position. -->
+ <div class="innerContents">inner</div>
+ <div class="zeroHeightContents">i</div>
+ </div>
+ outside after
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-block-003.html b/testing/web-platform/tests/css/css-contain/contain-size-block-003.html
new file mode 100644
index 0000000000..cf7e231016
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-block-003.html
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on 'overflow:auto' block elements should cause them to be sized as if they had no contents</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-block-003-ref.html">
+ <style>
+ .contain {
+ contain: size;
+ overflow: auto;
+ border: 2px solid green;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ }
+ .minHeight {
+ min-height: 60px;
+ background: lightblue;
+ }
+ .height {
+ height: 60px;
+ background: lightblue;
+ }
+ .maxWidth {
+ max-width: 60px;
+ }
+ .width {
+ width: 60px;
+ }
+ .floatLBasic {
+ float: left;
+ }
+ .floatLWidth {
+ float: left;
+ width: 60px;
+ }
+ .flexBaselineCheck {
+ display: flex;
+ align-items: baseline;
+ }
+ </style>
+</head>
+<body>
+ <!-- NOTE: In all cases below, the expectation is that the size-contained
+ element should be sized as if it had no contents (while honoring
+ whatever sizing properties are provided). -->
+
+ <!--CSS Test: A size-contained scrollable block with no specified size.-->
+ <div class="contain"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained scrollable block with specified min-height -->
+ <div class="contain minHeight"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained scrollable block with specified height -->
+ <div class="contain height"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained scrollable block with specified max-width -->
+ <div class="contain maxWidth"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained scrollable block with specified width -->
+ <div class="contain width"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained floated scrollable block with auto size -->
+ <div class="contain floatLBasic"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained floated scrollable block with
+ specified width -->
+ <div class="contain floatLWidth"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained scrollable block in a
+ baseline-aligning flex container: should size as if it's empty, but
+ still baseline-align using its contents' baseline -->
+ <div class="flexBaselineCheck">
+ outside before
+ <div class="contain">
+ <div class="innerContents">inner</div>
+ </div>
+ outside after
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-block-004-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-block-004-ref.html
new file mode 100644
index 0000000000..c8647b19dd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-block-004-ref.html
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .basic {
+ overflow: hidden;
+ position: relative;
+ border: 2px solid green;
+ }
+ .height-ref {
+ height: 60px;
+ background: lightblue;
+ }
+ .width-ref {
+ width: 60px;
+ }
+ .floatLBasic-ref {
+ float: left;
+ }
+ .floatLWidth-ref {
+ float: left;
+ width: 60px;
+ }
+ .flexBaselineCheck {
+ display: flex;
+ align-items: baseline;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ position: absolute;
+ }
+ .zeroHeightContents {
+ color: transparent;
+ height: 0px;
+ width: 0px;
+ }
+ </style>
+</head>
+<body>
+ <!-- NOTE: In the reference-case scenarios here, we use the same DOM as in
+ the testcase, and we simply use 'position: absolute' on the descendants
+ wherever the testcase has 'contain: size' on the container. This
+ produces an accurate reference rendering, because out-of-flow content
+ doesn't contribute to the container's sizing, but does create scrollable
+ overflow. -->
+ <div class="basic"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic height-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic height-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic width-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic width-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic floatLBasic-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic floatLWidth-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="flexBaselineCheck">
+ outside before
+ <div class="basic">
+ <!-- We use the out-of-flow "innerContents" to create the correct
+ amount of scrollable overflow to match the testcase, and we
+ use the smaller in-flow "zeroHeightContents" to provide a
+ baseline that we can use to verify the testcase's baseline
+ alignment position. -->
+ <div class="innerContents">inner</div>
+ <div class="zeroHeightContents">i</div>
+ </div>
+ outside after
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-block-004.html b/testing/web-platform/tests/css/css-contain/contain-size-block-004.html
new file mode 100644
index 0000000000..b6cca54a8c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-block-004.html
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on 'overflow:hidden' block elements should cause them to be sized as if they had no contents</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-block-004-ref.html">
+ <style>
+ .contain {
+ contain: size;
+ overflow: hidden;
+ border: 2px solid green;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ }
+ .minHeight {
+ min-height: 60px;
+ background: lightblue;
+ }
+ .height {
+ height: 60px;
+ background: lightblue;
+ }
+ .maxWidth {
+ max-width: 60px;
+ }
+ .width {
+ width: 60px;
+ }
+ .floatLBasic {
+ float: left;
+ }
+ .floatLWidth {
+ float: left;
+ width: 60px;
+ }
+ .flexBaselineCheck {
+ display: flex;
+ align-items: baseline;
+ }
+ </style>
+</head>
+<body>
+ <!-- NOTE: In all cases below, the expectation is that the size-contained
+ element should be sized as if it had no contents (while honoring
+ whatever sizing properties are provided). -->
+
+ <!--CSS Test: A size-contained scrollable block with no specified size.-->
+ <div class="contain"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained scrollable block with specified min-height -->
+ <div class="contain minHeight"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained scrollable block with specified height -->
+ <div class="contain height"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained scrollable block with specified max-width -->
+ <div class="contain maxWidth"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained scrollable block with specified width -->
+ <div class="contain width"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained floated scrollable block with auto size -->
+ <div class="contain floatLBasic"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained floated scrollable block with
+ specified width -->
+ <div class="contain floatLWidth"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained scrollable block in a
+ baseline-aligning flex container: should size as if it's empty, but
+ still baseline-align using its contents' baseline -->
+ <div class="flexBaselineCheck">
+ outside before
+ <div class="contain">
+ <div class="innerContents">inner</div>
+ </div>
+ outside after
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-borders.html b/testing/web-platform/tests/css/css-contain/contain-size-borders.html
new file mode 100644
index 0000000000..16b5b06295
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-borders.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>contain:size on auto-height block width vertical borders</title>
+<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="contain:size; width:100px; border:50px solid green; border-left:none; border-right:none; background:red;">
+ <div style="height:200px;"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-breaks-001.html b/testing/web-platform/tests/css/css-contain/contain-size-breaks-001.html
new file mode 100644
index 0000000000..e859b9c9f0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-breaks-001.html
@@ -0,0 +1,65 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: size containment and fragmentation</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="ahem">
+ <meta name=assert content="size containment makes element monolithic">
+ <link rel="match" href="reference/contain-size-breaks-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-size">
+ <link rel=help href="https://drafts.csswg.org/css-break-3/#monolithic">
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+article {
+ height: 2.5em;
+ column-gap: 0;
+ columns: 3 1em;
+ width: 3em;
+
+ font-size: 40px;
+ font-family: ahem;
+ line-height: 1;
+}
+div {
+ contain: size;
+ height: 5em;
+ color: orange;
+}
+</style>
+
+<p>This test passes if there is an orange rectangle below. If the shape is not a rectangle, the test fails.
+
+<article>
+<div>A B C D E</div>
+</article>
+
+<!--
+As the element is monolithic it should either:
+* Overflow vertically, appearing as a single 1x5 em rectangle:
+ -----
+ | A |
+ | B |
+ | C |
+ | D |
+ | E |
+ -----
+
+* Be sliced, with one slice in each column, appearing as a single 2x2.5 em rectangle:
+ ----------
+ | A |' ◟ '
+ | B || D |
+ ' ◜ '| E |
+ ----------
+
+Either way, it will always appear as a single rectangle.
+
+If the element is not monolithic, it will fit 2 letters (A & B) in the first column,
+2 (C & D) in the second column, and the fifth (E) will be overflowing the div,
+either into the third column, or into the bottom of the second one.
+Either way, this will not look like a rectangle.
+
+Note: We use some UTF-8 characters to simulate the sliced C on the ASCII diagrams:
+* U+25DC: ◜ Upper left quadrant circular arc
+* U+25DF: ◟ Lower left quadrant circular arc
+-->
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-button-001.html b/testing/web-platform/tests/css/css-contain/contain-size-button-001.html
new file mode 100644
index 0000000000..9048352f11
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-button-001.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on button</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/contain-size-button-001-ref.html">
+<meta name=assert content="Size containment does apply to buttons, thus their size is the same than if they don't have contents.">
+<style>
+button {
+ border: 5px solid green;
+ padding: 0;
+ margin: 0;
+ contain: size;
+ color: transparent;
+ font-size: 2em;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the top, and then the word "after".</p>
+before<button>flex</button>after
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-button-002-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-button-002-ref.html
new file mode 100644
index 0000000000..6cf0e4ad86
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-button-002-ref.html
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ button {
+ border: 1em solid green;
+ margin: 0;
+ /* In case the testcase's 'inner' text is taller than the button, don't let
+ it influence its line-box's size. This lets us more-easily compare
+ sizing between empty buttons vs. contained nonempty buttons. */
+ vertical-align: top;
+ }
+ .vaBaseline {
+ vertical-align: baseline;
+ }
+ .width-ref {
+ width: 50px;
+ }
+ .height-ref {
+ height: 50px;
+ background: lightblue;
+ }
+ .floatLBasic-ref {
+ float: left;
+ }
+ .floatLWidth-ref {
+ float: left;
+ width: 50px;
+ }
+ br { clear: both }
+ .iFlexBasic-ref {
+ display: inline-flex;
+ }
+ .iFlexWidth-ref {
+ display: inline-flex;
+ width: 50px;
+ }
+ .innerContents {
+ color: transparent;
+ height: 0;
+ width: 0;
+ }
+ .orthog-ref {
+ writing-mode: vertical-lr;
+ }
+ </style>
+</head>
+<body>
+ <button></button>
+ <br>
+
+ <button class="floatLBasic-ref"></button>
+ <br>
+
+ <button class="floatLWidth-ref"></button>
+ <br>
+
+ <button class="iFlexBasic-ref"></button>
+ <br>
+
+ <button class="iFlexWidth-ref"></button>
+ <br>
+
+ outside before<button class="vaBaseline"><div class="innerContents">inner</div></button>outside after
+ <br>
+
+ <button class="width-ref"></button>
+ <br>
+
+ <button class="width-ref"></button>
+ <br>
+
+ <button class="height-ref"></button>
+ <br>
+
+ <button class="height-ref"></button>
+ <br>
+
+ s<button class="orthog-ref vaBaseline"><div class="innerContents">inner</div></button>endtext
+ <br>
+
+ <button class="height-ref width-ref">inside</button>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-button-002.html b/testing/web-platform/tests/css/css-contain/contain-size-button-002.html
new file mode 100644
index 0000000000..d6b6d0d10d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-button-002.html
@@ -0,0 +1,109 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on buttons should cause them to be sized as if they had no contents.</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-button-002-ref.html">
+ <style>
+ button {
+ contain: size;
+ margin: 0;
+ border: 1em solid green;
+ /* In case the testcase's 'inner' text is taller than the button, don't let
+ it influence its line-box's size. This lets us more-easily compare
+ sizing between empty buttons vs. contained nonempty buttons. */
+ vertical-align: top;
+ }
+ .vaBaseline {
+ vertical-align: baseline;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ }
+ .minWidth {
+ min-width: 50px;
+ }
+ .width {
+ width: 50px;
+ }
+ .minHeight {
+ min-height: 50px;
+ background: lightblue;
+ }
+ .height {
+ height: 50px;
+ background: lightblue;
+ }
+ .floatLBasic {
+ float: left;
+ }
+ .floatLWidth {
+ float: left;
+ width: 50px;
+ }
+ br { clear: both }
+ .iFlexBasic {
+ display: inline-flex;
+ }
+ .iFlexWidth {
+ display: inline-flex;
+ width: 50px;
+ }
+ .orthog {
+ writing-mode: vertical-lr;
+ }
+ </style>
+</head>
+<body>
+ <!--CSS Test: A size-contained button with no specified size should render at 0 height regardless of content.-->
+ <button><div class="innerContents">inner</div></button>
+ <br>
+
+ <!--CSS Test: A size-contained floated button with no specified size should render at 0px by 0px regardless of content.-->
+ <button class="floatLBasic"><div class="innerContents">inner</div></button>
+ <br>
+
+ <!--CSS Test: A size-contained floated button with specified width and no specified height should render at given width and 0 height regardless of content.-->
+ <button class="floatLWidth"><div class="innerContents">inner</div></button>
+ <br>
+
+ <!--CSS Test: A size-contained inline-flex button with no specified size should render at 0px by 0px regardless of content.-->
+ <button class="iFlexBasic"><div class="innerContents">inner</div></button>
+ <br>
+
+ <!--CSS Test: A size-contained inline-flex button with specified width and no specified height should render at given width and 0 height regardless of content.-->
+ <button class="iFlexWidth"><div class="innerContents">inner</div></button>
+ <br>
+
+ <!--CSS Test: A size-contained button should perform baseline alignment regularly.-->
+ outside before<button class="vaBaseline"><div class="innerContents">inner</div></button>outside after
+ <br>
+
+ <!--CSS Test: A size-contained button with specified min-width should render at given min-width and zero height regardless of content.-->
+ <button class="minWidth"><div class="innerContents">inner</div></button>
+ <br>
+
+ <!--CSS Test: A size-contained button with specified width should render at given width and zero height regardless of content.-->
+ <button class="width"><div class="innerContents">inner</div></button>
+ <br>
+
+ <!--CSS Test: A size-contained button with specified min-height should render at given min-height regardless of content.-->
+ <button class="minHeight"><div class="innerContents">inner</div></button>
+ <br>
+
+ <!--CSS Test: A size-contained button with specified height should render at given height regardless of content.-->
+ <button class="height"><div class="innerContents">inner</div></button>
+ <br>
+
+ <!--CSS Test: A size-contained button with vertical text should perform baseline alignment regularly.-->
+ s<button class="orthog vaBaseline"><div class="innerContents">inner</div></button>endtext
+ <br>
+
+ <!--CSS Test: A size-contained button with inner text should layout the text in the same manner as a container of the same type with identical contents.-->
+ <button class="height width">inside</button>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-dynamic-001.html b/testing/web-platform/tests/css/css-contain/contain-size-dynamic-001.html
new file mode 100644
index 0000000000..f670d301c5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-dynamic-001.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Dynamic change to size containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1765615">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<meta name="assert" content="Verify size containment is properly updated after dynamic change to the contain property.">
+<style>
+ /* Selectors for contain */
+ #none .wrapper {
+ containt: none;
+ }
+ #size .wrapper {
+ contain: size;
+ }
+ #none_to_size .wrapper {
+ containt: none;
+ }
+ #size_to_none .wrapper {
+ contain: size;
+ }
+
+ /* Selectors for testing sizing as empty */
+ .wrapper {
+ display: inline-block;
+ }
+ .box {
+ display: inline-block;
+ width: 50px;
+ height: 5px;
+ background: black;
+ }
+</style>
+<body>
+ <div id="log"></div>
+
+ <div id="none">
+ <div class="wrapper"><div class="box"></div></div>
+ </div>
+
+ <div id="size">
+ <div class="wrapper"><div class="box"></div></div>
+ </div>
+
+ <div id="none_to_size">
+ <div class="wrapper"><div class="box"></div></div>
+ </div>
+
+ <div id="size_to_none">
+ <div class="wrapper"><div class="box"></div></div>
+ </div>
+
+ <script>
+ function verifySizeContainment(id, applied) {
+ // To verify size containment applies, we test whether it is sized as
+ // if empty i.e. the size of its inner box is ignored.
+ let container = document.getElementById(id);
+ let wrapper = container.getElementsByClassName("wrapper")[0];
+ let wrapperBox = wrapper.getBoundingClientRect();
+ assert_equals(wrapperBox.width == 0, applied, "width is zero");
+ assert_equals(wrapperBox.height == 0, applied, "height is zero");
+ }
+
+ function setContain(id, value) {
+ let container = document.getElementById(id);
+ let wrapper = container.getElementsByClassName("wrapper")[0];
+ wrapper.style.contain = value;
+ }
+
+ promise_test(async () => {
+ verifySizeContainment("none", /*applied=*/false);
+ }, "contain: none");
+
+ promise_test(async () => {
+ verifySizeContainment("size", /*applied=*/true);
+ }, "contain: size");
+
+ promise_test(async () => {
+ setContain("none_to_size", "size");
+ verifySizeContainment("none_to_size", /*applied=*/true);
+ }, "switching contain from none to size");
+
+ promise_test(async () => {
+ setContain("size_to_none", "none");
+ verifySizeContainment("size_to_none", /*applied=*/false);
+ }, "switching contain from size to none");
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-fieldset-001.html b/testing/web-platform/tests/css/css-contain/contain-size-fieldset-001.html
new file mode 100644
index 0000000000..f92424716c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-fieldset-001.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on fieldset</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/contain-size-fieldset-001-ref.html">
+<meta name=assert content="Size containment does apply to fieldsets, thus their size is the same than if they don't have contents.">
+<style>
+fieldset {
+ contain: size;
+ display: inline-block;
+ color: transparent;
+ border: none;
+ padding: 0;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a small space, and then the word "after".</p>
+before<fieldset><legend>legend</legend></fieldset>after
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-fieldset-002.html b/testing/web-platform/tests/css/css-contain/contain-size-fieldset-002.html
new file mode 100644
index 0000000000..54f6cb1f26
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-fieldset-002.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on fieldset</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/contain-size-fieldset-002-ref.html">
+<meta name=assert content="Size containment does apply to fieldsets, thus their size is the same than if they don't have contents.">
+<style>
+#border {
+ border: 1px solid black;
+ width: min-content;
+}
+fieldset {
+ contain: size;
+ visibility: hidden;
+ height: 1px;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You should see a black border box below.</p>
+<div id="border">
+ <fieldset>
+ <legend>legend</legend>
+ Fieldset contents are here.
+ </fieldset>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-fieldset-003-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-fieldset-003-ref.html
new file mode 100644
index 0000000000..6a77ee6887
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-fieldset-003-ref.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .basic {
+ visibility: hidden;
+ border: none;
+ }
+ .container {
+ border: 10px solid green;
+ display: inline-block;
+ vertical-align: top;
+ }
+ .height {
+ height: 30px;
+ }
+ .width {
+ width: 30px;
+ }
+ </style>
+</head>
+<body>
+ <div class="container"><fieldset class="basic"></fieldset></div>
+ <br>
+
+ <div class="container"><fieldset class="basic height"></fieldset></div>
+ <br>
+
+ <div class="container"><fieldset class="basic height"></fieldset></div>
+ <br>
+
+ <div class="container"><fieldset class="basic width"></fieldset></div>
+ <br>
+
+ <div class="container"><fieldset class="basic width"></fieldset></div>
+ <br>
+
+ <fieldset class="height"><legend>legend</legend></fieldset>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-fieldset-003.html b/testing/web-platform/tests/css/css-contain/contain-size-fieldset-003.html
new file mode 100644
index 0000000000..e618d44f6d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-fieldset-003.html
@@ -0,0 +1,99 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on fieldset elements should cause them to be sized as if they had no contents.</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-fieldset-003-ref.html">
+ <style>
+ .contain {
+ contain: size;
+ visibility: hidden;
+ border: none;
+ color: transparent;
+ }
+ .container {
+ border: 10px solid green;
+ display: inline-block;
+ vertical-align: top;
+ }
+ .innerContents {
+ height: 50px;
+ width: 50px;
+ }
+ .minHeight {
+ min-height: 30px;
+ }
+ .height {
+ height: 30px;
+ }
+ .minWidth {
+ min-width: 30px;
+ }
+ .width {
+ width: 30px;
+ }
+ </style>
+</head>
+<body>
+ <!--Note: The following .container class is used to help test if size-contained
+ fieldsets and non-contained fieldsets have the same size. Normally, we'd test
+ that a fieldset with children and size-containment is drawn identically to a
+ fieldset without containment or children. However, when we have a legend as
+ a child, border placement and padding of the fieldset are changed.
+ To check the dimensions between the ref-case and test-case without
+ failing because of the border/padding differences, we make the fieldset
+ {visibility:hidden; border:none;} and add a .container wrapper div.-->
+
+ <!--CSS Test: A size-contained fieldset element with no specified size should size itself as if it had no contents.-->
+ <div class="container">
+ <fieldset class="contain">
+ <legend>legend</legend>
+ <div class="innerContents">inner</div>
+ </fieldset>
+ </div>
+ <br>
+
+ <!--CSS Test: A size-contained fieldset element with specified min-height should size itself as if it had no contents.-->
+ <div class="container">
+ <fieldset class="contain minHeight">
+ <legend>legend</legend>
+ <div class="innerContents">inner</div>
+ </fieldset>
+ </div>
+ <br>
+
+ <!--CSS Test: A size-contained fieldset element with specified height should size itself as if it had no contents.-->
+ <div class="container">
+ <fieldset class="contain height">
+ <legend>legend</legend>
+ <div class="innerContents">inner</div>
+ </fieldset>
+ </div>
+ <br>
+
+ <!--CSS Test: A size-contained fieldset element with specified min-width should size itself as if it had no contents.-->
+ <div class="container">
+ <fieldset class="contain minWidth">
+ <legend>legend</legend>
+ <div class="innerContents">inner</div>
+ </fieldset>
+ </div>
+ <br>
+
+ <!--CSS Test: A size-contained fieldset element with specified width should size itself as if it had no contents.-->
+ <div class="container">
+ <fieldset class="contain width">
+ <legend>legend</legend>
+ <div class="innerContents">inner</div>
+ </fieldset>
+ </div>
+ <br>
+
+ <!--CSS Test: A size contained fieldset element with a legend should draw its legend and border in the same way as a non-contained fieldset element-->
+ <fieldset class="height" style="contain:size;">
+ <legend>legend</legend>
+ </fieldset>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-fieldset-004-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-fieldset-004-ref.html
new file mode 100644
index 0000000000..59f7c7e2a7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-fieldset-004-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .container {
+ border: 10px solid green;
+ display: inline-block;
+ }
+ .floatLBasic-ref {
+ float: left;
+ }
+ .floatLWidth-ref {
+ float: left;
+ width: 30px;
+ }
+ .flexBaselineCheck {
+ display: flex;
+ align-items: baseline;
+ }
+ fieldset {
+ border: none;
+ color: transparent;
+ }
+ legend, .innerContents {
+ width: 0;
+ padding: 0;
+ }
+ </style>
+</head>
+<body>
+ <div class="flexBaselineCheck">
+ outside before<fieldset>
+ <legend>l</legend>
+ <div class="innerContents">i</div>
+ </fieldset>outside after
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-fieldset-004.html b/testing/web-platform/tests/css/css-contain/contain-size-fieldset-004.html
new file mode 100644
index 0000000000..2ea5d2583b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-fieldset-004.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on fieldset elements shouldn't prevent them from being baseline-aligned regularly.</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-fieldset-004-ref.html">
+ <style>
+ .contain {
+ contain: size;
+ border: none;
+ color: transparent;
+ visibility: hidden;
+ }
+ .innerContents {
+ height: 50px;
+ width: 50px;
+ }
+ .flexBaselineCheck {
+ display: flex;
+ align-items: baseline;
+ }
+ </style>
+</head>
+<body>
+ <!--CSS Test: A size-contained fieldset element should perform baseline alignment regularly.-->
+ <div class="flexBaselineCheck">
+ outside before<fieldset class="contain">
+ <legend>legend</legend>
+ <div class="innerContents">inner</div>
+ </fieldset>outside after
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-flex-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-flex-001-ref.html
new file mode 100644
index 0000000000..995c45197f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-flex-001-ref.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .basic {
+ display: flex;
+ border: 1em solid green;
+ }
+ .height-ref {
+ height: 40px;
+ background: lightblue;
+ }
+ .width-ref {
+ width: 40px;
+ }
+ .floatLBasic-ref {
+ float: left;
+ }
+ .floatLWidth-ref {
+ float: left;
+ width: 40px;
+ }
+ </style>
+</head>
+<body>
+ <div class="basic"></div>
+ <br>
+
+ <div class="basic height-ref"></div>
+ <br>
+
+ <div class="basic height-ref"></div>
+ <br>
+
+ <div class="basic width-ref"></div>
+ <br>
+
+ <div class="basic width-ref"></div>
+ <br>
+
+ <div class="basic floatLBasic-ref"></div>
+ <br>
+
+ <div class="basic floatLWidth-ref"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-flex-001.html b/testing/web-platform/tests/css/css-contain/contain-size-flex-001.html
new file mode 100644
index 0000000000..72ab97043b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-flex-001.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on flex elements should cause them to be sized as if they had no contents.</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-flex-001-ref.html">
+ <style>
+ .contain {
+ display: flex;
+ contain:size;
+ border: 1em solid green;
+ background: red;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ }
+ .minHeight {
+ min-height: 40px;
+ background: lightblue;
+ }
+ .height {
+ height: 40px;
+ background: lightblue;
+ }
+ .maxWidth {
+ max-width: 40px;
+ }
+ .width {
+ width: 40px;
+ }
+ .floatLBasic {
+ float: left;
+ }
+ .floatLWidth {
+ float: left;
+ width: 40px;
+ }
+ </style>
+</head>
+<body>
+ <!--CSS Test: A size-contained flex element with no specified size should render at 0 height regardless of content.-->
+ <div class="contain"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained flex element with specified min-height should render at given min-height regardless of content.-->
+ <div class="contain minHeight"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained flex element with specified height should render at given height regardless of content.-->
+ <div class="contain height"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained flex element with specified max-width should render at given max-width and zero height regardless of content.-->
+ <div class="contain maxWidth"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained flex element with specified width should render at given width and zero height regardless of content.-->
+ <div class="contain width"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained floated flex element with no specified size should render at 0px by 0px regardless of content.-->
+ <div class="contain floatLBasic"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained floated flex element with specified width and no specified height should render at given width and 0 height regardless of content.-->
+ <div class="contain floatLWidth"><div class="innerContents">inner</div></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-flexbox-001.html b/testing/web-platform/tests/css/css-contain/contain-size-flexbox-001.html
new file mode 100644
index 0000000000..16ba62eda0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-flexbox-001.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on flexbox container</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/contain-size-flexbox-001-ref.html">
+<meta name=assert content="Size containment does apply to flexbox containers, thus their size is the same than if they don't have contents.">
+<style>
+div {
+ display: inline-flex;
+ border: 5px solid green;
+ contain: size;
+ color: transparent;
+ font-size: 2em;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the top, and then the word "after".</p>
+before<div>flex</div>after
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-flexbox-002.html b/testing/web-platform/tests/css/css-contain/contain-size-flexbox-002.html
new file mode 100644
index 0000000000..531af691af
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-flexbox-002.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>Tests that scrollbars are handled correctly in a flex item with contains:size</title>
+<link rel="author" title="Google LLC" href="https://www.google.com">
+<link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+<link rel="match" href="reference/contain-size-flexbox-002-ref.html">
+
+<style>
+div > div {
+ vertical-align: top;
+ display: inline-block;
+ contain: size;
+ overflow: scroll;
+ border: 1px solid;
+}
+</style>
+
+<p>Test passes if the two lines below look the same.</p>
+
+<div style="display: flex; line-height: 1.0;">
+ <div></div>
+</div>
+
+<div style="line-height: 1.0;">
+ <div></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-grid-001.html b/testing/web-platform/tests/css/css-contain/contain-size-grid-001.html
new file mode 100644
index 0000000000..4510c1e553
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-grid-001.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on grid container</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/contain-size-grid-001-ref.html">
+<meta name=assert content="Size containment does apply to grid containers, thus their size is the same than if they don't have contents.">
+<style>
+div {
+ display: inline-grid;
+ border: 5px solid green;
+ contain: size;
+ color: transparent;
+ font-size: 2em;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the top, and then the word "after".</p>
+before<div>grid</div>after
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-grid-002.html b/testing/web-platform/tests/css/css-contain/contain-size-grid-002.html
new file mode 100644
index 0000000000..43361c2983
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-grid-002.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on grid container with explicit non-intrinsically sized tracks (and gaps)</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<meta name=assert content="grid-gap, grid-template-columns, and grid-template-rows do affect the size of the grid, even with size containment">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+<style>
+body {
+ overflow: hidden;
+}
+div {
+ position: absolute;
+}
+#red {
+ background: red;
+ width: 100px;
+ height: 100px;
+}
+#test {
+ background: green;
+
+ contain: size;
+ display: grid;
+ grid-gap: 20px;
+ grid-template-columns: auto 80px; /* 0 + 20 + 80 = 100 */
+ grid-template-rows: 40px 40px; /* 40 + 20 + 40 = 100 */
+ font-size: 800px;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id=red></div>
+<div id=test>&nbsp;</div>
+
+<!--
+The &nbsp;, auto sized column, and 800px font size
+are to make the test fail in browsers
+that do not implement contain:size at all,
+by making the box non square.
+-->
+
+
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-grid-003.html b/testing/web-platform/tests/css/css-contain/contain-size-grid-003.html
new file mode 100644
index 0000000000..44b736b1d6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-grid-003.html
@@ -0,0 +1,201 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on grid containers</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<meta name=assert content="Size containment does apply to grid containers, thus their size is the same than if they don't have contents but taking into account the track sizes.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.grid {
+ display: inline-grid;
+ contain: size;
+ position: relative;
+ font: 10px/1 Ahem;
+}
+.wrapper {
+ width: 300px;
+ height: 150px;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<body onload="checkLayout('.grid')">
+
+<div id="log"></div>
+
+<div class="grid" style="grid: 50px / 100px;"
+ data-expected-width="100" data-expected-height="50">
+</div>
+
+<div class="grid" style="grid: 50px / 100px; width: 200px; height: 100px;"
+ data-expected-width="200" data-expected-height="100">
+</div>
+
+<div class="grid" style="grid: 50px / 100px; width: min-content; height: min-content;"
+ data-expected-width="100" data-expected-height="50">
+</div>
+
+<div class="grid" style="grid: 50px / 100px; overflow: scroll;"
+ data-expected-width="115" data-expected-height="65">
+</div>
+
+<div class="grid" style="grid: 50px / 100px; width: 200px; height: 100px; overflow: scroll;"
+ data-expected-width="200" data-expected-height="100">
+</div>
+
+<div class="grid" style="grid: 50px / 100px; width: min-content; height: min-content; overflow: scroll;"
+ data-expected-width="115" data-expected-height="65">
+</div>
+
+<div class="grid" style="grid: 50px / 100px; margin: 2px 4px;"
+ data-expected-width="100" data-expected-height="50">
+</div>
+
+<div class="grid" style="grid: 50px / 100px; margin: 2px 4px; border-style: solid; border-width: 5px 10px;"
+ data-expected-width="120" data-expected-height="60">
+</div>
+
+<div class="grid" style="grid: 50px / 100px; margin: 2px 4px; border-style: solid; border-width: 5px 10px; padding: 3px 6px;"
+ data-expected-width="132" data-expected-height="66">
+</div>
+
+<div class="grid" style="grid: 60% / 50%;"
+ data-expected-width="0" data-expected-height="0">
+</div>
+
+<div class="grid" style="grid: auto / auto;"
+ data-expected-width="0" data-expected-height="0">
+</div>
+
+<div class="grid" style="grid: 1fr / 2fr;"
+ data-expected-width="0" data-expected-height="0">
+</div>
+
+<div class="grid" style="grid: calc(50px - 10%) / calc(100px + 20%);"
+ data-expected-width="0" data-expected-height="0">
+</div>
+
+<div class="grid" style="grid: fit-content(50px) / fit-content(100px);"
+ data-expected-width="0" data-expected-height="0">
+</div>
+
+<div class="grid" style="grid: minmax(40px, 60px) / minmax(50px, 100px);"
+ data-expected-width="100" data-expected-height="60">
+</div>
+
+<div class="grid" style="grid: minmax(40px, 60px) / minmax(50px, 100px); width: min-content; height: min-content;"
+ data-expected-width="50" data-expected-height="60">
+</div>
+
+<div class="grid" style="grid: auto 50px 20% 1fr / 100px auto 10% 2fr;"
+ data-expected-width="100" data-expected-height="50">
+</div>
+
+<div class="grid" style="grid: repeat(3, 20px) / repeat(4, 25px);"
+ data-expected-width="100" data-expected-height="60">
+</div>
+
+<div class="grid" style="grid: repeat(3, 20px 10px) / repeat(2, 25px auto 25px);"
+ data-expected-width="100" data-expected-height="90">
+</div>
+
+<div class="grid" style="grid: repeat(auto-fill, 50px) / repeat(auto-fill, 100px);"
+ data-expected-width="100" data-expected-height="50">
+</div>
+
+<div class="grid" style="grid: repeat(auto-fill, 25px 25px) / repeat(auto-fill, 50px 50px);"
+ data-expected-width="100" data-expected-height="50">
+</div>
+
+<div class="grid" style="grid: repeat(auto-fill, 25px 20% 25px) / repeat(auto-fill, 50px 10% 50px);"
+ data-expected-width="100" data-expected-height="50">
+</div>
+
+<div class="grid" style="grid: repeat(auto-fit, 50px) / repeat(auto-fit, 100px);"
+ data-expected-width="0" data-expected-height="0">
+</div>
+
+<div class="grid" style="grid: repeat(auto-fit, 25px 20% 25px) / repeat(auto-fit, 50px 10% 50px);"
+ data-expected-width="0" data-expected-height="0">
+</div>
+
+<div class="grid" style="grid: 10px repeat(auto-fill, 20px) 10px / 25px repeat(auto-fill, 50px) 25px;"
+ data-expected-width="100" data-expected-height="40">
+</div>
+
+<div class="grid" style="grid: 50px fit-content(20px) / 100px fit-content(50px);"
+ data-expected-width="100" data-expected-height="50">
+</div>
+
+<div class="grid" style="grid: 50px / 100px; grid-gap: 10px 20px;"
+ data-expected-width="100" data-expected-height="50">
+</div>
+
+<div class="grid" style="grid: 25px 25px / 50px 50px; grid-gap: 10px 20px;"
+ data-expected-width="120" data-expected-height="60">
+</div>
+
+<div class="grid" style="grid: 10px repeat(2, 10px) / 20px repeat(4, 20px); grid-gap: 5px 10px;"
+ data-expected-width="140" data-expected-height="40">
+</div>
+
+<div class="grid" style="grid: repeat(auto-fill, 10px 20% 10px) / repeat(auto-fill, 20px 10% 20px); grid-gap: 5px 10px;"
+ data-expected-width="60" data-expected-height="30">
+</div>
+
+<div class="grid" style="grid: 50px repeat(auto-fill, 10px 10px) / 100px repeat(auto-fill, 20px 20px); grid-gap: 5px 10px;"
+ data-expected-width="160" data-expected-height="80">
+</div>
+
+<div class="grid" style="grid: repeat(auto-fill, 10px 10px) 50px / repeat(auto-fill, 20px 20px) 100px; grid-gap: 5px 10px;"
+ data-expected-width="160" data-expected-height="80">
+</div>
+
+<div class="grid" style="grid: 25px repeat(auto-fill, 10px 10px) 25px / 50px repeat(auto-fill, 20px 20px) 50px; grid-gap: 5px 10px;"
+ data-expected-width="170" data-expected-height="85">
+</div>
+
+<div class="grid" style="grid: 25px repeat(auto-fit, 10px 10px) 25px / 50px repeat(auto-fit, 20px 20px) 50px; grid-gap: 5px 10px;"
+ data-expected-width="110" data-expected-height="55">
+</div>
+
+<div class="wrapper">
+ <div class="grid" style="grid: repeat(auto-fill, 75px) / repeat(auto-fill, 100px);"
+ data-expected-width="100" data-expected-height="75">
+ </div>
+</div>
+
+<div class="wrapper">
+ <div class="grid" style="grid: repeat(auto-fit, 75px) / repeat(auto-fit, 100px);"
+ data-expected-width="0" data-expected-height="0">
+ </div>
+</div>
+
+<div class="wrapper">
+ <div class="grid" style="grid: repeat(auto-fill, 75px) / repeat(auto-fill, 100px);"
+ data-expected-width="100" data-expected-height="75">
+ <div></div>
+ </div>
+</div>
+
+<div class="wrapper">
+ <div class="grid" style="grid: repeat(auto-fit, 75px) / repeat(auto-fit, 100px);"
+ data-expected-width="0" data-expected-height="0">
+ <div></div>
+ </div>
+</div>
+
+<div class="grid" style="grid: auto 50px / 100px auto;"
+ data-expected-width="100" data-expected-height="50">
+ <div data-expected-width="100" data-expected-height="10"
+ data-offset-x="0" data-offset-y="0">X</div>
+ <div data-expected-width="40" data-expected-height="10"
+ data-offset-x="100" data-offset-y="0">XX</div>
+ <div data-expected-width="100" data-expected-height="50"
+ data-offset-x="0" data-offset-y="10">XXX</div>
+ <div data-expected-width="40" data-expected-height="50"
+ data-offset-x="100" data-offset-y="10">XXXX</div>
+</div>
+
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-grid-004.html b/testing/web-platform/tests/css/css-contain/contain-size-grid-004.html
new file mode 100644
index 0000000000..c333c03298
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-grid-004.html
@@ -0,0 +1,210 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on grid containers with percentages</title>
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<meta name="assert" content="Checks that grid containers with size containment and their grid items are sized correctly when the track sizing functions contain percentages.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.grid {
+ display: grid;
+ contain: size;
+ font: 75px/1 Ahem;
+}
+.min-content {
+ height: min-content;
+ width: min-content;
+}
+.max-content {
+ height: max-content;
+ width: max-content;
+}
+.fixed {
+ height: 100px;
+ width: 100px;
+}
+.percent {
+ grid: 50% / 200%;
+}
+.calc {
+ grid: calc(100px + 50%) / calc(100px + 200%);
+}
+.minmax-percent-fixed {
+ grid: minmax(50%, 100px) / minmax(200%, 100px);
+}
+.minmax-fixed-percent {
+ grid: minmax(100px, 50%) / minmax(100px, 200%);
+}
+.minmax-percent-flex {
+ grid: minmax(50%, 1fr) / minmax(200%, 1fr);
+}
+.minmax-percent-intrinsic {
+ grid: minmax(50%, min-content) / minmax(200%, min-content);
+}
+.minmax-intrinsic-percent {
+ grid: minmax(min-content, 50%) / minmax(min-content, 200%);
+}
+.fit-content {
+ grid: fit-content(50%) / fit-content(200%);
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<body onload="checkLayout('.grid')">
+
+<div id="log"></div>
+
+<div class="grid percent min-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="0" data-expected-width="0"></div>
+</div>
+<div class="grid percent min-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="0" data-expected-width="0">XXXX</div>
+</div>
+<div class="grid percent max-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="0" data-expected-width="0"></div>
+</div>
+<div class="grid percent max-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="0" data-expected-width="0">XXXX</div>
+</div>
+<div class="grid percent fixed" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="50" data-expected-width="200"></div>
+</div>
+<div class="grid percent fixed" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="50" data-expected-width="200">XXXX</div>
+</div>
+
+<div class="grid calc min-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="100" data-expected-width="100"></div>
+</div>
+<div class="grid calc min-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="100" data-expected-width="100">XXXX</div>
+</div>
+<div class="grid calc max-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="100" data-expected-width="100"></div>
+</div>
+<div class="grid calc max-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="100" data-expected-width="100">XXXX</div>
+</div>
+<div class="grid calc fixed" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="150" data-expected-width="300"></div>
+</div>
+<div class="grid calc fixed" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="150" data-expected-width="300">XXXX</div>
+</div>
+
+<div class="grid minmax-percent-fixed min-content" data-expected-height="100" data-expected-width="0">
+ <div data-expected-height="100" data-expected-width="0"></div>
+</div>
+<div class="grid minmax-percent-fixed min-content" data-expected-height="100" data-expected-width="0">
+ <div data-expected-height="100" data-expected-width="0">XXXX</div>
+</div>
+<div class="grid minmax-percent-fixed max-content" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="100" data-expected-width="200"></div>
+</div>
+<div class="grid minmax-percent-fixed max-content" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="100" data-expected-width="200">XXXX</div>
+</div>
+<div class="grid minmax-percent-fixed fixed" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="100" data-expected-width="200"></div>
+</div>
+<div class="grid minmax-percent-fixed fixed" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="100" data-expected-width="200">XXXX</div>
+</div>
+
+<div class="grid minmax-fixed-percent min-content" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="100" data-expected-width="100"></div>
+</div>
+<div class="grid minmax-fixed-percent min-content" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="100" data-expected-width="100">XXXX</div>
+</div>
+<div class="grid minmax-fixed-percent max-content" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="100" data-expected-width="100"></div>
+</div>
+<div class="grid minmax-fixed-percent max-content" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="100" data-expected-width="100">XXXX</div>
+</div>
+<div class="grid minmax-fixed-percent fixed" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="100" data-expected-width="100"></div>
+</div>
+<div class="grid minmax-fixed-percent fixed" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="100" data-expected-width="100">XXXX</div>
+</div>
+
+<div class="grid minmax-percent-flex min-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="0" data-expected-width="0"></div>
+</div>
+<div class="grid minmax-percent-flex min-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="0" data-expected-width="0">XXXX</div>
+</div>
+<div class="grid minmax-percent-flex max-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="0" data-expected-width="0"></div>
+</div>
+<div class="grid minmax-percent-flex max-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="0" data-expected-width="0">XXXX</div>
+</div>
+<div class="grid minmax-percent-flex fixed" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="100" data-expected-width="200"></div>
+</div>
+<div class="grid minmax-percent-flex fixed" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="100" data-expected-width="200">XXXX</div>
+</div>
+
+<div class="grid minmax-intrinsic-percent min-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="0" data-expected-width="0"></div>
+</div>
+<div class="grid minmax-intrinsic-percent min-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="75" data-expected-width="300">XXXX</div>
+</div>
+<div class="grid minmax-intrinsic-percent max-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="0" data-expected-width="0"></div>
+</div>
+<div class="grid minmax-intrinsic-percent max-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="75" data-expected-width="300">XXXX</div>
+</div>
+<div class="grid minmax-intrinsic-percent fixed" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="50" data-expected-width="100"></div>
+</div>
+<div class="grid minmax-intrinsic-percent fixed" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="75" data-expected-width="300">XXXX</div>
+</div>
+
+<div class="grid minmax-percent-intrinsic min-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="0" data-expected-width="0"></div>
+</div>
+<div class="grid minmax-percent-intrinsic min-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="0" data-expected-width="0">XXXX</div>
+</div>
+<div class="grid minmax-percent-intrinsic max-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="0" data-expected-width="0"></div>
+</div>
+<div class="grid minmax-percent-intrinsic max-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="0" data-expected-width="0">XXXX</div>
+</div>
+<div class="grid minmax-percent-intrinsic fixed" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="50" data-expected-width="200"></div>
+</div>
+<div class="grid minmax-percent-intrinsic fixed" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="75" data-expected-width="200">XXXX</div>
+</div>
+
+<div class="grid fit-content min-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="0" data-expected-width="0"></div>
+</div>
+<div class="grid fit-content min-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="75" data-expected-width="300">XXXX</div>
+</div>
+<div class="grid fit-content max-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="0" data-expected-width="0"></div>
+</div>
+<div class="grid fit-content max-content" data-expected-height="0" data-expected-width="0">
+ <div data-expected-height="75" data-expected-width="300">XXXX</div>
+</div>
+<div class="grid fit-content fixed" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="0" data-expected-width="0"></div>
+</div>
+<div class="grid fit-content fixed" data-expected-height="100" data-expected-width="100">
+ <div data-expected-height="75" data-expected-width="300">XXXX</div>
+</div>
+
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-grid-005.html b/testing/web-platform/tests/css/css-contain/contain-size-grid-005.html
new file mode 100644
index 0000000000..bd750d2f54
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-grid-005.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on grid elements should cause them to be sized as if they had no contents.</title>
+ <link rel="author" title="Gerald Squelart" href="mailto:gsquelart@mozilla.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="reference/contain-size-grid-005-ref.html">
+ <style>
+ .contain {
+ display: grid;
+ contain:size;
+ border: 1em solid green;
+ background: red;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ }
+ .minHeight {
+ min-height: 40px;
+ background: lightblue;
+ }
+ .height {
+ height: 40px;
+ background: lightblue;
+ }
+ .maxWidth {
+ max-width: 40px;
+ }
+ .width {
+ width: 40px;
+ }
+ .floatLBasic {
+ float: left;
+ }
+ .floatLWidth {
+ float: left;
+ width: 40px;
+ }
+ </style>
+</head>
+<body>
+ <!--CSS Test: A size-contained grid element with no specified size should render at 0 height regardless of content.-->
+ <div class="contain"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained grid element with specified min-height should render at given min-height regardless of content.-->
+ <div class="contain minHeight"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained grid element with specified height should render at given height regardless of content.-->
+ <div class="contain height"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained grid element with specified max-width should render at given max-width and zero height regardless of content.-->
+ <div class="contain maxWidth"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained grid element with specified width should render at given width and zero height regardless of content.-->
+ <div class="contain width"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained floated grid element with no specified size should render at 0px by 0px regardless of content.-->
+ <div class="contain floatLBasic"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained floated grid element with specified width and no specified height should render at given width and 0 height regardless of content.-->
+ <div class="contain floatLWidth"><div class="innerContents">inner</div></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-grid-006.html b/testing/web-platform/tests/css/css-contain/contain-size-grid-006.html
new file mode 100644
index 0000000000..7bfbac1c6c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-grid-006.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Test: 'contain: size' on grid elements should cause them to be sized as if they had no contents.</title>
+<link rel="author" title="Ethan Jimenez" href="mailto:ethavar@microsoft.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+<style>
+.grid {
+ display: inline-grid;
+ contain: size;
+ border: 5px solid green;
+ background: lightblue;
+}
+.item {
+ color: transparent;
+ grid-column: 1 / -1;
+ grid-row: 1 / -1;
+ height: 100px;
+ width: 100px;
+}
+.min-size {
+ min-height: 55px;
+ min-width: 55px;
+}
+.max-size {
+ max-height: 70px;
+ max-width: 70px;
+}
+.auto-tracks {
+ grid-template-columns: auto auto;
+ grid-template-rows: auto auto;
+}
+.fixed-tracks {
+ grid-template-columns: 70px 30px;
+ grid-template-rows: 30px 70px;
+}
+.fr-tracks {
+ grid-template-columns: 1fr 2fr;
+ grid-template-rows: 2fr 1fr;
+}
+.auto-repeat-tracks {
+ grid-template-columns: repeat(auto-fill, 40px);
+ grid-template-rows: repeat(auto-fill, 40px);
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+</head>
+<body onload="checkLayout('.grid')">
+<div id="log"></div>
+
+<div class="grid auto-tracks" data-expected-height="10" data-expected-width="10"><div class="item"></div></div>
+<div class="grid min-size auto-tracks" data-expected-height="65" data-expected-width="65"><div class="item"></div></div>
+<div class="grid max-size auto-tracks" data-expected-height="10" data-expected-width="10"><div class="item"></div></div>
+<div class="grid min-size max-size auto-tracks" data-expected-height="65" data-expected-width="65"><div class="item"></div></div>
+
+<div class="grid fixed-tracks" data-expected-height="110" data-expected-width="110"><div class="item"></div></div>
+<div class="grid min-size fixed-tracks" data-expected-height="110" data-expected-width="110"><div class="item"></div></div>
+<div class="grid max-size fixed-tracks" data-expected-height="80" data-expected-width="80"><div class="item"></div></div>
+<div class="grid min-size max-size fixed-tracks" data-expected-height="80" data-expected-width="80"><div class="item"></div></div>
+
+<div class="grid fr-tracks" data-expected-height="10" data-expected-width="10"><div class="item"></div></div>
+<div class="grid min-size fr-tracks" data-expected-height="65" data-expected-width="65"><div class="item"></div></div>
+<div class="grid max-size fr-tracks" data-expected-height="10" data-expected-width="10"><div class="item"></div></div>
+<div class="grid min-size max-size fr-tracks" data-expected-height="65" data-expected-width="65"><div class="item"></div></div>
+
+<div class="grid auto-repeat-tracks" data-expected-height="50" data-expected-width="50"><div class="item"></div></div>
+<div class="grid min-size auto-repeat-tracks" data-expected-height="90" data-expected-width="90"><div class="item"></div></div>
+<div class="grid max-size auto-repeat-tracks" data-expected-height="50" data-expected-width="50"><div class="item"></div></div>
+<div class="grid min-size max-size auto-repeat-tracks" data-expected-height="65" data-expected-width="65"><div class="item"></div></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-grid-indefinite-height-min-height-flex-row.html b/testing/web-platform/tests/css/css-contain/contain-size-grid-indefinite-height-min-height-flex-row.html
new file mode 100644
index 0000000000..5899475fc2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-grid-indefinite-height-min-height-flex-row.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="author" title="Sammy Gill" href="mailto:sammy.gill@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+<link rel="help" href="https://drafts.csswg.org/css-grid-2/#algo-flex-tracks">
+<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="Grid with size containment, an indefinite height, and min-height will properly size flex rows">
+<style>
+grid {
+ display: grid;
+ min-height: 100px;
+ grid-template-rows: 1fr;
+ contain: size;
+}
+.absolute {
+ position: absolute;
+}
+.align-last-baseline{
+ align-self: last baseline;
+}
+.item {
+ width: 100px;
+ height: 50px;
+ background-color: green;
+}
+</style>
+</head>
+<body>
+ <p>Test passes if there is a filled green square.</p>
+ <grid>
+ <div class="absolute item"></div>
+ <div class="item align-last-baseline"></div>
+ </grid>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-grid-stretches-auto-rows.html b/testing/web-platform/tests/css/css-contain/contain-size-grid-stretches-auto-rows.html
new file mode 100644
index 0000000000..10b84665aa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-grid-stretches-auto-rows.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="author" title="Sammy Gill" href="mailto:sammy.gill@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#size-containment">
+<link rel="help" href="https://drafts.csswg.org/css-grid-2/#algo-stretch">
+<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="grid with size containment, and min-height will still distribute extra space to auto rows">
+<style>
+grid {
+ display: grid;
+ min-height: 100px;
+ grid-template-rows: auto;
+ contain: size;
+}
+.absolute {
+ position: absolute;
+}
+.align-end {
+ align-self: end;
+}
+.item {
+ width: 100px;
+ height: 50px;
+ background-color: green;
+}
+</style>
+</head>
+<body>
+ <p>Test passes if there is a filled green square.</p>
+ <grid>
+ <div class="absolute item"></div>
+ <div class="item align-end"></div>
+ </grid>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-inline-block-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-inline-block-001-ref.html
new file mode 100644
index 0000000000..92a6c7de5e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-inline-block-001-ref.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .basic {
+ display: inline-block;
+ border: 1em solid green;
+ }
+ .height-ref {
+ height: 50px;
+ }
+ .width-ref {
+ width: 50px;
+ }
+ .innerContents {
+ color: transparent;
+ width: 0;
+ height: 0;
+ }
+ </style>
+</head>
+<body>
+ <div class="basic"><div class="innerContents">i</div></div>
+ <br>
+
+ outside before<div class="basic"><div class="innerContents">i</div></div>outside after
+ <br>
+
+ <div class="basic height-ref"><div class="innerContents">i</div></div>
+ <br>
+
+ <div class="basic height-ref"><div class="innerContents">i</div></div>
+ <br>
+
+ <div class="basic width-ref"><div class="innerContents">i</div></div>
+ <br>
+
+ <div class="basic width-ref"><div class="innerContents">i</div></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-inline-block-001.html b/testing/web-platform/tests/css/css-contain/contain-size-inline-block-001.html
new file mode 100644
index 0000000000..4145855027
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-inline-block-001.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on inline-block elements should cause them to be sized as if they had no contents and baseline-aligned regularly.</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-inline-block-001-ref.html">
+ <style>
+ .contain {
+ display: inline-block;
+ contain:size;
+ border: 1em solid green;
+ background: red;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ }
+ .minHeight {
+ min-height: 50px;
+ }
+ .height {
+ height: 50px;
+ }
+ .minWidth {
+ min-width: 50px;
+ }
+ .width {
+ width: 50px;
+ }
+ </style>
+</head>
+<body>
+ <!--CSS Test: A size-contained inline-block element with no specified size should render at 0 height and 0 width regardless of content.-->
+ <div class="contain"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained inline-block element should perform baseline alignment regularly.-->
+ outside before<div class="contain"><div class="innerContents">inner</div></div>outside after
+ <br>
+
+ <!--CSS Test: A size-contained inline-block element with specified min-height should render at given min-height and 0 width regardless of content.-->
+ <div class="contain minHeight"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained inline-block element with specified height should render at given height and 0 width regardless of content.-->
+ <div class="contain height"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained inline-block element with specified min-width should render at given min-width and 0 height regardless of content.-->
+ <div class="contain minWidth"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained inline-block element with specified width should render at given width and 0 height regardless of content.-->
+ <div class="contain width"><div class="innerContents">inner</div></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-inline-block-002-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-inline-block-002-ref.html
new file mode 100644
index 0000000000..3d0f38f7c0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-inline-block-002-ref.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .basic {
+ display: inline-block;
+ overflow: scroll;
+ position: relative;
+ border: 2px solid green;
+ }
+ .height-ref {
+ height: 60px;
+ }
+ .width-ref {
+ width: 60px;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ position: absolute;
+ }
+ </style>
+</head>
+<body>
+ <!-- NOTE: In the reference-case scenarios here, we use the same DOM as in
+ the testcase, and we simply use 'position: absolute' on the descendants
+ wherever the testcase has 'contain: size' on the container. This
+ produces an accurate reference rendering, because out-of-flow content
+ doesn't contribute to the container's sizing, but does create scrollable
+ overflow (i.e. it produces scrollbars of the appropriate size for the
+ amount of overflow). -->
+ <div class="basic"><div class="innerContents">inner</div></div>
+ <br>
+
+ outside before
+ <div class="basic"><div class="innerContents">inner</div></div>
+ outside after
+ <br>
+
+ <div class="basic height-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic height-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic width-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic width-ref"><div class="innerContents">inner</div></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-inline-block-002.html b/testing/web-platform/tests/css/css-contain/contain-size-inline-block-002.html
new file mode 100644
index 0000000000..d3a69e5f35
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-inline-block-002.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on 'overflow:scroll' inline-block elements should cause them to be sized as if they had no contents and baseline-aligned regularly.</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-inline-block-002-ref.html">
+ <style>
+ .contain {
+ display: inline-block;
+ overflow: scroll;
+ contain:size;
+ border: 2px solid green;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ }
+ .minHeight {
+ min-height: 60px;
+ }
+ .height {
+ height: 60px;
+ }
+ .minWidth {
+ min-width: 60px;
+ }
+ .width {
+ width: 60px;
+ }
+ </style>
+</head>
+<body>
+ <!-- NOTE: In all cases below, the expectation is that the size-contained
+ element should be sized as if it had no contents (while honoring
+ whatever sizing properties are provided). -->
+
+ <!-- A size-contained scrollable inline-block with no specified size -->
+ <div class="contain"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!-- A size-contained scrollable inline-block should perform baseline
+ alignment regularly, based on contents' baseline. -->
+ outside before
+ <div class="contain"><div class="innerContents">inner</div></div>
+ outside after
+ <br>
+
+ <!-- A size-contained scrollable inline-block with specified min-height -->
+ <div class="contain minHeight"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!-- A size-contained scrollable inline-block with specified height -->
+ <div class="contain height"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!-- A size-contained scrollable inline-block with specified min-width -->
+ <div class="contain minWidth"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!-- A size-contained scrollable inline-block with specified width -->
+ <div class="contain width"><div class="innerContents">inner</div></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-inline-block-003-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-inline-block-003-ref.html
new file mode 100644
index 0000000000..6079764591
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-inline-block-003-ref.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .basic {
+ display: inline-block;
+ overflow: auto;
+ position: relative;
+ border: 2px solid green;
+ }
+ .height-ref {
+ height: 60px;
+ }
+ .width-ref {
+ width: 60px;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ position: absolute;
+ }
+ </style>
+</head>
+<body>
+ <!-- NOTE: In the reference-case scenarios here, we use the same DOM as in
+ the testcase, and we simply use 'position: absolute' on the descendants
+ wherever the testcase has 'contain: size' on the container. This
+ produces an accurate reference rendering, because out-of-flow content
+ doesn't contribute to the container's sizing, but does create scrollable
+ overflow (i.e. it produces scrollbars of the appropriate size for the
+ amount of overflow). -->
+ <div class="basic"><div class="innerContents">inner</div></div>
+ <br>
+
+ outside before
+ <div class="basic"><div class="innerContents">inner</div></div>
+ outside after
+ <br>
+
+ <div class="basic height-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic height-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic width-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic width-ref"><div class="innerContents">inner</div></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-inline-block-003.html b/testing/web-platform/tests/css/css-contain/contain-size-inline-block-003.html
new file mode 100644
index 0000000000..7ea22635d3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-inline-block-003.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on 'overflow:auto' inline-block elements should cause them to be sized as if they had no contents and baseline-aligned regularly.</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-inline-block-003-ref.html">
+ <style>
+ .contain {
+ display: inline-block;
+ overflow: auto;
+ contain:size;
+ border: 2px solid green;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ }
+ .minHeight {
+ min-height: 60px;
+ }
+ .height {
+ height: 60px;
+ }
+ .minWidth {
+ min-width: 60px;
+ }
+ .width {
+ width: 60px;
+ }
+ </style>
+</head>
+<body>
+ <!-- NOTE: In all cases below, the expectation is that the size-contained
+ element should be sized as if it had no contents (while honoring
+ whatever sizing properties are provided). -->
+
+ <!-- A size-contained scrollable inline-block with no specified size -->
+ <div class="contain"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!-- A size-contained scrollable inline-block should perform baseline
+ alignment regularly, based on contents' baseline. -->
+ outside before
+ <div class="contain"><div class="innerContents">inner</div></div>
+ outside after
+ <br>
+
+ <!-- A size-contained scrollable inline-block with specified min-height -->
+ <div class="contain minHeight"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!-- A size-contained scrollable inline-block with specified height -->
+ <div class="contain height"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!-- A size-contained scrollable inline-block with specified min-width -->
+ <div class="contain minWidth"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!-- A size-contained scrollable inline-block with specified width -->
+ <div class="contain width"><div class="innerContents">inner</div></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-inline-block-004-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-inline-block-004-ref.html
new file mode 100644
index 0000000000..e7f03ff2d3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-inline-block-004-ref.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .basic {
+ display: inline-block;
+ overflow: hidden;
+ position: relative;
+ border: 2px solid green;
+ }
+ .height-ref {
+ height: 60px;
+ }
+ .width-ref {
+ width: 60px;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ position: absolute;
+ }
+ </style>
+</head>
+<body>
+ <!-- NOTE: In the reference-case scenarios here, we use the same DOM as in
+ the testcase, and we simply use 'position: absolute' on the descendants
+ wherever the testcase has 'contain: size' on the container. This
+ produces an accurate reference rendering, because out-of-flow content
+ doesn't contribute to the container's sizing, but does create scrollable
+ overflow. -->
+ <div class="basic"><div class="innerContents">inner</div></div>
+ <br>
+
+ outside before
+ <div class="basic"><div class="innerContents">inner</div></div>
+ outside after
+ <br>
+
+ <div class="basic height-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic height-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic width-ref"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="basic width-ref"><div class="innerContents">inner</div></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-inline-block-004.html b/testing/web-platform/tests/css/css-contain/contain-size-inline-block-004.html
new file mode 100644
index 0000000000..1de39348b7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-inline-block-004.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on 'overflow:hidden' inline-block elements should cause them to be sized as if they had no contents and baseline-aligned regularly.</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-inline-block-004-ref.html">
+ <style>
+ .contain {
+ display: inline-block;
+ overflow: hidden;
+ contain:size;
+ border: 2px solid green;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ }
+ .minHeight {
+ min-height: 60px;
+ }
+ .height {
+ height: 60px;
+ }
+ .minWidth {
+ min-width: 60px;
+ }
+ .width {
+ width: 60px;
+ }
+ </style>
+</head>
+<body>
+ <!-- NOTE: In all cases below, the expectation is that the size-contained
+ element should be sized as if it had no contents (while honoring
+ whatever sizing properties are provided). -->
+
+ <!-- A size-contained scrollable inline-block with no specified size -->
+ <div class="contain"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!-- A size-contained scrollable inline-block should perform baseline
+ alignment regularly, based on contents' baseline. -->
+ outside before
+ <div class="contain"><div class="innerContents">inner</div></div>
+ outside after
+ <br>
+
+ <!-- A size-contained scrollable inline-block with specified min-height -->
+ <div class="contain minHeight"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!-- A size-contained scrollable inline-block with specified height -->
+ <div class="contain height"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!-- A size-contained scrollable inline-block with specified min-width -->
+ <div class="contain minWidth"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!-- A size-contained scrollable inline-block with specified width -->
+ <div class="contain width"><div class="innerContents">inner</div></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-inline-flex-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-inline-flex-001-ref.html
new file mode 100644
index 0000000000..93a263b5b2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-inline-flex-001-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .basic {
+ border: 1em solid green;
+ display: inline-flex;
+ }
+ .width-ref {
+ width: 50px;
+ }
+ .innerContents {
+ color: transparent;
+ width: 0;
+ height: 0;
+ }
+ </style>
+</head>
+<body>
+ aa<div class="basic"><div class="innerContents">i</div></div>bb
+ <br>
+
+ aa<div class="basic width-ref"><div class="innerContents">i</div></div>bb
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-inline-flex-001.html b/testing/web-platform/tests/css/css-contain/contain-size-inline-flex-001.html
new file mode 100644
index 0000000000..15a2c943bb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-inline-flex-001.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on inline-flex elements should cause them to be sized as if they had no contents and baseline-aligned regularly.</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-inline-flex-001-ref.html">
+ <style>
+ .contain {
+ display: inline-flex;
+ contain:size;
+ border: 1em solid green;
+ background: red;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ }
+ .width {
+ width: 50px;
+ }
+ </style>
+</head>
+<body>
+ <!--CSS Test: A size-contained inline-flex element without dimensions should ensure baseline alignment behaves regularly.-->
+ aa<div class="contain"><div class="innerContents">inner</div></div>bb
+ <br>
+
+ <!--CSS Test: A size-contained inline-flex element with specified width should ensure baseline alignment behaves regularly.-->
+ aa<div class="contain width"><div class="innerContents">inner</div></div>bb
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-monolithic-001.html b/testing/web-platform/tests/css/css-contain/contain-size-monolithic-001.html
new file mode 100644
index 0000000000..0e101bbab1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-monolithic-001.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: size' element is monolithic</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-multicol-1/#column-gaps-and-rules">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+ <link rel="match" href="reference/contain-size-monolithic-001-ref.html">
+
+ <meta content="This test checks that an element with size containment becomes monolithic. In this test, the only way to break the content of such monolithic element is to break (or slice) the content at each pair of characters. Since column rules are only drawn between two columns that both have content and since the test expects only 1 column filled with content, therefore the column rule should not be painted, thus the 'no red' test success condition." name="assert">
+ <meta name="fuzzy" content="maxDifference=0-16; totalPixels=0-2">
+
+ <style>
+ div#multi-column
+ {
+ column-count: 2;
+ column-fill: balance; /* balance is the initial column-fill value */
+ column-gap: 4ch;
+ column-rule: red solid 4ch;
+ column-width: 2ch;
+ font-family: monospace;
+ font-size: 20px;
+ width: 8ch;
+ }
+
+ div#size-contain
+ {
+ contain: size;
+ }
+ </style>
+
+ <p>Test passes if "AB", "CD", "EF" and "GH" are vertically aligned into 1 single column and if there is <strong>no red</strong>.
+
+ <div id="multi-column">
+ <div id="size-contain">AB CD EF GH</div>
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-monolithic-002.html b/testing/web-platform/tests/css/css-contain/contain-size-monolithic-002.html
new file mode 100644
index 0000000000..7f407df30b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-monolithic-002.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="UTF-8">
+ <title>CSS Containment Test: absolute positioned 'contain: size' element is monolithic</title>
+ <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+ <link rel="author" title="Mozilla" href="https://www.mozilla.org/">
+ <link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+ <link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+ <meta name="assert" content="This test checks that an absolute positioned element with size containment is monolithic.">
+
+ <style>
+ #multicol {
+ width: 300px;
+ column-count: 3;
+ }
+ #container {
+ position: relative;
+ }
+ #abs-size-contain {
+ position: absolute;
+ contain: size;
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ </style>
+
+ <p>Test passes if there is a filled green square.</p>
+ <div id="multicol">
+ <div id="container">
+ <div id="abs-size-contain"></div>
+ </div>
+ </div>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-multicol-001.html b/testing/web-platform/tests/css/css-contain/contain-size-multicol-001.html
new file mode 100644
index 0000000000..81465c02d6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-multicol-001.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on a multicol with set column size (and gap)</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<meta name=assert content="columns and column-gap do affect the size of a multicol, even with size containment">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+<style>
+div {
+ position: absolute;
+}
+#red {
+ background: red;
+ width: 100px;
+ height: 100px;
+}
+#test {
+ background: green;
+
+ contain: size;
+ columns: 2 40px;
+ column-gap: 20px;
+ min-height: 100px;
+
+ color: transparent;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id=red></div>
+<div id=test>
+filler filler filler filler filler filler filler filler
+filler filler filler filler filler filler filler filler
+filler filler filler filler filler filler filler filler
+filler filler filler filler filler filler filler filler
+</div>
+
+<!--
+The filler text, min-height (instead of height) and transparent color
+are to make the test fail in browsers
+that do not implement contain:size at all,
+by making the box non square.
+-->
+
+
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-multicol-002-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-multicol-002-ref.html
new file mode 100644
index 0000000000..c1c9f1388e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-multicol-002-ref.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .basic {
+ border: 1em solid green;
+ column-count: 3;
+ }
+ .height-ref {
+ height: 20px;
+ background: lightblue;
+ }
+ .width-ref {
+ width: 20px;
+ }
+ .floatLBasic-ref {
+ float: left;
+ }
+ .floatLWidth-ref {
+ float: left;
+ width: 20px;
+ }
+ </style>
+</head>
+<body>
+ <div class="basic"></div>
+ <br>
+
+ <div class="basic height-ref"></div>
+ <br>
+
+ <div class="basic height-ref"></div>
+ <br>
+
+ <div class="basic width-ref"></div>
+ <br>
+
+ <div class="basic width-ref"></div>
+ <br>
+
+ <div class="basic floatLBasic-ref"></div>
+ <br>
+
+ <div class="basic floatLWidth-ref"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-multicol-002.html b/testing/web-platform/tests/css/css-contain/contain-size-multicol-002.html
new file mode 100644
index 0000000000..0e35e2fed2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-multicol-002.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on multicol elements should cause them to be sized as if they had no contents.</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-multicol-002-ref.html">
+ <style>
+ .contain {
+ contain: size;
+ border: 1em solid green;
+ background: red;
+ column-count: 3;
+ }
+ .innerContents {
+ color: transparent;
+ height: 50px;
+ width: 50px;
+ }
+ .minHeight {
+ min-height: 20px;
+ background: lightblue;
+ }
+ .height {
+ height: 20px;
+ background: lightblue;
+ }
+ .maxWidth {
+ max-width: 20px;
+ }
+ .width {
+ width: 20px;
+ }
+ .floatLBasic {
+ float: left;
+ }
+ .floatLWidth {
+ float: left;
+ width: 20px;
+ }
+ </style>
+</head>
+<body>
+ <!--CSS Test: A size-contained multicol element with no specified size should render at 0 height regardless of content.-->
+ <div class="contain"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained multicol element with specified min-height should render at given min-height regardless of content.-->
+ <div class="contain minHeight"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained multicol element with specified height should render at given height regardless of content.-->
+ <div class="contain height"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained multicol element with specified max-width should render at given max-width and zero height regardless of content.-->
+ <div class="contain maxWidth"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained multicol element with specified width should render at given width and zero height regardless of content.-->
+ <div class="contain width"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained floated multicol element with no specified size should render at 0px by 0px regardless of content.-->
+ <div class="contain floatLBasic"><div class="innerContents">inner</div></div>
+ <br>
+
+ <!--CSS Test: A size-contained floated multicol element with specified width and no specified height should render at given width and 0 height regardless of content.-->
+ <div class="contain floatLWidth"><div class="innerContents">inner</div></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-multicol-003-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-multicol-003-ref.html
new file mode 100644
index 0000000000..af927aa268
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-multicol-003-ref.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .basic {
+ border: 1em solid green;
+ column-count: 3;
+ }
+ .innerContents {
+ color: transparent;
+ height: 0;
+ width: 0;
+ }
+ .col-width-ref {
+ column-width: 20px;
+ }
+ .col-gap-ref {
+ column-gap: 5px;
+ }
+ .flexBaselineCheck {
+ display: flex;
+ align-items: baseline;
+ }
+ .min {
+ width: min-content;
+ }
+ .max {
+ width: max-content;
+ }
+ </style>
+</head>
+<body>
+ <div class="flexBaselineCheck">
+ outside before
+ <div class="basic" style="max-height:0px">
+ <div class="innerContents">inner</div>
+ </div>
+ outside after
+ </div>
+ <br>
+
+ <div class="basic min col-width-ref"></div>
+ <br>
+
+ <div class="basic max col-width-ref"></div>
+ <br>
+
+ <div class="basic min col-gap-ref col-width-ref"></div>
+ <br>
+
+ <div class="basic max col-gap-ref col-width-ref"></div>
+ <br>
+
+ <div class="min">
+ <div class="basic"></div>
+ </div>
+ <br>
+
+ <div class="max">
+ <div class="basic"></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-multicol-003.html b/testing/web-platform/tests/css/css-contain/contain-size-multicol-003.html
new file mode 100644
index 0000000000..447e3cc98d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-multicol-003.html
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on multicol elements should cause them to be sized as if they had no contents</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-multicol-003-ref.html">
+ <style>
+ .contain {
+ contain: size;
+ border: 1em solid green;
+ background: red;
+ column-count: 3;
+ }
+ .innerContents {
+ color: transparent;
+ height: 100px;
+ width: 100px;
+ }
+ .col-width {
+ column-width: 20px;
+ }
+ .col-gap {
+ column-gap: 5px;
+ }
+ .flexBaselineCheck {
+ display: flex;
+ align-items: baseline;
+ }
+ .min {
+ width: min-content;
+ }
+ .max {
+ width: max-content;
+ }
+ </style>
+</head>
+<body>
+ <!-- This test verifies that contain:size doesn't interfere with the
+ determination of a multicol element's baseline. -->
+ <div class="flexBaselineCheck">
+ outside before
+ <div class="contain">
+ <div class="innerContents">inner</div>
+ </div>
+ outside after
+ </div>
+ <br>
+
+ <!--The following tests are used to ensure column-gaps and column-widths continue to contribute to the minimum and maximum width of a size-contained multicol element. Each should render as if it had no contents.-->
+
+ <div class="contain min col-width"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="contain max col-width"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="contain min col-gap col-width"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="contain max col-gap col-width"><div class="innerContents">inner</div></div>
+ <br>
+
+ <div class="min">
+ <div class="contain">
+ <div class="innerContents">inner</div>
+ </div>
+ </div>
+ <br>
+
+ <div class="max">
+ <div class="contain">
+ <div class="innerContents">inner</div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-multicol-004-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-multicol-004-ref.html
new file mode 100644
index 0000000000..32dd4b6ab6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-multicol-004-ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .cols {
+ column-count: 3;
+ column-rule: 1px dotted blue;
+ column-fill: auto;
+ border: 2px solid blue;
+ height: 50px;
+ width: 300px;
+ }
+ .innerObject {
+ height: 200px;
+ width: 100px;
+ background: orange;
+ }
+ </style>
+</head>
+ <body>
+ <div class="cols">
+ <canvas class="innerObject">
+ <!-- Note: We use a canvas object here as a generic reference for
+ something monolithic/non-fragmentable. -->
+ </canvas>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-multicol-004.html b/testing/web-platform/tests/css/css-contain/contain-size-multicol-004.html
new file mode 100644
index 0000000000..e63c213ab1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-multicol-004.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+ <title>CSS Test: 'contain: size' should force elements to be monolithic, i.e. to not fragment inside a multicol element.</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-multicol-004-ref.html">
+ <style>
+ .contain {
+ contain:size;
+ }
+ .cols {
+ column-count: 3;
+ column-rule: 1px dotted blue;
+ column-fill: auto;
+ border: 2px solid blue;
+ height: 50px;
+ width: 300px;
+ }
+ .innerObject {
+ height: 200px;
+ width: 100px;
+ background: orange;
+ }
+ </style>
+</head>
+ <body>
+ <div class="cols">
+ <div class="contain innerObject">
+ </div>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-multicol-as-flex-item.html b/testing/web-platform/tests/css/css-contain/contain-size-multicol-as-flex-item.html
new file mode 100644
index 0000000000..19aa12262f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-multicol-as-flex-item.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=863454">
+<style>
+ #flex {
+ display: flex;
+ }
+
+ #multicol {
+ columns: 3;
+ min-width: 0;
+ column-gap: 50px;
+ contain:size;
+ height:100px;
+ background:green;
+ }
+</style>
+<p>There should be a green square below.</p>
+<div id="flex">
+ <div id="multicol" data-expected-width="100" data-expected-height="100">
+ <div style="width:1000px; height:1px;"></div>
+ </div>
+</div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<script>
+ checkLayout("#flex");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-removed.html b/testing/web-platform/tests/css/css-contain/contain-size-removed.html
new file mode 100644
index 0000000000..9db8f44d63
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-removed.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Remove size from style.contain</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<meta name="assert" content="After removing size from style.contain, the element should trigger layout">
+<link rel="match" href="reference/pass_if_pass_below_clipped.html">
+<style>
+
+</style>
+<p>Test passes if there is the word "PASS" below.</p>
+<div id="container" style="contain: size; overflow: hidden;"><span>PASS</span></div>
+
+<script>
+window.requestAnimationFrame(() => {
+ document.getElementById("container").style.contain = "";
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-replaced-001.html b/testing/web-platform/tests/css/css-contain/contain-size-replaced-001.html
new file mode 100644
index 0000000000..b0dba02f1c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-replaced-001.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment replaced elements intrinsic size</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert content="This test checks that intrinsic size of replaced elements with 'contain: size' is zero.">
+<style>
+object {
+ background: green;
+ padding: 50px;
+ contain: size;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<object data="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect fill='red' width='100' height='100'/></svg>">
+</object>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-replaced-002.html b/testing/web-platform/tests/css/css-contain/contain-size-replaced-002.html
new file mode 100644
index 0000000000..20e4c8a1a6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-replaced-002.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment replaced elements intrinsic size</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert content="This test checks that intrinsic size of replaced elements with 'contain: size' is zero.">
+<style>
+svg {
+ background: green;
+ padding: 50px 0;
+ contain: size;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<svg width="100" viewBox="0 0 50 50">
+ <rect fill="red" width="50" height="50"/>
+</svg>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-replaced-003-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-replaced-003-ref.html
new file mode 100644
index 0000000000..cc574b0d56
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-replaced-003-ref.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference</title>
+<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<style>
+ video, audio, canvas, svg, img, embed, object, iframe {
+ border: 3px solid teal;
+ max-height: 0px;
+ max-width: 0px;
+ margin: 15px;
+ }
+</style>
+<body>
+ <!-- video element: -->
+ <video></video>
+ <video controls></video>
+ <video poster="support/blue-100x100.png"></video>
+ <video poster="support/blue-100x100.png" controls></video>
+ <video src="support/white.webm" controls></video>
+ <video src="support/white.webm" controls></video>
+ <br>
+
+ <!-- audio element with controls, and a few other misc replaced elements: -->
+ <audio controls></audio>
+ <canvas></canvas>
+ <svg></svg>
+ <br>
+
+ <!-- image elements: -->
+ <img src="broken">
+ <img src="support/blue-100x100.png">
+ <picture><source srcset="support/blue-100x100.png"><img></picture>
+ <br>
+
+ <!-- document-embedding elements (with & without a target resource that
+ could provide an intrinsic ratio in some cases, in the absence of
+ contain:size): -->
+ <embed>
+ <embed src="support/blue-100x100.png">
+ <object></object>
+ <object data="support/blue-100x100.png"></object>
+ <iframe></iframe>
+ <iframe src="support/blue-100x100.png"></iframe>
+ <br>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-replaced-003a.html b/testing/web-platform/tests/css/css-contain/contain-size-replaced-003a.html
new file mode 100644
index 0000000000..832e8b29f2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-replaced-003a.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: intrinsic size of size-contained replaced elems</title>
+<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+<link rel="match" href="contain-size-replaced-003-ref.html">
+<meta name=assert content="This test checks that various size-contained replaced elements have an intrinsic size of 0,0 regardless of their content.">
+<style>
+ video, audio, canvas, svg, img, embed, object, iframe {
+ border: 3px solid teal;
+ contain: size;
+ margin: 15px;
+ width: auto;
+ height: auto;
+ }
+</style>
+<body>
+ <!-- video element: -->
+ <video></video>
+ <video controls></video>
+ <video poster="support/blue-100x100.png"></video>
+ <video poster="support/blue-100x100.png" controls></video>
+ <video src="support/white.webm" controls></video>
+ <video src="support/white.webm" controls></video>
+ <br>
+
+ <!-- audio element with controls, and a few other misc replaced elements: -->
+ <audio controls></audio>
+ <canvas></canvas>
+ <svg></svg>
+ <br>
+
+ <!-- Image elements: -->
+ <img src="broken">
+ <img src="support/blue-100x100.png">
+ <picture><source srcset="support/blue-100x100.png"><img></picture>
+ <br>
+
+ <!-- Document-embedding elements (with & without a target resource that
+ could provide an intrinsic ratio in some cases, in the absence of
+ contain:size): -->
+ <embed>
+ <embed src="support/blue-100x100.png">
+ <object></object>
+ <object data="support/blue-100x100.png"></object>
+ <iframe></iframe>
+ <iframe src="support/blue-100x100.png"></iframe>
+ <br>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-replaced-003b.html b/testing/web-platform/tests/css/css-contain/contain-size-replaced-003b.html
new file mode 100644
index 0000000000..b6ae094ad3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-replaced-003b.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: intrinsic size of size-contained replaced elems, with explicit max-content width</title>
+<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+<link rel="match" href="contain-size-replaced-003-ref.html">
+<meta name=assert content="This test checks that various size-contained replaced elements have an intrinsic size of 0,0 regardless of their content.">
+<style>
+ video, audio, canvas, svg, img, embed, object, iframe {
+ border: 3px solid teal;
+ contain: size;
+ margin: 15px;
+ width: max-content; /* This means 0, given 'contain:size'. */
+ height: auto;
+ }
+</style>
+<body>
+ <!-- video element: -->
+ <video></video>
+ <video controls></video>
+ <video poster="support/blue-100x100.png"></video>
+ <video poster="support/blue-100x100.png" controls></video>
+ <video src="support/white.webm" controls></video>
+ <video src="support/white.webm" controls></video>
+ <br>
+
+ <!-- audio element with controls, and a few other misc replaced elements: -->
+ <audio controls></audio>
+ <canvas></canvas>
+ <svg></svg>
+ <br>
+
+ <!-- Image elements: -->
+ <img src="broken">
+ <img src="support/blue-100x100.png">
+ <picture><source srcset="support/blue-100x100.png"><img></picture>
+ <br>
+
+ <!-- Document-embedding elements (with & without a target resource that
+ could provide an intrinsic ratio in some cases, in the absence of
+ contain:size): -->
+ <embed>
+ <embed src="support/blue-100x100.png">
+ <object></object>
+ <object data="support/blue-100x100.png"></object>
+ <iframe></iframe>
+ <iframe src="support/blue-100x100.png"></iframe>
+ <br>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-replaced-003c.html b/testing/web-platform/tests/css/css-contain/contain-size-replaced-003c.html
new file mode 100644
index 0000000000..9018eaa685
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-replaced-003c.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: intrinsic size of size-contained replaced elems, with explicit max-content height</title>
+<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+<link rel="match" href="contain-size-replaced-003-ref.html">
+<meta name=assert content="This test checks that various size-contained replaced elements have an intrinsic size of 0,0 regardless of their content.">
+<style>
+ video, audio, canvas, svg, img, embed, object, iframe {
+ border: 3px solid teal;
+ contain: size;
+ margin: 15px;
+ height: max-content; /* This means 0, given 'contain:size'. */
+ width: auto;
+ }
+</style>
+<body>
+ <!-- video element: -->
+ <video></video>
+ <video controls></video>
+ <video poster="support/blue-100x100.png"></video>
+ <video poster="support/blue-100x100.png" controls></video>
+ <video src="support/white.webm" controls></video>
+ <video src="support/white.webm" controls></video>
+ <br>
+
+ <!-- audio element with controls, and a few other misc replaced elements: -->
+ <audio controls></audio>
+ <canvas></canvas>
+ <svg></svg>
+ <br>
+
+ <!-- Image elements: -->
+ <img src="broken">
+ <img src="support/blue-100x100.png">
+ <picture><source srcset="support/blue-100x100.png"><img></picture>
+ <br>
+
+ <!-- Document-embedding elements (with & without a target resource that
+ could provide an intrinsic ratio in some cases, in the absence of
+ contain:size): -->
+ <embed>
+ <embed src="support/blue-100x100.png">
+ <object></object>
+ <object data="support/blue-100x100.png"></object>
+ <iframe></iframe>
+ <iframe src="support/blue-100x100.png"></iframe>
+ <br>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-replaced-004-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-replaced-004-ref.html
new file mode 100644
index 0000000000..56ca5d2e50
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-replaced-004-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Reference: Size containment replaced elements intrinsic size</title>
+<style>
+ body > div, video, audio, img, canvas, svg, iframe {
+ border: 3px solid orange;
+ contain: size;
+ margin-bottom: 15px;
+ width: 0px;
+ height: 0px;
+ float: left;
+ clear: both;
+ }
+</style>
+<div>abc</div>
+<video></video><br>
+<video controls></video><br>
+<img src="support/60x60-green.png"><br>
+<picture>
+<source srcset="support/60x60-green.png">
+ <img>
+</picture><br>
+<canvas></canvas><br>
+<svg></svg><br>
+<iframe></iframe>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-replaced-004.html b/testing/web-platform/tests/css/css-contain/contain-size-replaced-004.html
new file mode 100644
index 0000000000..9f84481504
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-replaced-004.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment replaced elements intrinsic size</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="contain-size-replaced-004-ref.html">
+<meta name=assert content="This test checks that intrinsic size of replaced elements with 'contain: size' is zero.">
+<style>
+ body > div, video, audio, img, canvas, svg, iframe {
+ border: 3px solid orange;
+ contain: size;
+ margin-bottom: 15px;
+ width: min-content;
+ height: min-content;
+ float: left;
+ clear: both;
+ }
+</style>
+<div>abc</div>
+<video></video><br>
+<video controls></video><br>
+<img src="support/60x60-green.png"><br>
+<picture>
+<source srcset="support/60x60-green.png">
+ <img>
+</picture><br>
+<canvas></canvas><br>
+<svg></svg><br>
+<iframe></iframe>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-replaced-005-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-replaced-005-ref.html
new file mode 100644
index 0000000000..178e137cb7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-replaced-005-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Reference: Size containment replaced elements intrinsic size</title>
+<style>
+ body > div, video, audio, img, canvas, svg, iframe {
+ position: absolute;
+ border: 3px solid orange;
+ contain: size;
+ margin-bottom: 15px;
+ width: 0px;
+ height: 0px;
+ float: left;
+ clear: both;
+ }
+</style>
+<div>abc</div>
+<video></video><br>
+<video controls></video><br>
+<img src="support/60x60-green.png"><br>
+<picture>
+<source srcset="support/60x60-green.png">
+ <img>
+</picture><br>
+<canvas></canvas><br>
+<svg></svg><br>
+<iframe></iframe>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-replaced-005.html b/testing/web-platform/tests/css/css-contain/contain-size-replaced-005.html
new file mode 100644
index 0000000000..754f3608e3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-replaced-005.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment replaced elements intrinsic size</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="contain-size-replaced-005-ref.html">
+<meta name=assert content="This test checks that intrinsic size of out-of-flow replaced elements with 'contain: size' is zero.">
+<style>
+ body > div, video, audio, img, canvas, svg, iframe {
+ position: absolute;
+ border: 3px solid orange;
+ contain: size;
+ margin-bottom: 15px;
+ width: min-content;
+ height: min-content;
+ float: left;
+ clear: both;
+ }
+</style>
+<div>abc</div>
+<video></video><br>
+<video controls></video><br>
+<img src="support/60x60-green.png"><br>
+<picture>
+<source srcset="support/60x60-green.png">
+ <img>
+</picture><br>
+<canvas></canvas><br>
+<svg></svg><br>
+<iframe></iframe>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-replaced-006-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-replaced-006-ref.html
new file mode 100644
index 0000000000..d6753c0694
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-replaced-006-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Reference: Size containment replaced elements intrinsic size</title>
+<style>
+ div, video, audio, img, canvas, svg, iframe {
+ border: 3px solid orange;
+ margin-bottom: 15px;
+ width: 25px;
+ height: 35px;
+ float: left;
+ clear: both;
+ }
+</style>
+<div>abc</div>
+<video></video><br>
+<video controls></video><br>
+<img src="support/60x60-green.png"><br>
+<picture>
+<source srcset="support/60x60-green.png">
+ <img>
+</picture><br>
+<canvas></canvas><br>
+<svg></svg><br>
+<iframe></iframe>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-replaced-006.html b/testing/web-platform/tests/css/css-contain/contain-size-replaced-006.html
new file mode 100644
index 0000000000..f716ce42a8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-replaced-006.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment replaced elements intrinsic size</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="contain-size-replaced-006-ref.html">
+<meta name=assert content="This test checks that min-width/min-height of replaced elements with 'contain: size' works.">
+<style>
+ body > div, video, audio, img, canvas, svg, iframe {
+ border: 3px solid orange;
+ contain: size;
+ margin-bottom: 15px;
+ min-width: 25px;
+ min-height: 35px;
+ width: min-content;
+ height: min-content;
+ float: left;
+ clear: both;
+ }
+</style>
+<div>abc</div>
+<video></video><br>
+<video controls></video><br>
+<img src="support/60x60-green.png"><br>
+<picture>
+<source srcset="support/60x60-green.png">
+ <img>
+</picture><br>
+<canvas></canvas><br>
+<svg></svg><br>
+<iframe></iframe>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-replaced-007.html b/testing/web-platform/tests/css/css-contain/contain-size-replaced-007.html
new file mode 100644
index 0000000000..6a17057bdd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-replaced-007.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment replaced elements intrinsic size</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#attributes-for-embedded-content-and-images">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name=assert content="This test checks that an aspect ratio computed from width and height attributes is used even with contain: size.">
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<img src="support/60x60-green.png" width="60" height="60" style="width: 100px; height: auto; contain: size;">
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-scrollbars-001.html b/testing/web-platform/tests/css/css-contain/contain-size-scrollbars-001.html
new file mode 100644
index 0000000000..26f0d81da8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-scrollbars-001.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment scrollbars</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/contain-size-scrollbars-001-ref.html">
+<meta name=assert content="This test checks that the size of an element with 'contain: size' includes the scrollbars too.">
+<style>
+div {
+ contain: size;
+ display: inline-block;
+ border: solid thick;
+ overflow: scroll;
+}
+</style>
+<p>This test passes if it has the same output as the reference.</p>
+<div>FAIL</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-scrollbars-002.html b/testing/web-platform/tests/css/css-contain/contain-size-scrollbars-002.html
new file mode 100644
index 0000000000..4fe1aae744
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-scrollbars-002.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment scrollbars</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/contain-size-scrollbars-001-ref.html">
+<meta name=assert content="This test checks that the size of a flexbox container with 'contain: size' includes the scrollbars too.">
+<style>
+div {
+ contain: size;
+ display: inline-flex;
+ border: solid thick;
+ overflow: scroll;
+}
+</style>
+<p>This test passes if it has the same output as the reference.</p>
+<div>FAIL</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-scrollbars-003.html b/testing/web-platform/tests/css/css-contain/contain-size-scrollbars-003.html
new file mode 100644
index 0000000000..4684440bdb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-scrollbars-003.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment scrollbars</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/contain-size-scrollbars-001-ref.html">
+<meta name=assert content="This test checks that the size of a grid container with 'contain: size' includes the scrollbars too.">
+<style>
+div {
+ contain: size;
+ display: inline-grid;
+ border: solid thick;
+ overflow: scroll;
+}
+</style>
+<p>This test passes if it has the same output as the reference.</p>
+<div>FAIL</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-scrollbars-004.html b/testing/web-platform/tests/css/css-contain/contain-size-scrollbars-004.html
new file mode 100644
index 0000000000..6a45fdd23f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-scrollbars-004.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment scrollbars</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/contain-size-scrollbars-004-ref.html">
+<meta name=assert content="This test checks that contain:size element's content and padding are considered for scrollbars.">
+<style>
+#scroller {
+ contain: size;
+ background: lightgreen;
+ overflow: scroll;
+ padding-bottom: 50px;
+ width: 100px;
+ height: 100px;
+}
+#content {
+ background: lightblue;
+ width: 50px;
+ height: 130px;
+}
+</style>
+
+<div id=scroller>
+ <div id=content>
+ </div>
+</div>
+
+<p>This test passes if it has the same output as the reference.</p>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-select-001.html b/testing/web-platform/tests/css/css-contain/contain-size-select-001.html
new file mode 100644
index 0000000000..479eb810aa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-select-001.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on select</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/contain-size-select-001-ref.html">
+<meta name=assert content="<select> elements with 'contain: size' should be treated as having no contents.">
+<style>
+select {
+ color: transparent;
+ background: white;
+ contain: size;
+}
+</style>
+<p>Test passes if it has the same output than the reference.</p>
+<select>
+ <option>AVeryLongOption</option>
+ <option>Another Option</option>
+</select>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-select-002.html b/testing/web-platform/tests/css/css-contain/contain-size-select-002.html
new file mode 100644
index 0000000000..3fdea55047
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-select-002.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on select</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/contain-size-select-001-ref.html">
+<meta name=assert content="Check that setting 'contain: size' on a <select> elements causes it to be sized as having no contents.">
+<style>
+select {
+ color: transparent;
+ background: white;
+}
+</style>
+<p>Test passes if it has the same output than the reference.</p>
+<select id="target">
+ <option>AVeryLongOption</option>
+ <option>Another Option</option>
+</select>
+<script>
+ window.requestAnimationFrame( () => {
+ target.style.contain = "size";
+ document.documentElement.removeAttribute("class");
+ });
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-select-elem-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-001-ref.html
new file mode 100644
index 0000000000..095b2f0ba5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-001-ref.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ select {
+ color: transparent;
+ }
+ .minWidth {
+ min-width: 100px;
+ }
+ .width {
+ width: 100px;
+ }
+ .floatLWidth {
+ float: left;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <select class="floatLWidth">
+ </select>
+ <br style="clear:both;">
+
+ <select class="minWidth">
+ </select>
+ <br>
+
+ <select class="width">
+ </select>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-select-elem-001.html b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-001.html
new file mode 100644
index 0000000000..fbb776a256
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-001.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on select objects should cause them to be sized as if they have no contents.</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-select-elem-001-ref.html">
+ <style>
+ select {
+ contain: size;
+ color: transparent;
+ }
+ .minWidth {
+ min-width: 100px;
+ }
+ .width {
+ width: 100px;
+ }
+ .floatLWidth {
+ float: left;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <select class="floatLWidth">
+ <option>CSS Test: A size-contained floated select with specified width and no specified height should size itself as if it had no contents.</option>
+ <option>a</option>
+ <option>b</option>
+ <option>c</option>
+ </select>
+ <br style="clear:both;">
+
+ <select class="minWidth">
+ <option>CSS Test: A size-contained select with specified min-width should size itself as if it had no contents.</option>
+ <option>a</option>
+ <option>b</option>
+ <option>c</option>
+ </select>
+ <br>
+
+ <select class="width">
+ <option>CSS Test: A size-contained select with specified width should size itself as if it had no contents.</option>
+ <option>a</option>
+ <option>b</option>
+ <option>c</option>
+ </select>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-select-elem-002-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-002-ref.html
new file mode 100644
index 0000000000..a2ec520bb3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-002-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ select {
+ color: transparent;
+ }
+ .floatLBasic {
+ float: left;
+ }
+ </style>
+</head>
+<body>
+ <select>
+ </select>
+ <br>
+
+ <select class="floatLBasic">
+ </select>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-select-elem-002.html b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-002.html
new file mode 100644
index 0000000000..c9fcfbd2cd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-002.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on select objects should cause them to be sized as if they have no contents.</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-select-elem-002-ref.html">
+ <style>
+ select {
+ contain: size;
+ color: transparent;
+ }
+ .floatLBasic {
+ float: left;
+ }
+ </style>
+</head>
+<body>
+ <select>
+ <option>CSS Test: A size-contained select with no specified size should size itself as if it had no contents.</option>
+ <option>aaaaaa</option>
+ <option>b</option>
+ <option>c</option>
+ </select>
+ <br>
+
+ <select class="floatLBasic">
+ <option>CSS Test: A size-contained floated select with no specified size should size itself as if it had no contents.</option>
+ <option>a</option>
+ <option>b</option>
+ <option>c</option>
+ </select>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-select-elem-003-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-003-ref.html
new file mode 100644
index 0000000000..214ad1891b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-003-ref.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ select {
+ color: transparent;
+ }
+ .minWidth {
+ min-width: 100px;
+ }
+ .width {
+ width: 100px;
+ }
+ .floatLWidth {
+ float: left;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <select multiple class="floatLWidth">
+ </select>
+ <br style="clear:both;">
+
+ <select multiple class="minWidth">
+ </select>
+ <br>
+
+ <select multiple class="width">
+ </select>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-select-elem-003.html b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-003.html
new file mode 100644
index 0000000000..85428064ec
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-003.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on select objects should cause them to be sized as if they have no contents.</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-select-elem-003-ref.html">
+ <style>
+ select {
+ contain: size;
+ color: transparent;
+ }
+ .minWidth {
+ min-width: 100px;
+ }
+ .width {
+ width: 100px;
+ }
+ .floatLWidth {
+ float: left;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+ <select multiple class="floatLWidth">
+ <option>CSS Test: A size-contained floated select with specified width and no specified height should size itself as if it had no contents.</option>
+ <option>a</option>
+ </select>
+ <br style="clear:both;">
+
+ <select multiple class="minWidth">
+ <option>CSS Test: A size-contained select with specified min-width should size itself as if it had no contents.</option>
+ <option>a</option>
+ </select>
+ <br>
+
+ <select multiple class="width">
+ <option>CSS Test: A size-contained select with specified width should size itself as if it had no contents.</option>
+ <option>a</option>
+ </select>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-select-elem-004-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-004-ref.html
new file mode 100644
index 0000000000..faf6228ea1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-004-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ select {
+ color: transparent;
+ }
+ .floatLBasic {
+ float: left;
+ }
+ </style>
+</head>
+<body>
+ <select multiple>
+ </select>
+ <br>
+
+ <select multiple class="floatLBasic">
+ </select>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-select-elem-004.html b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-004.html
new file mode 100644
index 0000000000..818f4a3016
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-004.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on select objects should cause them to be sized as if they have no contents.</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-select-elem-004-ref.html">
+ <style>
+ select {
+ contain: size;
+ color: transparent;
+ }
+ .floatLBasic {
+ float: left;
+ }
+ </style>
+</head>
+<body>
+ <select multiple>
+ <option>CSS Test: A size-contained select with no specified size should size itself as if it had no contents.</option>
+ <option>aaaaaa</option>
+ </select>
+ <br>
+
+ <select multiple class="floatLBasic">
+ <option>CSS Test: A size-contained floated select with no specified size should size itself as if it had no contents.</option>
+ <option>a</option>
+ </select>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-select-elem-005-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-005-ref.html
new file mode 100644
index 0000000000..e14152d633
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-005-ref.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <style>
+ select {
+ color: transparent;
+ /* We make scrollbars transparent because some <option> elements can cause
+ overflow, which can cause scrollbars to be active in the test and
+ inactive in the reference. But the test only cares about the sizing. */
+ scrollbar-color: transparent transparent;
+ }
+ .fsMedium {
+ /* custom styling for some select elements, which is allowed to influence
+ their size (in the same way that it influences the size of an empty
+ select element): */
+ font-size: 10px;
+ }
+ </style>
+</head>
+<body>
+ <select multiple ></select>
+ <select multiple size="1" ></select>
+ <select multiple class="fsMedium"></select>
+
+ <select multiple ></select>
+ <select multiple size="1" ></select>
+ <select multiple class="fsMedium"></select>
+
+ <br><br>
+
+ <select multiple ></select>
+ <select multiple size="1" ></select>
+ <select multiple class="fsMedium"></select>
+
+ <select multiple ></select>
+ <select multiple size="1" ></select>
+ <select multiple class="fsMedium"></select>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-select-elem-005.html b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-005.html
new file mode 100644
index 0000000000..127b3cd5f8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-select-elem-005.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on select objects should cause them to be sized as if they have no contents.</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-select-elem-005-ref.html">
+ <style>
+ select {
+ contain: size;
+ color: transparent;
+ /* We make scrollbars transparent because some <option> elements can cause
+ overflow, which can cause scrollbars to be active in the test and
+ inactive in the reference. But the test only cares about the sizing. */
+ scrollbar-color: transparent transparent;
+ }
+ .fsMedium {
+ /* custom styling for some select elements, which is allowed to influence
+ their size (in the same way that it influences the size of an empty
+ select element): */
+ font-size: 10px;
+ }
+ .fsSmall {
+ /* custom styling for some option elements (which would make their parent
+ select elem shorter, except for the fact that it's size-contained): */
+ font-size: 6px;
+ }
+ </style>
+</head>
+<body>
+ <!-- No contents: -->
+ <select multiple ></select>
+ <select multiple size="1" ></select>
+ <select multiple class="fsMedium"></select>
+
+ <!-- Empty option: -->
+ <select multiple ><option></option></select>
+ <select multiple size="1" ><option></option></select>
+ <select multiple class="fsMedium"><option></option></select>
+
+ <br><br>
+
+ <!-- Nonempty option: -->
+ <select multiple ><option>X</option></select>
+ <select multiple size="1" ><option>X</option></select>
+ <select multiple class="fsMedium"><option>X</option></select>
+
+ <!-- Nonempty option with custom font-size: -->
+ <select multiple ><option class="fsSmall">X</option></select>
+ <select multiple size="1" ><option class="fsSmall">X</option></select>
+ <select multiple class="fsMedium"><option class="fsSmall">X</option></select>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-table-caption-001-ref.html b/testing/web-platform/tests/css/css-contain/contain-size-table-caption-001-ref.html
new file mode 100644
index 0000000000..49b09334f2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-table-caption-001-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ caption {
+ border: 1em solid green;
+ }
+ </style>
+</head>
+<body>
+ <table>
+ <caption></caption>
+ </table>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-size-table-caption-001.html b/testing/web-platform/tests/css/css-contain/contain-size-table-caption-001.html
new file mode 100644
index 0000000000..8ef46b7666
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-size-table-caption-001.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on table captions should cause them to be sized as if they had no contents.</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-table-caption-001-ref.html">
+ <style>
+ .contain {
+ contain:size;
+ }
+ .innerContents {
+ height: 100px;
+ width: 100px;
+ color: transparent;
+ }
+ caption {
+ border: 1em solid green;
+ }
+ </style>
+</head>
+<body>
+ <table>
+ <caption class="contain">
+ <div class="innerContents">
+ inner
+ </div>
+ </caption>
+ </table>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/contain-strict-001.html b/testing/web-platform/tests/css/css-contain/contain-strict-001.html
new file mode 100644
index 0000000000..e5451e2d94
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-strict-001.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: strict' and table caption</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+ <link rel="match" href="reference/contain-paint-size-001-ref.html">
+
+
+ <style>
+ table
+ {
+ table-layout: fixed;
+ width: 206px;
+ }
+
+ caption
+ {
+ background-color: red;
+ border: green solid 1em;
+ color: red;
+ contain: strict;
+ font-size: 20px;
+ }
+ </style>
+
+ <p>Test passes if there is a short horizontal green stripe and <strong>no red</strong>.
+
+ <table>
+
+ <caption>FAIL FAIL FAIL FAIL FAIL FAIL</caption>
+
+ <tr><td>&nbsp;<td>&nbsp;
+
+ <tr><td>&nbsp;<td>&nbsp;
+
+ </table>
diff --git a/testing/web-platform/tests/css/css-contain/contain-strict-002.html b/testing/web-platform/tests/css/css-contain/contain-strict-002.html
new file mode 100644
index 0000000000..5985fc850f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-strict-002.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: strict' and block box</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+ <link rel="match" href="reference/contain-paint-size-001-ref.html">
+
+
+ <style>
+ div
+ {
+ background-color: red;
+ border: green solid 1em;
+ color: red;
+ contain: strict;
+ font-size: 20px;
+ width: 166px;
+ }
+ </style>
+
+ <p>Test passes if there is a short horizontal green stripe and <strong>no red</strong>.
+
+ <div>FAIL FAIL FAIL FAIL FAIL FAIL</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-strict-003.html b/testing/web-platform/tests/css/css-contain/contain-strict-003.html
new file mode 100644
index 0000000000..903df07868
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-strict-003.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: a block with 'contain: strict' alongside a float</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+ <link rel="match" href="reference/contain-layout-size-003-ref.html">
+
+
+ <style>
+ div
+ {
+ color: transparent;
+ font-size: 16px;
+ padding: 8px;
+ }
+
+ div#floated-left
+ {
+ background-color: blue;
+ float: left;
+ margin: 8px;
+ width: 6em;
+ }
+
+ div#with-contain-strict
+ {
+ background-color: orange;
+ width: 12em;
+
+ contain: strict;
+ }
+ </style>
+
+ <p>Test passes if the orange rectangle and blue rectangle do not overlap.
+
+ <div id="floated-left">Some text in a blue rectangle.</div>
+
+ <div id="with-contain-strict">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore.</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-strict-011.html b/testing/web-platform/tests/css/css-contain/contain-strict-011.html
new file mode 100644
index 0000000000..3e1256ba9c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-strict-011.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: strict' does not turn on style containment</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+ <link rel="match" href="reference/contain-strict-011-ref.html">
+
+ <meta name="assert" content="'contain: strict' turns on style containment. So, in this test, the counter of spans should not be reset and must not be reset.">
+
+ <style>
+ body
+ {
+ counter-reset: counter-of-span 17;
+ }
+
+ /*
+ This creates a new counter identified as "counter-of-span"
+ and initially sets such counter to 17 (an entirely
+ arbitrary number)
+ */
+
+ div
+ {
+ contain: strict;
+ }
+
+ div > span
+ {
+ background-color: yellow;
+ color: red;
+ counter-increment: counter-of-span 3;
+ }
+
+ /*
+ This increments the counter identified as "counter-of-span"
+ of the step value of 3 (an entirely arbitrary number) each
+ and every time there is a <span> child within the subtree
+ of div
+ */
+
+ p#test::after
+ {
+ content: counter(counter-of-span);
+ font-size: 3em;
+ }
+
+ /*
+ Now, the generated content is set to the current
+ value of the counter identified as "counter-of-span":
+ 17 + 3 * 3 == 26
+ */
+ </style>
+
+ <body>
+
+ <div><span>FAIL1</span> <span>FAIL2</span> <span>FAIL3</span></div>
+
+ <p id="pass-fail-conditions-sentence">Test passes if there is the number 17.
+
+ <p id="test">
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-baseline-001.html b/testing/web-platform/tests/css/css-contain/contain-style-baseline-001.html
new file mode 100644
index 0000000000..f13b1e8efb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-baseline-001.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment and baselines</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=assert content="contain:style does not suppress baseline alignment">
+ <link rel="match" href="reference/contain-baseline-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<style>
+div {
+ display: inline-block;
+ height: 5px;
+ background: blue;
+ width: 50px;
+ contain: style;
+ color: transparent;
+ font-size: 100px;
+}
+</style>
+
+<p>Test passes if there are two, not one, blue lines below.</p>
+<div></div><div>a</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-breaks-001.html b/testing/web-platform/tests/css/css-contain/contain-style-breaks-001.html
new file mode 100644
index 0000000000..9e5c27a075
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-breaks-001.html
@@ -0,0 +1,48 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment and break-inside:avoid</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment is (no longer) supposed to have any effect on the break-inside property">
+ <link rel="match" href="reference/contain-style-breaks-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<style>
+article {
+ columns: 2 1ch;
+ column-gap: 0;
+ float: left;
+ font-family: monospace;
+ margin-right: 3em;
+}
+div {
+ page-break-inside: avoid;
+ break-inside: avoid;
+}
+#test > div {
+ contain: style;
+}
+</style>
+
+<p>Test passes if there are two identical blocks “A” letters below.
+<article id=ref>
+ <div>
+ A<br>
+ A<br>
+ A<br>
+ A
+ <div>
+</article>
+<article id=test>
+ <div>
+ A<br>
+ A<br>
+ A<br>
+ A
+ <div>
+</article>
+<!--
+Having two blocks to avoid making browsers that don't support the property at all fail.
+Since containment is supposed to have no effect, failing such browsers would not be useful.
+-->
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-breaks-002.html b/testing/web-platform/tests/css/css-contain/contain-style-breaks-002.html
new file mode 100644
index 0000000000..1b089c84a2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-breaks-002.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment and break-inside:avoid</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment is not (any longer) supposed to have any effect on the break-inside property. Same as -001, applying containment on the parent.">
+ <link rel="match" href="reference/contain-style-breaks-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<style>
+article {
+ columns: 2 1ch;
+ column-gap: 0;
+ float: left;
+ font-family: monospace;
+ margin-right: 3em;
+}
+div > div {
+ page-break-inside: avoid;
+ break-inside: avoid;
+}
+#test > div {
+ contain: style;
+}
+</style>
+
+<p>Test passes if there are two identical blocks “A” letters below.
+<article id=ref>
+ <div>
+ <div>
+ A<br>
+ A<br>
+ A<br>
+ A
+ <div>
+ </div>
+</article>
+<article id=test>
+ <div>
+ <div>
+ A<br>
+ A<br>
+ A<br>
+ A
+ <div>
+ </div>
+</article>
+<!--
+Having two blocks to avoid making browsers that don't support the property at all fail.
+Since containment is supposed to have no effect, failing such browsers would not be useful.
+-->
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-breaks-003.html b/testing/web-platform/tests/css/css-contain/contain-style-breaks-003.html
new file mode 100644
index 0000000000..2cfd5900c1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-breaks-003.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment and break-inside:avoid</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment is not (any longer) supposed to have any effect on the break-inside property. Same as -001, applying break-inside on the parent.">
+ <link rel="match" href="reference/contain-style-breaks-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<style>
+article {
+ columns: 2 1ch;
+ column-gap: 0;
+ float: left;
+ font-family: monospace;
+ margin-right: 3em;
+}
+article > div {
+ page-break-inside: avoid;
+ break-inside: avoid;
+}
+#test div > div {
+ contain: style;
+}
+</style>
+
+<p>Test passes if there are two identical blocks “A” letters below.
+<article id=ref>
+ <div>
+ <div>
+ A<br>
+ A<br>
+ A<br>
+ A
+ <div>
+ </div>
+</article>
+<article id=test>
+ <div>
+ <div>
+ A<br>
+ A<br>
+ A<br>
+ A
+ <div>
+ </div>
+</article>
+<!--
+Having two blocks to avoid making browsers that don't support the property at all fail.
+Since containment is supposed to have no effect, failing such browsers would not be useful.
+-->
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-breaks-004.html b/testing/web-platform/tests/css/css-contain/contain-style-breaks-004.html
new file mode 100644
index 0000000000..98e79a6dba
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-breaks-004.html
@@ -0,0 +1,46 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment and break-before</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment is not (any longer) supposed to have any effect on the break-before property.">
+ <link rel="match" href="reference/contain-style-breaks-004-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<style>
+article {
+ columns: 2 1ch;
+ column-gap: 0;
+ float: left;
+ font-family: monospace;
+ margin-right: 3em;
+ line-height: 1;
+ height: 4em;
+ column-fill: auto;
+}
+div > div:last-of-type {
+ break-before: column;
+}
+#test > div {
+ contain: style;
+}
+</style>
+
+<p>Test passes if there are two identical blocks “A” letters below.
+<article id=ref>
+ <div>
+ <div>A<br>A</div>
+ <div>A<br>A</div>
+ </div>
+</article>
+<article id=test>
+ <div>
+ <div>A<br>A</div>
+ <div>A<br>A</div>
+ </div>
+</article>
+<!--
+Having two blocks to avoid making browsers that don't support the property at all fail.
+Since containment is supposed to have no effect, failing such browsers would not be useful.
+-->
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-breaks-005.html b/testing/web-platform/tests/css/css-contain/contain-style-breaks-005.html
new file mode 100644
index 0000000000..bfcd1fbd91
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-breaks-005.html
@@ -0,0 +1,46 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment and break-after</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment is not (any longer) supposed to have any effect on the break-after property.">
+ <link rel="match" href="reference/contain-style-breaks-004-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<style>
+article {
+ columns: 2 1ch;
+ column-gap: 0;
+ float: left;
+ font-family: monospace;
+ margin-right: 3em;
+ line-height: 1;
+ height: 4em;
+ column-fill: auto;
+}
+div > div:first-of-type {
+ break-after: column;
+}
+#test > div {
+ contain: style;
+}
+</style>
+
+<p>Test passes if there are two identical blocks “A” letters below.
+<article id=ref>
+ <div>
+ <div>A<br>A</div>
+ <div>A<br>A</div>
+ </div>
+</article>
+<article id=test>
+ <div>
+ <div>A<br>A</div>
+ <div>A<br>A</div>
+ </div>
+</article>
+<!--
+Having two blocks to avoid making browsers that don't support the property at all fail.
+Since containment is supposed to have no effect, failing such browsers would not be useful.
+-->
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-counters-001.html b/testing/web-platform/tests/css/css-contain/contain-style-counters-001.html
new file mode 100644
index 0000000000..bd480858ed
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-counters-001.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: style' and counter</title>
+
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-style">
+ <link rel="match" href="reference/contain-style-counters-001-ref.html">
+
+ <meta content="This test checks that when an element has 'contain: style', then counters which may be affecting its subtree are reset to 0 for such scope." name="assert">
+
+ <style>
+ div#create-counter
+ {
+ counter-reset: counter-of-span 9;
+ }
+
+ /*
+ This creates a new counter identified as "counter-of-span"
+ and initially sets such counter to 9 (an entirely
+ arbitrary number).
+ */
+
+ div#test
+ {
+ contain: style;
+ font-size: 3em;
+ }
+
+ div#test span
+ {
+ counter-increment: counter-of-span 5;
+ }
+
+ /*
+ This increments the counter identified as "counter-of-span"
+ of the step value of 5 (an entirely arbitrary number) each
+ and every time there is a <span> descendant within the subtree
+ of div#test
+ */
+
+ div#test span::after
+ {
+ content: counter(counter-of-span);
+ }
+ /*
+ Now, the generated content after the span is set to the
+ current value of the counter identified as "counter-of-span"
+ */
+
+ </style>
+
+
+ <p>Test passes if there is the digit 5.
+
+ <div id="create-counter"></div>
+
+ <div id="test"><span></span></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-counters-002.html b/testing/web-platform/tests/css/css-contain/contain-style-counters-002.html
new file mode 100644
index 0000000000..48494ce2be
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-counters-002.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: style' and counter (with 'display: contents')</title>
+
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-style">
+ <link rel=help href="https://github.com/w3c/csswg-drafts/issues/7392">
+ <link rel="match" href="reference/contain-style-counters-001-ref.html">
+
+ <meta content="This test checks that when an element has 'contain: style', then counters which may be affecting its subtree are reset to 0 for such scope. In this test, the div#test does not generate a principal box because of 'display: contents'. Despite that particular condition, 'contain: style' will have an effect on div#test." name="assert">
+
+ <style>
+ div#create-counter
+ {
+ counter-reset: counter-of-span 9;
+ }
+
+ /*
+ This creates a new counter identified as "counter-of-span"
+ and initially sets such counter to 9 (an entirely
+ arbitrary number).
+ */
+
+ div#test
+ {
+ contain: style;
+ display: contents;
+ font-size: 3em;
+ }
+
+ /*
+ Other types of containment (size, layout, paint) have no
+ effect on box that do not generate a principal box which
+ is the case here with div#test because of 'display: contents'.
+ But in this test, 'contain: style' will apply and will
+ have a rendering effect on the counter.
+ */
+
+ div#test span
+ {
+ counter-increment: counter-of-span 5;
+ }
+
+ /*
+ This increments the counter identified as "counter-of-span"
+ of the step value of 5 (an entirely arbitrary number) each
+ and every time there is a <span> descendant within the subtree
+ of div#test
+ */
+
+ div#test span::after
+ {
+ content: counter(counter-of-span);
+ }
+ /*
+ Now, the generated content after the span is set to the
+ current value of the counter identified as "counter-of-span"
+ */
+
+ </style>
+
+
+ <p>Test passes if there is the digit 5.
+
+ <div id="create-counter"></div>
+
+ <div id="test"><span></span></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-counters-003.html b/testing/web-platform/tests/css/css-contain/contain-style-counters-003.html
new file mode 100644
index 0000000000..3e3e1b910a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-counters-003.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Containment Test: 'contain: style' for counters (span children of &lt;body&gt;)</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-style">
+ <link rel="match" href="reference/contain-style-counters-003-ref.html">
+
+
+ <style>
+ body
+ {
+ counter-reset: counter-of-span 17;
+ }
+
+ /*
+ This creates a new counter identified as "counter-of-span"
+ and initially sets such counter to 17 (an entirely
+ arbitrary number)
+ */
+
+ body
+ {
+ contain: style;
+ }
+
+ /*
+ This will reset the counter to 0.
+ */
+
+ body span
+ {
+ counter-increment: counter-of-span 4;
+ }
+
+ /*
+ This increments the counter identified as "counter-of-span"
+ of the step value of 4 (an entirely arbitrary number) each
+ and every time there is a <span> descendant within the subtree
+ of body
+ */
+
+ div
+ {
+ font-size: 3em;
+ }
+
+ div::after
+ {
+ content: counter(counter-of-span);
+ }
+
+ /*
+ Now, the generated content after the span is set to the
+ current value of the counter identified as "counter-of-span"
+ */
+ </style>
+
+ <body>
+
+ <span></span> <span></span> <span></span> <span></span> <span></span>
+
+ <!-- 5 span above -->
+
+ <p>Test passes if there is the number 20.
+
+ <div></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-counters-004.html b/testing/web-platform/tests/css/css-contain/contain-style-counters-004.html
new file mode 100644
index 0000000000..56e7e3d87e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-counters-004.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Containment Test: 'contain: style' for counters (span descendants of &lt;body&gt;)</title>
+<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+<link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-style">
+<link rel="match" href="reference/contain-style-counters-004-ref.html">
+<style>
+body {
+ counter-reset: counter-of-span 13;
+ contain: style;
+}
+body span {
+ counter-increment: counter-of-span 5;
+}
+div {
+ font-size: 3em;
+}
+div::after {
+ content: counter(counter-of-span);
+}
+</style>
+<body>
+ <p><span></span> <span></span> <span></span> <span></span></p>
+
+<!-- The <span>s aren't allowed to modify the counter instantiated on the <body>,
+ so a new instance of the counter is created.
+ Since the <div> isn't a sibling of the <span>, it will not inherit this new instance,
+ and instead it will read the original counter from the <body>, with value 13.
+ This is per example at: https://drafts.csswg.org/css-contain/#containment-style -->
+ <p>Test passes if there is the number 13.</p>
+ <div></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-counters-005.html b/testing/web-platform/tests/css/css-contain/contain-style-counters-005.html
new file mode 100644
index 0000000000..6e22f7aa59
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-counters-005.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>CSS Containment Test: 'contain: style' for counters and contained subtree scope</title>
+<link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-style">
+<link rel="match" href="reference/contain-style-counters-005-ref.html">
+<style>
+.contain {
+ float: right;
+ contain: style;
+ clear: both;
+}
+.reset { counter-reset: c;}
+.increment:before { content: counters(c, ""); }
+.increment { counter-increment: c; }
+</style>
+<body>
+<div class="increment"></div>
+<div class="contain">
+ <div class="increment"></div>
+ <div class="reset"></div>
+ <div class="increment"></div>
+</div>
+<div class="increment"></div>
+<div class="contain">
+ <div class="increment"></div>
+ <div class="increment"></div>
+</div>
+<div class="increment"></div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-counters-ref.html b/testing/web-platform/tests/css/css-contain/contain-style-counters-ref.html
new file mode 100644
index 0000000000..feef9209f5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-counters-ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<title>CSS Containment Reference File</title>
+<div>You should see the number 1 here: 1</div>
+<div>You should see the number 4 here: 4</div>
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-dynamic-001.html b/testing/web-platform/tests/css/css-contain/contain-style-dynamic-001.html
new file mode 100644
index 0000000000..dfd4032ac5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-dynamic-001.html
@@ -0,0 +1,280 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Dynamic change to style containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1765615">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta name="assert" content="Verify style containment is properly updated after dynamic change to the contain property.">
+<style>
+ /* Selectors for contain */
+ #none .wrapper {
+ contain: none;
+ }
+ #style .wrapper {
+ contain: style;
+ }
+ #none_to_style .wrapper {
+ contain: none;
+ }
+ #style_to_none .wrapper {
+ contain: style;
+ }
+
+ /* Selectors for testing counters */
+ .set_counter_to_9 {
+ counter-set: testcounter 9;
+ }
+ .increment_counter {
+ counter-increment: testcounter;
+ }
+ .set_counter_to_10 {
+ counter-set: testcounter 10;
+ }
+ span.print_counter::after {
+ font: 25px/1 Ahem;
+ content: counters(testcounter, ".");
+ }
+
+ /* Selectors for testing quotes */
+ .open_quote::after {
+ content: open-quote;
+ }
+ .close_quote::after {
+ content: close-quote;
+ }
+ .no_open_quote::after {
+ content: no-open-quote;
+ }
+ .no_close_quote::after {
+ content: no-close-quote;
+ }
+ span.print_quotes::before, span.print_quotes::after {
+ font: 25px/1 Ahem;
+ quotes: "A" "" "BB" "" "CCC" "" "DDDD" "" "EEEEE" "" "FFFFF" "" "GGGGGG" "" "HHHHHHH" "" "IIIIIIII" "" "JJJJJJJJJ" "";
+ }
+ span.print_quotes::before {
+ content: open-quote;
+ }
+ span.print_quotes::after {
+ content: no-close-quote;
+ }
+</style>
+<body>
+ <div id="log"></div>
+
+ <div id="none">
+ <div class="set_counter_to_9"></div>
+ <span><span class="print_counter"></span></span>
+ <div class="wrapper">
+ <span class="increment_counter"></span>
+ </div>
+ <span><span class="print_counter"></span></span>
+
+ <div class="set_counter_to_9"></div>
+ <span><span class="print_counter"></span></span>
+ <div class="wrapper">
+ <span class="set_counter_to_10"></span>
+ </div>
+ <span><span class="print_counter"></span></span>
+
+ <span><span class="print_quotes"></span></span>
+ <div class="wrapper">
+ <span class="open_quote"></span>
+ </div>
+ <span><span class="print_quotes"></span></span>
+
+ <span><span class="print_quotes"></span></span>
+ <div class="wrapper">
+ <span class="close_quote"></span>
+ </div>
+ <span><span class="print_quotes"></span></span>
+
+ <span><span class="print_quotes"></span></span>
+ <div class="wrapper">
+ <span class="no_open_quote"></span>
+ </div>
+ <span><span class="print_quotes"></span></span>
+
+ <span><span class="print_quotes"></span></span>
+ <div class="wrapper">
+ <span class="no_close_quote"></span>
+ </div>
+ <span><span class="print_quotes"></span></span>
+ </div>
+
+ <div id="style">
+ <div class="set_counter_to_9"></div>
+ <span><span class="print_counter"></span></span>
+ <div class="wrapper">
+ <span class="increment_counter"></span>
+ </div>
+ <span><span class="print_counter"></span></span>
+
+ <div class="set_counter_to_9"></div>
+ <span><span class="print_counter"></span></span>
+ <div class="wrapper">
+ <span class="set_counter_to_10"></span>
+ </div>
+ <span><span class="print_counter"></span></span>
+
+ <span><span class="print_quotes"></span></span>
+ <div class="wrapper">
+ <span class="open_quote"></span>
+ </div>
+ <span><span class="print_quotes"></span></span>
+
+ <span><span class="print_quotes"></span></span>
+ <div class="wrapper">
+ <span class="close_quote"></span>
+ </div>
+ <span><span class="print_quotes"></span></span>
+
+ <span><span class="print_quotes"></span></span>
+ <div class="wrapper">
+ <span class="no_open_quote"></span>
+ </div>
+ <span><span class="print_quotes"></span></span>
+
+ <span><span class="print_quotes"></span></span>
+ <div class="wrapper">
+ <span class="no_close_quote"></span>
+ </div>
+ <span><span class="print_quotes"></span></span>
+ </div>
+
+ <div id="none_to_style">
+ <div class="set_counter_to_9"></div>
+ <span><span class="print_counter"></span></span>
+ <div class="wrapper">
+ <span class="increment_counter"></span>
+ </div>
+ <span><span class="print_counter"></span></span>
+
+ <div class="set_counter_to_9"></div>
+ <span><span class="print_counter"></span></span>
+ <div class="wrapper">
+ <span class="set_counter_to_10"></span>
+ </div>
+ <span><span class="print_counter"></span></span>
+
+ <span><span class="print_quotes"></span></span>
+ <div class="wrapper">
+ <span class="open_quote"></span>
+ </div>
+ <span><span class="print_quotes"></span></span>
+
+ <span><span class="print_quotes"></span></span>
+ <div class="wrapper">
+ <span class="close_quote"></span>
+ </div>
+ <span><span class="print_quotes"></span></span>
+
+ <span><span class="print_quotes"></span></span>
+ <div class="wrapper">
+ <span class="no_open_quote"></span>
+ </div>
+ <span><span class="print_quotes"></span></span>
+
+ <span><span class="print_quotes"></span></span>
+ <div class="wrapper">
+ <span class="no_close_quote"></span>
+ </div>
+ <span><span class="print_quotes"></span></span>
+ </div>
+
+ <div id="style_to_none">
+ <div class="set_counter_to_9"></div>
+ <span><span class="print_counter"></span></span>
+ <div class="wrapper">
+ <span class="increment_counter"></span>
+ </div>
+ <span><span class="print_counter"></span></span>
+
+ <div class="set_counter_to_9"></div>
+ <span><span class="print_counter"></span></span>
+ <div class="wrapper">
+ <span class="set_counter_to_10"></span>
+ </div>
+ <span><span class="print_counter"></span></span>
+
+ <span><span class="print_quotes"></span></span>
+ <div class="wrapper">
+ <span class="open_quote"></span>
+ </div>
+ <span><span class="print_quotes"></span></span>
+
+ <span><span class="print_quotes"></span></span>
+ <div class="wrapper">
+ <span class="close_quote"></span>
+ </div>
+ <span><span class="print_quotes"></span></span>
+
+ <span><span class="print_quotes"></span></span>
+ <div class="wrapper">
+ <span class="no_open_quote"></span>
+ </div>
+ <span><span class="print_quotes"></span></span>
+
+ <span><span class="print_quotes"></span></span>
+ <div class="wrapper">
+ <span class="no_close_quote"></span>
+ </div>
+ <span><span class="print_quotes"></span></span>
+ </div>
+
+ <script>
+ function verifyStyleContainment(id, applied) {
+ let container = document.getElementById(id);
+
+ // To verify style containment for counters and quotes, we check whether
+ // the properties in the wrapper affect the string length of generated
+ // content.
+ function haveSameStringLength(box1, box2) {
+ const ahemFontSizePx = 25;
+ return Math.abs(box2.width - box1.width) < ahemFontSizePx / 2;
+ }
+ let counter_box =
+ Array.from(container.getElementsByClassName("print_counter"))
+ .map(e => e.parentNode.getBoundingClientRect());
+ let quote_box =
+ Array.from(container.getElementsByClassName("print_quotes"))
+ .map(e => e.parentNode.getBoundingClientRect());
+ assert_equals(haveSameStringLength(counter_box[0], counter_box[1]), applied, "increment-counter");
+ assert_equals(haveSameStringLength(counter_box[2], counter_box[3]), applied, "set-counter");
+ assert_equals(haveSameStringLength(quote_box[0], quote_box[1]), applied, "open-quote");
+ assert_equals(haveSameStringLength(quote_box[2], quote_box[3]), applied, "close-quote");
+ assert_equals(haveSameStringLength(quote_box[4], quote_box[5]), applied, "no-open-quote");
+ assert_equals(haveSameStringLength(quote_box[6], quote_box[7]), applied, "no-close-quote");
+ }
+
+ function setContain(id, value) {
+ let container = document.getElementById(id);
+ Array.from(container.getElementsByClassName("wrapper"))
+ .forEach(element => element.style.contain = value);
+ }
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ verifyStyleContainment("none", /*applied=*/ false);
+ }, "contain: none");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ verifyStyleContainment("style", /*applied=*/ true);
+ }, "contain: style");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ setContain("none_to_style", "style");
+ verifyStyleContainment("none_to_style", /*applied=*/ true);
+ }, "switching contain from none to style");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ setContain("style_to_none", "none");
+ verifyStyleContainment("style_to_none", /*applied=*/ false);
+ }, "switching contain from style to none");
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-li-container.html b/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-li-container.html
new file mode 100644
index 0000000000..4076407332
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-li-container.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<title>CSS Containment: contain:style and &lt;ol&gt; (&lt;li&gt; container)</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-style">
+<link rel="match" href="reference/contain-style-ol-ordinal-li-container-ref.html">
+<ol>
+ <li>A</li>
+ <li>B</li>
+ <li style="contain:style">X</li>
+ <li style="contain:style">Y</li>
+ <li>C</li>
+ <li>D</li>
+</ol>
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-pseudo-reversed.html b/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-pseudo-reversed.html
new file mode 100644
index 0000000000..dc895abda3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-pseudo-reversed.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>CSS Containment: contain:style and &lt;ol&gt; ordinals (pseudo, reversed)</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-style">
+<link rel="match" href="reference/contain-style-ol-ordinal-pseudo-reversed-ref.html">
+<style>
+ li::before, li::after { content: counter(list-item); }
+</style>
+<ol start=10 reversed>
+ <li>A</li>
+ <li>B</li>
+ <div style="contain:style">
+ <li>X</li>
+ <li>Y</li>
+ </div>
+ <li>C</li>
+ <li>D</li>
+</ol>
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-pseudo.html b/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-pseudo.html
new file mode 100644
index 0000000000..a9ccfb5930
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-pseudo.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>CSS Containment: contain:style and &lt;ol&gt; ordinals (pseudo)</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-style">
+<link rel="match" href="reference/contain-style-ol-ordinal-pseudo-ref.html">
+<style>
+ li::before, li::after { content: counter(list-item); }
+</style>
+<ol start=10>
+ <li>A</li>
+ <li>B</li>
+ <div style="contain:style">
+ <li>X</li>
+ <li>Y</li>
+ </div>
+ <li>C</li>
+ <li>D</li>
+</ol>
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-reversed.html b/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-reversed.html
new file mode 100644
index 0000000000..22f2f20cff
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-reversed.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title>CSS Containment: contain:style and &lt;ol&gt; ordinals (reversed)</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-style">
+<link rel="match" href="reference/contain-style-ol-ordinal-reversed-ref.html">
+<ol reversed>
+ <li>A</li>
+ <li>B</li>
+ <div style="contain:style">
+ <li>X</li>
+ <li>Y</li>
+ </div>
+ <li>C</li>
+ <li>D</li>
+</ol>
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-start-reversed.html b/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-start-reversed.html
new file mode 100644
index 0000000000..175aa81403
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-start-reversed.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title>CSS Containment: contain:style and &lt;ol&gt; ordinals (start attribute, reversed)</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-style">
+<link rel="match" href="reference/contain-style-ol-ordinal-start-reversed-ref.html">
+<ol start=10 reversed>
+ <li>A</li>
+ <li>B</li>
+ <div style="contain:style">
+ <li>X</li>
+ <li>Y</li>
+ </div>
+ <li>C</li>
+ <li>D</li>
+</ol>
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-start.html b/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-start.html
new file mode 100644
index 0000000000..dc23b65f14
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal-start.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title>CSS Containment: contain:style and &lt;ol&gt; ordinals (start attribute)</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-style">
+<link rel="match" href="reference/contain-style-ol-ordinal-start-ref.html">
+<ol start=10>
+ <li>A</li>
+ <li>B</li>
+ <div style="contain:style">
+ <li>X</li>
+ <li>Y</li>
+ </div>
+ <li>C</li>
+ <li>D</li>
+</ol>
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal.html b/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal.html
new file mode 100644
index 0000000000..0901325a4e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-ol-ordinal.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title>CSS Containment: contain:style and &lt;ol&gt; ordinals</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-style">
+<link rel="match" href="reference/contain-style-ol-ordinal-ref.html">
+<ol>
+ <li>A</li>
+ <li>B</li>
+ <div style="contain:style">
+ <li>X</li>
+ <li>Y</li>
+ </div>
+ <li>C</li>
+ <li>D</li>
+</ol>
diff --git a/testing/web-platform/tests/css/css-contain/contain-style-remove-element-crash.html b/testing/web-platform/tests/css/css-contain/contain-style-remove-element-crash.html
new file mode 100644
index 0000000000..cbf079523f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-style-remove-element-crash.html
@@ -0,0 +1,26 @@
+<style>
+* {
+ counter-reset: reversed(counter_3) reversed(counter_4) 64 reversed(counter_5) -8772;
+ contain: layout paint style inline-size !important;
+}
+</style>
+<script>
+window.addEventListener("load", () => {
+ let a = document.documentElement
+ let b = document.getElementById("o1")
+ let c = document.getElementById("o3")
+ let d = new Range()
+ document.documentElement.style.display = "none"
+ document.documentElement.getBoundingClientRect()
+ document.documentElement.style.display = ""
+ d.setStartAfter(document.getElementById("o2"))
+ try { document.prepend("", document.documentElement) } catch (e) {}
+ d.surroundContents(b)
+ try { b.prepend(a, c) } catch (e) {}
+ b.scrollIntoView({ })
+ a.style.display = "none"
+})
+</script>
+<br id="o1">
+<li id="o2">
+<input id="o3">
diff --git a/testing/web-platform/tests/css/css-contain/contain-subgrid-001.html b/testing/web-platform/tests/css/css-contain/contain-subgrid-001.html
new file mode 100644
index 0000000000..59a104bfba
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/contain-subgrid-001.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: layout/paint containment on subgrid</title>
+ <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+ <meta name=assert content="layout/paint containment inhibits subgrid">
+ <link rel="match" href="reference/contain-subgrid-001.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain/#containment-layout">
+ <link rel=help href="https://drafts.csswg.org/css-contain/#containment-paint">
+ <link rel=help href="https://drafts.csswg.org/css-grid-2/">
+
+<style>
+.grid {
+ display: grid;
+ width: 40px;
+ height: 40px;
+ grid: [a] repeat(2,15px) [b] / [a] repeat(2,15px) [b];
+ gap: 10px;
+}
+
+.subgrid {
+ display: grid;
+ grid: subgrid;
+ background: lightgrey;
+ grid-area:1/1/3/3;
+}
+
+.layout { contain: layout; }
+.paint { contain: paint; }
+
+.inner {
+ background: blue;
+ grid-area:a/a/b/b;
+}
+.p {
+ place-self: start;
+ width:100%;
+ height:100%;
+}
+</style>
+
+<div class="grid"><div class="subgrid layout"><div class="inner"></div></div></div>
+<div class="grid"><div class="subgrid paint"><div class="inner"></div></div></div>
+<div class="grid"><div class="subgrid layout"><div class="inner p"></div></div></div>
+<div class="grid"><div class="subgrid paint"><div class="inner p"></div></div></div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/WEB_FEATURES.yml b/testing/web-platform/tests/css/css-contain/container-queries/WEB_FEATURES.yml
new file mode 100644
index 0000000000..445ceb373f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: container-queries
+ files: "**"
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/animation-container-size.html b/testing/web-platform/tests/css/css-contain/container-queries/animation-container-size.html
new file mode 100644
index 0000000000..fefb721cbc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/animation-container-size.html
@@ -0,0 +1,43 @@
+<!doctype html>
+<title>Container Queries - Animating container size</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ @keyframes anim {
+ from { width: 200px; }
+ to { width: 100px; }
+ }
+ #container {
+ container-type: inline-size;
+ animation: anim 1s linear paused;
+ }
+ #target {
+ background-color: green;
+ }
+
+ @container (width: 200px) {
+ #target {
+ background-color: blue;
+ }
+ }
+</style>
+<div id=container>
+ <div id=target>
+ Test
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(target).backgroundColor, 'rgb(0, 0, 255)');
+
+ assert_equals(container.getAnimations().length, 1);
+ let animation = container.getAnimations()[0];
+ animation.currentTime = 500;
+
+ assert_equals(getComputedStyle(target).backgroundColor, 'rgb(0, 128, 0)');
+ }, 'Animation affects container query evaluation');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/animation-container-type-dynamic.html b/testing/web-platform/tests/css/css-contain/container-queries/animation-container-type-dynamic.html
new file mode 100644
index 0000000000..835e8e1be1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/animation-container-type-dynamic.html
@@ -0,0 +1,68 @@
+<!doctype html>
+<title>Container Queries - Animated container creating new containers</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ @keyframes anim {
+ from { width: 200px; }
+ to { width: 300px; }
+ }
+ #container {
+ container-type: inline-size;
+ animation: anim 1s linear paused;
+ }
+ #target {
+ background-color: red;
+ }
+
+ #intermediate {
+ width: 100px;
+ }
+
+ @container (min-width: 250px) {
+ #intermediate {
+ container-type: inline-size;
+ }
+ }
+
+ @container (width: 200px) {
+ #target {
+ background-color: blue;
+ }
+ }
+
+ @container (width: 100px) {
+ /* Initially queries #container, but later queries #intermediate, when
+ the other container query starts matching. */
+ #target {
+ background-color: green;
+ }
+ }
+</style>
+<div id=container>
+ <div id=intermediate>
+ <div id=target>
+ Test
+ </div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(target).backgroundColor, 'rgb(0, 0, 255)');
+
+ assert_equals(container.getAnimations().length, 1);
+ let animation = container.getAnimations()[0];
+
+ animation.currentTime = 600;
+ assert_equals(getComputedStyle(target).backgroundColor, 'rgb(0, 128, 0)');
+
+ // Verify that #intermediate is queried by changing its width. The container
+ // query will stop matching if #intermediate is the queried container.
+ intermediate.style.width = '110px';
+ assert_equals(getComputedStyle(target).backgroundColor, 'rgb(255, 0, 0)');
+ }, 'Animated container creating new container');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/animation-nested-animation.html b/testing/web-platform/tests/css/css-contain/container-queries/animation-nested-animation.html
new file mode 100644
index 0000000000..7f1ae854ae
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/animation-nested-animation.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<title>Container Queries - Animations within animating container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ @keyframes outer {
+ from { width: 100px; }
+ to { width: 300px; }
+ }
+ @keyframes inner {
+ from { background-color: blue; }
+ to { background-color: yellow; }
+ }
+ #container {
+ container-type: inline-size;
+ animation: outer 1s linear paused;
+ }
+ #target {
+ background-color: green;
+ }
+
+ @container (min-width: 200px) {
+ #target {
+ animation: inner 1s linear paused;
+ }
+ }
+</style>
+<div id=container>
+ <div id=target>
+ Test
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(target).backgroundColor, 'rgb(0, 128, 0)');
+
+ assert_equals(container.getAnimations().length, 1);
+ let animation = container.getAnimations()[0];
+ animation.currentTime = 600;
+
+ assert_equals(getComputedStyle(target).backgroundColor, 'rgb(0, 0, 255)');
+ }, 'Animated container can create inner animation');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/animation-nested-transition.html b/testing/web-platform/tests/css/css-contain/container-queries/animation-nested-transition.html
new file mode 100644
index 0000000000..934f995a97
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/animation-nested-transition.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<title>Container Queries - Animated container with inner transition</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ @keyframes outer {
+ from { width: 100px; }
+ to { width: 300px; }
+ }
+ #container {
+ container-type: inline-size;
+ animation: outer 1s linear paused;
+ }
+ #target {
+ background-color: rgb(100, 100, 100);
+ }
+
+ @container (min-width: 200px) {
+ #target {
+ transition: background-color 100s steps(2, start);
+ background-color: rgb(200, 200, 200);
+ }
+ }
+</style>
+<div id=container>
+ <div id=target>
+ Test
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(target).backgroundColor, 'rgb(100, 100, 100)');
+
+ assert_equals(container.getAnimations().length, 1);
+ let animation = container.getAnimations()[0];
+ animation.currentTime = 600;
+
+ assert_equals(getComputedStyle(target).backgroundColor, 'rgb(150, 150, 150)');
+ }, 'Animated container size triggers transition');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/aspect-ratio-feature-evaluation.html b/testing/web-platform/tests/css/css-contain/container-queries/aspect-ratio-feature-evaluation.html
new file mode 100644
index 0000000000..843f34732b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/aspect-ratio-feature-evaluation.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<title>@container queries with aspect-ratio</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#aspect-ratio">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ .container {
+ width: 100px;
+ height: 100px;
+ }
+ #inline-size { container-type: inline-size; }
+ #size { container-type: size; }
+ span { color: red }
+ @container (min-aspect-ratio: 1 / 1000) {
+ span { color: green; }
+ }
+ @container (min-aspect-ratio: 2 / 1) {
+ span { background-color: lime; }
+ }
+</style>
+<div id="inline-size" class="container"><span></span></div>
+<div id="size" class="container"><span></span></div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const red = "rgb(255, 0, 0)";
+ const green = "rgb(0, 128, 0)";
+ const lime = "rgb(0, 255, 0)";
+ const transparent = "rgba(0, 0, 0, 0)";
+
+ const inline_span = document.querySelector("#inline-size > span");
+ const size_span = document.querySelector("#size > span");
+
+ test(() => {
+ assert_equals(getComputedStyle(inline_span).color, red,
+ "Should not match for inline-size containment");
+ assert_equals(getComputedStyle(size_span).color, green,
+ "Should match for block-size containment");
+ assert_equals(getComputedStyle(size_span).backgroundColor, transparent,
+ "Square should not match 2/1 min-ratio");
+ }, "@container queries with aspect-ratio and size containment");
+
+ test(() => {
+ document.querySelector("#size").style.width = "200px";
+ assert_equals(getComputedStyle(size_span).backgroundColor, lime,
+ "Should match 2/1 min-ratio");
+ }, "@container query with aspect-ratio change after resize");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/at-container-parsing.html b/testing/web-platform/tests/css/css-contain/container-queries/at-container-parsing.html
new file mode 100644
index 0000000000..b0196b5e5a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/at-container-parsing.html
@@ -0,0 +1,195 @@
+<!doctype html>
+<title>@container: parsing</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<div style="container-name:name;container-type:size; width:100px; height:100px">
+ <main id=main></main>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ function cleanup_main() {
+ while (main.firstChild)
+ main.firstChild.remove();
+ }
+
+ function set_style(text) {
+ let style = document.createElement('style');
+ style.innerText = text;
+ main.append(style);
+ return style;
+ }
+
+ function test_rule_valid(query) {
+ test(t => {
+ t.add_cleanup(cleanup_main);
+ let style = set_style(`@container ${query} {}`);
+ assert_equals(style.sheet.rules.length, 1);
+ }, query);
+ }
+
+ function test_condition_invalid(condition) {
+ test(t => {
+ t.add_cleanup(cleanup_main);
+ let style = set_style(`@container name ${condition} {}`);
+ assert_equals(style.sheet.rules.length, 0);
+ }, condition);
+ }
+
+ // Tests that 1) the condition parses, and 2) is either "unknown" or not, as
+ // specified.
+ function test_condition_valid(condition, unknown) {
+ test(t => {
+ t.add_cleanup(cleanup_main);
+ let style = set_style(`
+ @container name ${condition} {}
+ @container name (${condition}) or (not (${condition})) { main { --match:true; } }
+ `);
+ assert_equals(style.sheet.rules.length, 2);
+ const expected = unknown ? '' : 'true';
+ assert_equals(getComputedStyle(main).getPropertyValue('--match'), expected);
+ }, condition);
+ }
+
+ function test_condition_known(condition) {
+ test_condition_valid(condition, false /* unknown */);
+ }
+
+ function test_condition_unknown(condition) {
+ test_condition_valid(condition, true /* unknown */);
+ }
+
+ function test_container_name_invalid(container_name) {
+ test(t => {
+ t.add_cleanup(cleanup_main);
+ let style = set_style(`@container ${container_name} not (width) {}`);
+ assert_equals(style.sheet.rules.length, 0);
+ }, `Container name: ${container_name}`);
+ }
+
+ function test_container_name_valid(container_name) {
+ test(t => {
+ t.add_cleanup(cleanup_main);
+ let style = set_style(`@container ${container_name} not (width) {}`);
+ assert_equals(style.sheet.rules.length, 1);
+ }, `Container name: ${container_name}`);
+ }
+
+ test_condition_known('(width)');
+ test_condition_known('(min-width: 0px)');
+ test_condition_known('(max-width: 0px)');
+ test_condition_known('(height)');
+ test_condition_known('(min-height: 0px)');
+ test_condition_known('(max-height: 0px)');
+ test_condition_known('(aspect-ratio)');
+ test_condition_known('(min-aspect-ratio: 1/2)');
+ test_condition_known('(max-aspect-ratio: 1/2)');
+ test_condition_known('(orientation: portrait)');
+ test_condition_known('(inline-size)');
+ test_condition_known('(min-inline-size: 0px)');
+ test_condition_known('(max-inline-size: 0px)');
+ test_condition_known('(block-size)');
+ test_condition_known('(min-block-size: 0px)');
+ test_condition_known('(max-block-size: 0px)');
+
+ test_condition_known('(width: 100px)');
+ test_condition_known('((width: 100px))');
+ test_condition_known('(not (width: 100px))');
+ test_condition_known('((width: 100px) and (height: 100px))');
+ test_condition_known('(((width: 40px) or (width: 50px)) and (height: 100px))');
+ test_condition_known('((width: 100px) and ((height: 40px) or (height: 50px)))');
+ test_condition_known('(((width: 40px) and (height: 50px)) or (height: 100px))');
+ test_condition_known('((width: 50px) or ((width: 40px) and (height: 50px)))');
+ test_condition_known('((width: 100px) and (not (height: 100px)))');
+ test_condition_known('(width < 100px)');
+ test_condition_known('(width <= 100px)');
+ test_condition_known('(width = 100px)');
+ test_condition_known('(width > 100px)');
+ test_condition_known('(width >= 100px)');
+ test_condition_known('(100px < width)');
+ test_condition_known('(100px <= width)');
+ test_condition_known('(100px = width)');
+ test_condition_known('(100px > width)');
+ test_condition_known('(100px >= width)');
+ test_condition_known('(100px < width < 200px)');
+ test_condition_known('(100px < width <= 200px)');
+ test_condition_known('(100px <= width < 200px)');
+ test_condition_known('(100px > width > 200px)');
+ test_condition_known('(100px > width >= 200px)');
+ test_condition_known('(100px >= width > 200px)');
+
+ test_condition_known('(width: calc(10px))');
+ test_condition_known('(width: calc(10em))');
+ test_condition_known('(width: calc(10px + 10em))');
+ test_condition_known('(width < calc(10px + 10em))');
+ test_condition_known('(width < max(10px, 10em))');
+ test_condition_known('(calc(10px + 10em) < width)');
+ test_condition_known('(calc(10px + 10em) < width < max(30px, 30em))');
+ test_condition_known('(width: 100px) and (height: 100px)');
+ test_condition_known('(width: 100px) or (height: 100px)');
+ test_condition_known('not (width: 100px)');
+
+ test_condition_unknown('foo(width)');
+ test_condition_unknown('size(width)');
+ test_condition_unknown('(asdf)');
+ test_condition_unknown('(resolution > 100dpi)');
+ test_condition_unknown('(resolution: 150dpi)');
+ test_condition_unknown('(resolution: calc(2x))');
+ test_condition_unknown('(color)');
+ test_condition_unknown('(min-color: 1)');
+ test_condition_unknown('(color-index >= 1)');
+ test_condition_unknown('size(grid)');
+ test_condition_unknown('(grid)');
+ test_condition_unknown('(width == 100px)');
+ test_condition_unknown('(100px == width)');
+ test_condition_unknown('(100px = width = 200px)');
+ test_condition_unknown('(100px < width > 200px)');
+ test_condition_unknown('(100px <= width >= 200px)');
+ test_condition_unknown('(100px <= width > 200px)');
+ test_condition_unknown('(100px < width >= 200px)');
+ test_condition_unknown('(100px : width : 200px)');
+
+ test_condition_invalid('screen');
+ test_condition_invalid('print');
+ test_condition_invalid('not print');
+ test_condition_invalid('only print');
+ test_condition_invalid('screen and (width: 100px)');
+ test_condition_invalid('screen or (width: 100px)');
+ test_condition_invalid('not screen and (width: 100px)');
+ test_condition_invalid('not screen or (width: 100px)');
+ test_condition_invalid('(width: 100px), (height: 100px)');
+ test_condition_invalid('foo (width: 100px)');
+
+ test_rule_valid('name not (width <= 500px)');
+ test_rule_valid('not (width <= 500px)');
+
+ test_container_name_valid('foo');
+ test_container_name_valid(' foo');
+ test_container_name_valid(' foo ');
+ test_container_name_valid('normal');
+ test_container_name_valid('Normal');
+ test_container_name_valid('auto');
+ test_container_name_valid('Auto');
+
+ test_container_name_invalid('foo foo');
+ test_container_name_invalid('1px');
+ test_container_name_invalid('50gil');
+ test_container_name_invalid('name(foo)');
+ test_container_name_invalid('type(inline-size)');
+ test_container_name_invalid('"foo"');
+ test_container_name_invalid('"inherit"');
+ test_container_name_invalid('inherit');
+ test_container_name_invalid('INITIAL');
+ test_container_name_invalid('Unset');
+ test_container_name_invalid('deFAULT');
+ test_container_name_invalid('none');
+ test_container_name_invalid('None');
+ test_container_name_invalid('and');
+ test_container_name_invalid('or');
+ test_container_name_invalid('not');
+ test_container_name_invalid('And');
+ test_container_name_invalid('oR');
+ test_container_name_invalid('nOt');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/at-container-serialization.html b/testing/web-platform/tests/css/css-contain/container-queries/at-container-serialization.html
new file mode 100644
index 0000000000..141062a8d4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/at-container-serialization.html
@@ -0,0 +1,74 @@
+<!doctype html>
+<title>CSS Container Queries: @container serialization</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<link rel="help" href="https://drafts.csswg.org/cssom/#serialize-a-css-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style id="testSheet">
+ @container (width=100px) {
+ @container \!-name (inline-size > 200px ) {
+ #id { color: lime }
+ }
+ #id { color: green }
+ }
+ @container ( wiDTh ) { }
+ @container (width:100px) { }
+ @container (min-width: 100px) { }
+ @container ( MAX-WIDTH:100px ) { }
+ @container (width > 100px) { }
+ @container (width < 100px) { }
+ @container (widTH >= 100px) { }
+ @container (width <= 100px) { }
+ @container (10px < width < 100px) { }
+ @container (10px <= width <= 100px) { }
+ @container (100px>WIDTH>10px) { }
+ @container ( 100px >= width >= 10px ) { }
+ @container (calc(1em + 1px) >= width >= max(10em, 10px)) { }
+</style>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ let rules = testSheet.sheet.cssRules;
+
+ test(() => {
+ assert_equals(rules.length, 14);
+ assert_equals(rules[0].cssRules.length, 2);
+
+ assert_equals(rules[0].conditionText, "(width = 100px)");
+ assert_equals(rules[0].cssRules[0].conditionText, "\\!-name (inline-size > 200px)");
+ }, "Serialization of conditionText");
+
+ test(() => {
+ assert_equals(rules[0].cssRules[0].cssText, "@container \\!-name (inline-size > 200px) {\n #id { color: lime; }\n}");
+ }, "Serialization of inner @container rule");
+
+ test(() => {
+ assert_equals(rules[0].cssText, "@container (width = 100px) {\n @container \\!-name (inline-size > 200px) {\n #id { color: lime; }\n}\n #id { color: green; }\n}");
+ }, "Serialization of nested @container rule");
+
+ test(() => {
+ assert_equals(rules[1].conditionText, "(width)");
+ }, "Serialization of boolean condition syntax");
+
+ test(() => {
+ assert_equals(rules[2].conditionText, "(width: 100px)");
+ assert_equals(rules[3].conditionText, "(min-width: 100px)");
+ assert_equals(rules[4].conditionText, "(max-width: 100px)");
+ }, "Serialization of colon condition syntax");
+
+ test(() => {
+ assert_equals(rules[5].conditionText, "(width > 100px)");
+ assert_equals(rules[6].conditionText, "(width < 100px)");
+ assert_equals(rules[7].conditionText, "(width >= 100px)");
+ assert_equals(rules[8].conditionText, "(width <= 100px)");
+ assert_equals(rules[9].conditionText, "(10px < width < 100px)");
+ assert_equals(rules[10].conditionText, "(10px <= width <= 100px)");
+ assert_equals(rules[11].conditionText, "(100px > width > 10px)");
+ assert_equals(rules[12].conditionText, "(100px >= width >= 10px)");
+ }, "Serialization of range condition syntax");
+
+ test(() => {
+ assert_equals(rules[13].conditionText, "(calc(1em + 1px) >= width >= max(10em, 10px))");
+ }, "Serialization of calc()");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/at-container-style-parsing.html b/testing/web-platform/tests/css/css-contain/container-queries/at-container-style-parsing.html
new file mode 100644
index 0000000000..36fda2e366
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/at-container-style-parsing.html
@@ -0,0 +1,75 @@
+<!doctype html>
+<title>@container: style queries parsing</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<div style="container-name:name">
+ <main id="main"></main>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ function cleanup_main() {
+ while (main.firstChild)
+ main.firstChild.remove();
+ }
+
+ function set_style(text) {
+ let style = document.createElement('style');
+ style.innerText = text;
+ main.append(style);
+ return style;
+ }
+
+ function test_rule_valid(query) {
+ test(t => {
+ t.add_cleanup(cleanup_main);
+ let style = set_style(`@container ${query} {}`);
+ assert_equals(style.sheet.rules.length, 1);
+ }, query);
+ }
+
+ function test_condition_invalid(condition) {
+ test(t => {
+ t.add_cleanup(cleanup_main);
+ let style = set_style(`@container name ${condition} {}`);
+ assert_equals(style.sheet.rules.length, 0);
+ }, condition);
+ }
+
+ // Tests that 1) the condition parses, and 2) is either "unknown" or not, as
+ // specified.
+ function test_condition_valid(condition, unknown) {
+ test(t => {
+ t.add_cleanup(cleanup_main);
+ let style = set_style(`
+ @container name ${condition} {}
+ @container name (${condition}) or (not (${condition})) { main { --match:true; } }
+ `);
+ assert_equals(style.sheet.rules.length, 2);
+ const expected = unknown ? '' : 'true';
+ assert_equals(getComputedStyle(main).getPropertyValue('--match'), expected);
+ }, condition);
+ }
+
+ function test_condition_known(condition) {
+ test_condition_valid(condition, false /* unknown */);
+ }
+
+ function test_condition_unknown(condition) {
+ test_condition_valid(condition, true /* unknown */);
+ }
+
+ test_condition_known('style(--my-prop: foo)');
+ test_condition_known('style(--my-prop: foo - bar ())');
+ test_condition_known('style(not ((--foo: calc(10px + 2em)) and ((--foo: url(x)))))');
+ test_condition_known('style((--foo: bar) or (--bar: 10px))');
+ test_condition_known('style(--my-prop:)');
+ test_condition_known('style(--my-prop: )');
+ test_condition_known('style(--foo: bar !important)');
+ test_condition_known('style(--foo)');
+
+ test_condition_unknown('style(--foo: bar;)');
+ test_condition_unknown('style(style(--foo: bar))');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/at-container-style-serialization.html b/testing/web-platform/tests/css/css-contain/container-queries/at-container-style-serialization.html
new file mode 100644
index 0000000000..a4fb25378c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/at-container-style-serialization.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<title>CSS Container Queries: style() conditionText serialization</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<link rel="help" href="https://drafts.csswg.org/cssom/#serialize-a-css-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style id="testSheet">
+ @container style( --foo:bar) { }
+ @container STyle(--foo: ) { }
+ @container STyle(--foo:) { }
+ @container STyle(--foo) { }
+ @container style( ( --FOO: BAR) OR ( prop: val ) ) { }
+ @container style (--foo: bar) { }
+ @container style(--foo: bar baz) { }
+ @container style(--foo:2.100 ) { }
+</style>
+<script>
+ setup(() => {
+ assert_implements_container_queries();
+ assert_equals(testSheet.sheet.cssRules.length, 8);
+ });
+
+ const tests = [
+ ["style(--foo: bar)", "Normalize spaces"],
+ ["style(--foo: )", "Empty declaration value - spaces"],
+ ["style(--foo: )", "Empty declaration value"],
+ ["style(--foo)", "No declaration value"],
+ ["style((--FOO: BAR) or ( prop: val ))", "Unknown CSS property after 'or'"],
+ ["style (--foo: bar)", "Not a style function with space before '('"],
+ ["style(--foo: bar baz)", "Spaces preserved in custom property value"],
+ ["style(--foo: 2.100)", "Original string number in custom property value"]
+ ].map((e, i) => [testSheet.sheet.cssRules[i], ...e]);
+
+ tests.forEach((t) => {
+ test(() => assert_equals(t[0].conditionText, t[1]), t[2]);
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/auto-scrollbars.html b/testing/web-platform/tests/css/css-contain/container-queries/auto-scrollbars.html
new file mode 100644
index 0000000000..44074ed213
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/auto-scrollbars.html
@@ -0,0 +1,53 @@
+<!doctype html>
+<title>CSS Container Queries Test: scrollbar stability for @container queries and overflow:auto</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#scrollbar-layout">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #scroller {
+ height: 100px;
+ width: 100px;
+ overflow-y: auto;
+ }
+ #container {
+ container-type: inline-size;
+ }
+ #inner {
+ height: 100px;
+ border-bottom: 1px solid red;
+ }
+ @container (max-width: 99px) {
+ #inner {
+ height: 50px;
+ }
+ }
+</style>
+<div id="precondition" style="width:100px;height:100px;overflow:scroll"></div>
+<div id="scroller">
+ <div id="container">
+ <div id="inner"></div>
+ </div>
+</div>
+<script>
+ setup(() => {
+ assert_implements_container_queries();
+ assert_implements_optional(precondition.clientWidth < 100,
+ "Tests do not work with overlay scrollbars");
+ });
+
+ let initialScrollerWidth = scroller.clientWidth;
+ test(() => {
+ assert_equals(getComputedStyle(inner).height, "50px",
+ "Layout with a scrollbar means the container query applies");
+ }, "Initial layout - expecting a scrollbar without overflowing content instead of overflowing content without a scrollbar");
+
+ test(() => {
+ inner.style.borderBottomWidth = "2px";
+ assert_equals(scroller.clientWidth, initialScrollerWidth, "Scrollbar visibility is consistent after reflow.");
+ assert_equals(getComputedStyle(inner).height, "50px",
+ "Layout with a scrollbar means the container query applies");
+ }, "Same result after a reflow");
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/backdrop-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/backdrop-invalidation.html
new file mode 100644
index 0000000000..6a59a2f894
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/backdrop-invalidation.html
@@ -0,0 +1,51 @@
+<!doctype html>
+<title>Test that ::backdrop responds to container size changes</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ :root {
+ color: black;
+ }
+
+ #container {
+ container-type: size;
+ width: 200px;
+ height: 40px;
+ }
+
+ ::backdrop {
+ background-color: black;
+ }
+
+ @container (min-width: 300px) {
+ ::backdrop {
+ background-color: green;
+ }
+ }
+</style>
+<main id=container>
+ <dialog>test</dialog>
+</main>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ let dialog = document.querySelector('dialog');
+
+ test(function() {
+ try {
+ dialog.showModal();
+
+ assert_equals(getComputedStyle(dialog, '::backdrop').backgroundColor, 'rgb(0, 0, 0)');
+
+ container.style.width = '300px';
+ assert_equals(getComputedStyle(dialog, '::backdrop').backgroundColor, 'rgb(0, 128, 0)');
+
+ container.style = '';
+ assert_equals(getComputedStyle(dialog, '::backdrop').backgroundColor, 'rgb(0, 0, 0)');
+ } finally {
+ dialog.close();
+ }
+ }, 'Pseudo-element ::backdrop responds to container size changes');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/calc-evaluation.html b/testing/web-platform/tests/css/css-contain/container-queries/calc-evaluation.html
new file mode 100644
index 0000000000..71a5e23764
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/calc-evaluation.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<title>CSS Container Queries Test: calc()</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://drafts.csswg.org/mediaqueries-4/#units">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ :root { font-size: 10px; }
+
+ /* To make output more readable */
+ :root > * { font-size: initial; }
+
+ #container {
+ container-type: size;
+ width: 200px;
+ height: 50px;
+ }
+ @container (width = calc(100px + 10rem)) {
+ #target { color: green; }
+ }
+</style>
+<div id=container>
+ <div id=target></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(target).color, 'rgb(0, 128, 0)');
+ }, 'em relative inline-size');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-001.html b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-001.html
new file mode 100644
index 0000000000..f904d1fe24
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-001.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<title>CSS Container Queries Test: Canvas as size container for focusable child</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
+<style>
+ @supports (container-type: size) {
+ canvas:focus-within {
+ border: 50px solid green;
+ }
+ canvas {
+ display: block;
+ width: 100px;
+ height: 100px;
+ box-sizing: border-box;
+ container-type: size;
+ }
+ }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<canvas>
+ <div id="target" tabIndex="1"></div>
+</canvas>
+<script>
+ requestAnimationFrame(()=> {
+ requestAnimationFrame(()=> {
+ target.focus();
+ });
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-002.html b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-002.html
new file mode 100644
index 0000000000..689feeb5ff
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-002.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<title>CSS Container Queries Test: Absolute positioned canvas as size container for focusable child</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
+<style>
+ @supports (container-type: size) {
+ canvas:focus-within {
+ border: 50px solid green;
+ }
+ canvas {
+ display: block;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ box-sizing: border-box;
+ container-type: size;
+ }
+ }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<canvas>
+ <div id="target" tabIndex="1"></div>
+</canvas>
+<script>
+ requestAnimationFrame(()=> {
+ requestAnimationFrame(()=> {
+ target.focus();
+ });
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-003.html b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-003.html
new file mode 100644
index 0000000000..74199cc72b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-003.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<title>CSS Container Queries Test: Canvas as size container for focusable child with display</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
+<style>
+ @supports (container-type: size) {
+ canvas:focus-within {
+ background-color: green;
+ }
+ canvas {
+ display: block;
+ width: 100px;
+ height: 100px;
+ container-type: size;
+ }
+ #target { display: none; }
+ @container (width = 100px) {
+ #target { display: block; }
+ }
+ }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<canvas>
+ <div id="target" tabIndex="1"></div>
+</canvas>
+<script>
+ requestAnimationFrame(()=> {
+ requestAnimationFrame(()=> {
+ target.focus();
+ });
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-004.html b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-004.html
new file mode 100644
index 0000000000..b23846382b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-004.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<title>CSS Container Queries Test: Absolute positioned canvas as size container for focusable child with display</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
+<style>
+ @supports (container-type: size) {
+ canvas:focus-within {
+ background-color: green;
+ }
+ canvas {
+ display: block;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ container-type: size;
+ }
+ #target { display: none; }
+ @container (width = 100px) {
+ #target { display: block; }
+ }
+ }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<canvas>
+ <div id="target" tabIndex="1"></div>
+</canvas>
+<script>
+ requestAnimationFrame(()=> {
+ requestAnimationFrame(()=> {
+ target.focus();
+ });
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-005.html b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-005.html
new file mode 100644
index 0000000000..9132592434
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-005.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<title>CSS Container Queries Test: Canvas as dynamic size container for focusable child with display</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ canvas {
+ display: block;
+ width: 100px;
+ height: 100px;
+ container-type: size;
+ }
+ #target { display: none; }
+ @container (width = 200px) {
+ #target { display: block; }
+ }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<canvas id="canvas">
+ <div id="target" tabIndex="1"></div>
+</canvas>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ target.focus();
+ assert_not_equals(document.activeElement, target);
+ }, "Initially display:none, not focusable");
+
+ test(() => {
+ canvas.style.width = "200px";
+ target.focus();
+ assert_equals(document.activeElement, target);
+ }, "Focusable after container size change");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-006.html b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-006.html
new file mode 100644
index 0000000000..02dbce6275
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/canvas-as-container-006.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<title>CSS Container Queries Test: Absolute positioned canvas as dynamic size container for focusable child with display</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ canvas {
+ display: block;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ container-type: size;
+ }
+ #target { display: none; }
+ @container (width = 200px) {
+ #target { display: block; }
+ }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<canvas id="canvas">
+ <div id="target" tabIndex="1"></div>
+</canvas>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ target.focus();
+ assert_not_equals(document.activeElement, target);
+ }, "Initially display:none, not focusable");
+
+ test(() => {
+ canvas.style.width = "200px";
+ target.focus();
+ assert_equals(document.activeElement, target);
+ }, "Focusable after container size change");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/change-display-in-container-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/change-display-in-container-ref.html
new file mode 100644
index 0000000000..8dd3b8b2c1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/change-display-in-container-ref.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<p>You should see the word PASS below.</p>
+PASS
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/change-display-in-container.html b/testing/web-platform/tests/css/css-contain/container-queries/change-display-in-container.html
new file mode 100644
index 0000000000..8c58d22b7d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/change-display-in-container.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<title>CSS Container Queries Test: Change display and box inside a container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<link rel="match" href="change-display-in-container-ref.html">
+<style>
+ .fail { display: inline; }
+ .pass { display: none; }
+ #container { container-type: size; width: 100px; }
+ @container (min-width: 200px) {
+ .fail { display: none; }
+ .pass { display: inline; }
+ }
+</style>
+<p>You should see the word PASS below.</p>
+<div id="container">
+ <span>
+ <span class="fail">FAIL</span>
+ </span>
+ <span>
+ <span class="pass">PASS</span>
+ <span class="fail">FAIL</span>
+ </span>
+</div>
+<script>
+ container.offsetTop;
+ container.style.width = "auto";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/chrome-legacy-skip-recalc.html b/testing/web-platform/tests/css/css-contain/container-queries/chrome-legacy-skip-recalc.html
new file mode 100644
index 0000000000..b86a4091a2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/chrome-legacy-skip-recalc.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>CSS Container Queries Test: Chrome legacy layout skipping style recalc</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://crbug.com/1288879">
+<link rel="match" href="/css/reference/pass_if_pass_below.html">
+<style>
+ #container {
+ container-type: inline-size;
+ }
+ #multicol {
+ column-count: 1;
+ }
+
+ @supports not (container-type: inline-size) {
+ #container { display: none }
+ }
+</style>
+<p>Test passes if there is the word "PASS" below.</p>
+<div id="container"><span>PASS</span></div>
+<span id="multicol"><table></table></span>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/column-spanner-in-container.html b/testing/web-platform/tests/css/css-contain/container-queries/column-spanner-in-container.html
new file mode 100644
index 0000000000..d494e28504
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/column-spanner-in-container.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<title>CSS Container Queries Test: Column-spanner depending on container in column</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #multicol {
+ container-type: inline-size;
+ width: 600px;
+ columns: 2;
+ column-gap: 0;
+ height: 200px;
+ }
+ #spanner { height: 100px; }
+ @container (width = 600px) {
+ #spanner {
+ column-span: all;
+ }
+ }
+</style>
+<div id="multicol">
+ <div id="spanner"></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(spanner).width, "600px");
+ }, "#spanner matching container with column-width 300px, getting column-span:all");
+
+ test(() => {
+ multicol.style.width = "500px";
+ assert_equals(getComputedStyle(spanner).width, "250px");
+ }, "Reducing #multicol width means #spanner no longer gets column-span:all");
+
+ test(() => {
+ multicol.style.width = "";
+ assert_equals(getComputedStyle(spanner).width, "600px");
+ }, "Back to matching 300px and column-span:all");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/conditional-container-status.html b/testing/web-platform/tests/css/css-contain/container-queries/conditional-container-status.html
new file mode 100644
index 0000000000..e9762f9323
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/conditional-container-status.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<title>Conditionally removing container status</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ .parent { width: 300px; }
+ .child { width: 100px; }
+ .parent, .child { container-type: inline-size; }
+ @container (min-width: 200px) {
+ .child { container-type: initial; }
+ .grandchild { border: 3px solid green }
+ }
+</style>
+<div class="parent">
+ <div class="child">
+ <div class="grandchild">You should see a green border around this text</div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(function() {
+ let s = getComputedStyle(document.querySelector('.grandchild'));
+ assert_equals(s.getPropertyValue('border-color'), 'rgb(0, 128, 0)');
+ }, 'Conditionally applying container-type:initial');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-computed.html b/testing/web-platform/tests/css/css-contain/container-queries/container-computed.html
new file mode 100644
index 0000000000..2be304481b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-computed.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Computed values of container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-name">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<div id="target"></div>
+<script>
+setup(() => assert_implements_container_queries());
+
+test_computed_value('container', 'initial', 'none');
+test_computed_value('container', 'inherit', 'none');
+test_computed_value('container', 'unset', 'none');
+test_computed_value('container', 'none / inline-size');
+test_computed_value('container', 'none / size');
+test_computed_value('container', 'inline-size / inline-size');
+test_computed_value('container', 'block-size / size');
+test_computed_value('container', 'foo / inline-size');
+test_computed_value('container', 'foo /inline-size', 'foo / inline-size');
+test_computed_value('container', 'foo/ inline-size', 'foo / inline-size');
+test_computed_value('container', 'foo/inline-size', 'foo / inline-size');
+test_computed_value('container', 'FoO / size');
+test_computed_value('container', 'foo bar / size', 'foo bar / size');
+test_computed_value('container', 'foo / normal', 'foo');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-for-cue-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/container-for-cue-ref.html
new file mode 100644
index 0000000000..40b0a07ae0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-for-cue-ref.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html class="reftest-wait">
+<head>
+ <title>CSS Test Reference</title>
+ <script src="/common/reftest-wait.js"></script>
+ <style>
+ video {
+ contain: size;
+ width: 200px;
+ height: 200px;
+ }
+ video::cue { background-color: green }
+ video::cue(b) { color: lime }
+ </style>
+</head>
+<body>
+ <video autoplay onplaying="this.onplaying = null; this.pause(); takeScreenshot();">
+ <track default src="support/test.vtt">
+ <source src="/media/white.mp4" type="video/mp4">
+ <source src="/media/white.webm" type="video/webm">
+ </video>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-for-cue.html b/testing/web-platform/tests/css/css-contain/container-queries/container-for-cue.html
new file mode 100644
index 0000000000..a460f79af0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-for-cue.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<html class="reftest-wait">
+<head>
+ <title>CSS Container Queries Test: Container for pseudo elements</title>
+ <link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+ <link rel="match" href="container-for-cue-ref.html">
+ <script src="/common/reftest-wait.js"></script>
+ <style>
+ video {
+ container-type: size;
+ width: 200px;
+ height: 200px;
+ }
+ @container (width = 200px) {
+ video::cue { background-color: green }
+ video::cue(b) { color: lime }
+ }
+ </style>
+</head>
+<body>
+ <video autoplay onplaying="this.onplaying = null; this.pause(); takeScreenshot();">
+ <source src="/media/white.mp4" type="video/mp4">
+ <source src="/media/white.webm" type="video/webm">
+ <track default src="support/test.vtt">
+ </video>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-for-shadow-dom.html b/testing/web-platform/tests/css/css-contain/container-queries/container-for-shadow-dom.html
new file mode 100644
index 0000000000..b136af902e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-for-shadow-dom.html
@@ -0,0 +1,343 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Container Queries Test: query container for Shadow DOM</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #inclusive-ancestor-across-root,
+ #inclusive-ancestor-skip-slotting,
+ #inclusive-ancestor-slotted,
+ #inclusive-ancestor-host,
+ #inclusive-ancestor-part,
+ #inclusive-ancestor-slotted-before,
+ #inclusive-ancestor-host-before,
+ #inclusive-ancestor-part-before,
+ #inclusive-ancestor-inner-part,
+ #inclusive-ancestor-slot-fallback,
+ #inner-scope-host-part {
+ width: 400px;
+ container-type: inline-size;
+ }
+</style>
+
+<div id="inclusive-ancestor-across-root">
+ <div>
+ <template shadowrootmode="open">
+ <style>
+ @container (width = 400px) {
+ #t1 { color: green; }
+ }
+ </style>
+ <div id="t1"></div>
+ </template>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-skip-slotting">
+ <div>
+ <template shadowrootmode="open">
+ <style>
+ div {
+ width: 200px;
+ container-type: inline-size;
+ }
+ </style>
+ <div>
+ <slot></slot>
+ </div>
+ </template>
+ <style>
+ @container (width = 400px) {
+ #t2 { color: green; }
+ }
+ </style>
+ <div id="t2"></div>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-slotted">
+ <div>
+ <template shadowrootmode="open">
+ <style>
+ slot {
+ display: block;
+ width: 200px;
+ container-type: inline-size;
+ }
+ @container (width = 200px) {
+ ::slotted(#t3) { color: green; }
+ }
+ </style>
+ <slot></slot>
+ </template>
+ <div id="t3"></div>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-host">
+ <div id="t4">
+ <template shadowrootmode="open">
+ <style>
+ @container (width = 400px) {
+ :host(#t4) { color: green; }
+ }
+ </style>
+ </template>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-part">
+ <div>
+ <template shadowrootmode="open">
+ <style>
+ div {
+ width: 200px;
+ container-type: inline-size;
+ }
+ </style>
+ <div>
+ <span id="t5" part="part"></span>
+ </div>
+ </template>
+ <style>
+ @container (width = 400px) {
+ #inclusive-ancestor-part > div::part(part) { color: green; }
+ }
+ </style>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-slotted-before">
+ <div>
+ <template shadowrootmode="open">
+ <style>
+ slot {
+ display: block;
+ width: 200px;
+ container-type: inline-size;
+ }
+ @container (width = 200px) {
+ ::slotted(#t6)::before {
+ content: "X";
+ color: green;
+ }
+ }
+ </style>
+ <slot></slot>
+ </template>
+ <style>
+ #t6 {
+ width: 400px;
+ container-type: inline-size;
+ }
+ </style>
+ <div id="t6"></div>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-host-before">
+ <div id="t7">
+ <template shadowrootmode="open">
+ <style>
+ :host {
+ width: 200px;
+ container-type: inline-size;
+ }
+ @container (width = 200px) {
+ :host(#t7)::before {
+ content: "X";
+ color: green;
+ }
+ }
+ </style>
+ </template>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-part-before">
+ <style>
+ @container (width = 400px) {
+ #inclusive-ancestor-part-before > div::part(part)::before {
+ content: "X";
+ color: green;
+ }
+ }
+ </style>
+ <div>
+ <template shadowrootmode="open">
+ <style>
+ div {
+ width: 200px;
+ container-type: inline-size;
+ }
+ </style>
+ <div>
+ <span id="t8" part="part"></span>
+ </div>
+ </template>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-inner-part">
+ <style>
+ @container (width = 400px) {
+ #inclusive-ancestor-inner-part > div::part(inner-part) { color: green; }
+ }
+ </style>
+ <div>
+ <template shadowrootmode="open">
+ <style>
+ div {
+ width: 200px;
+ container-type: inline-size;
+ }
+ </style>
+ <div exportparts="inner-part">
+ <template shadowrootmode="open">
+ <style>
+ div {
+ width: 200px;
+ container-type: inline-size;
+ }
+ </style>
+ <div>
+ <span id="t9" part="inner-part"></span>
+ </div>
+ </template>
+ </div>
+ </template>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-slot-fallback">
+ <div><template shadowrootmode="open">
+ <style>
+ div {
+ width: 200px;
+ container-type: inline-size;
+ }
+ @container (width = 200px) {
+ #t10 { color: green; }
+ }
+ </style>
+ <div>
+ <slot><span id="t10"></span></slot>
+ </div>
+ </template></div>
+</div>
+
+<div id="no-container-for-part">
+ <div>
+ <template shadowrootmode="open">
+ <style>
+ div {
+ width: 200px;
+ container-type: inline-size;
+ }
+ #t11 { color: green; }
+ </style>
+ <div>
+ <span id="t11" part="part"></span>
+ </div>
+ </template>
+ <style>
+ @container (width = 200px) {
+ #no-container-for-part > div::part(part) { color: red; }
+ }
+ </style>
+ </div>
+</div>
+
+<div id="inner-scope-host-part">
+ <div>
+ <template shadowrootmode="open">
+ <style>
+ div {
+ width: 200px;
+ container-type: inline-size;
+ }
+ @container (width = 400px) {
+ :host::part(part) { color: green; }
+ }
+ </style>
+ <div>
+ <span id="t12" part="part"></span>
+ </div>
+ </template>
+ <style>
+ </style>
+ </div>
+</div>
+
+<script>
+ setup(() => {
+ assert_implements_container_queries();
+ });
+
+ const green = "rgb(0, 128, 0)";
+
+ test(() => {
+ const t1 = document.querySelector("#inclusive-ancestor-across-root > div").shadowRoot.querySelector("#t1");
+ assert_equals(getComputedStyle(t1).color, green);
+ }, "Match container in outer tree");
+
+ test(() => {
+ const t2 = document.querySelector("#t2");
+ assert_equals(getComputedStyle(t2).color, green);
+ }, "Match container in same tree, not walking flat tree ancestors");
+
+ test(() => {
+ const t3 = document.querySelector("#t3");
+ assert_equals(getComputedStyle(t3).color, green);
+ }, "Match container in ::slotted selector's originating element tree");
+
+ test(() => {
+ const t4 = document.querySelector("#t4");
+ assert_equals(getComputedStyle(t4).color, green);
+ }, "Match container in outer tree for :host");
+
+ test(() => {
+ const t5 = document.querySelector("#inclusive-ancestor-part > div").shadowRoot.querySelector("#t5");
+ assert_equals(getComputedStyle(t5).color, green);
+ }, "Match container in ::part selector's originating element tree");
+
+ test(() => {
+ const t6 = document.querySelector("#t6");
+ assert_equals(getComputedStyle(t6, "::before").color, green);
+ }, "Match container for ::before in ::slotted selector's originating element tree");
+
+ test(() => {
+ const t7 = document.querySelector("#t7");
+ assert_equals(getComputedStyle(t7, "::before").color, green);
+ }, "Match container in outer tree for :host::before");
+
+ test(() => {
+ const t8 = document.querySelector("#inclusive-ancestor-part-before > div").shadowRoot.querySelector("#t8");
+ assert_equals(getComputedStyle(t8, "::before").color, green);
+ }, "Match container for ::before in ::part selector's originating element tree");
+
+ test(() => {
+ const outerhost = document.querySelector("#inclusive-ancestor-inner-part > div");
+ const innerhost = outerhost.shadowRoot.querySelector("div");
+ const t9 = innerhost.shadowRoot.querySelector("#t9");
+ assert_equals(getComputedStyle(t9).color, green);
+ }, "Match container for ::part selector's originating element tree for exportparts");
+
+ test(() => {
+ const t10 = document.querySelector("#inclusive-ancestor-slot-fallback > div").shadowRoot.querySelector("#t10");
+ assert_equals(getComputedStyle(t10).color, green);
+ }, "Match container for slot light tree child fallback");
+
+ test(() => {
+ const t11 = document.querySelector("#no-container-for-part > div").shadowRoot.querySelector("#t11");
+ assert_equals(getComputedStyle(t11).color, green);
+ }, "Should not match container inside shadow tree for ::part()");
+
+ test(() => {
+ const t12 = document.querySelector("#inner-scope-host-part > div").shadowRoot.querySelector("#t12");
+ assert_equals(getComputedStyle(t12).color, green);
+ }, "A :host::part rule should match containers in the originating element tree");
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-inheritance.html b/testing/web-platform/tests/css/css-contain/container-queries/container-inheritance.html
new file mode 100644
index 0000000000..b333b691fd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-inheritance.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Inheritance of container-*</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-name">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/inheritance-testcommon.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<div id="container">
+ <div id="target"></div>
+</div>
+<script>
+setup(() => assert_implements_container_queries());
+
+assert_not_inherited('container-name', 'none', 'foo');
+assert_not_inherited('container-type', 'normal', 'inline-size');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-inner-at-rules.html b/testing/web-platform/tests/css/css-contain/container-queries/container-inner-at-rules.html
new file mode 100644
index 0000000000..ac18002929
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-inner-at-rules.html
@@ -0,0 +1,196 @@
+<!doctype html>
+<title>@container: inner at-rules</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ container-type: size;
+ width: 100px;
+ height: 100px;
+ }
+
+</style>
+<div id=container>
+ <div id=child></div>
+</div>
+
+<script>
+ setup(() => assert_implements_container_queries());
+</script>
+
+<style>
+ @container (width: 100px) {
+ @keyframes anim1 {
+ from { --anim1:true; }
+ to { --anim1:true; }
+ }
+ }
+
+ @container (width: 200px) {
+ @keyframes anim2 {
+ from { --anim2:true; }
+ to { --anim2:true; }
+ }
+ }
+
+ #child { animation: anim1 10s paused, anim2 10s paused; }
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--anim1'), 'true');
+ assert_equals(getComputedStyle(child).getPropertyValue('--anim2'), 'true');
+ }, '@keyframes is defined regardless of evaluation');
+</script>
+
+
+<style>
+ @container (width: 100px) {
+ @property --prop1 {
+ syntax: "<length>";
+ inherits: false;
+ initial-value: 0px;
+ }
+ }
+
+ @container (width: 200px) {
+ @property --prop2 {
+ syntax: "<length>";
+ inherits: false;
+ initial-value: 0px;
+ }
+ }
+
+ #child {
+ font-size: 20px;
+ --prop1:1em;
+ --prop2:2em;
+ }
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--prop1'), '20px');
+ assert_equals(getComputedStyle(child).getPropertyValue('--prop2'), '40px');
+ }, '@property is defined regardless of evaluation');
+</script>
+
+
+<style>
+ @container (width: 100px) {
+ @layer a;
+ }
+
+ @container (width: 200px) {
+ @layer b;
+ }
+
+ @layer b {
+ #child { --layer:b; }
+ }
+
+ @layer a {
+ #child { --layer:a; }
+ }
+
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--layer'), 'b');
+ }, '@layer order respected regardless of evaluation');
+</script>
+
+
+<style>
+ @container (width: 100px) {
+ @font-face {
+ font-family: Font1;
+ font-stretch: 50% 200%;
+ src: url(/fonts/Ahem.ttf);
+ }
+ }
+
+ @container (width: 200px) {
+ @font-face {
+ font-family: Font2;
+ font-stretch: 40% 190%;
+ src: url(/fonts/Ahem.ttf);
+ }
+ }
+
+</style>
+<script>
+ promise_test(async (t) => {
+ const fonts1 = await document.fonts.load("20px Font1");
+ assert_not_equals(fonts1[0], undefined);
+ assert_equals(fonts1[0].stretch, "50% 200%");
+
+ const fonts2 = await document.fonts.load("20px Font2");
+ assert_not_equals(fonts2[0], undefined);
+ assert_equals(fonts2[0].stretch, "40% 190%");
+ }, '@font-face is defined regardless of evaluation');
+</script>
+
+
+<style>
+ @container (width: 100px) {
+ /* Assumed to be false */
+ @media (width: 0px) {
+ #child { --media1:true; }
+ }
+ /* Assumed to be true */
+ @media (min-width: 0px) {
+ #child { --media2:true; }
+ }
+ }
+
+ /* Same again, but with failing container query. */
+ @container (width: 200px) {
+ @media (width: 0px) {
+ #child { --media3:true; }
+ }
+ @media (min-width: 0px) {
+ #child { --media4:true; }
+ }
+ }
+
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--media1'), '');
+ assert_equals(getComputedStyle(child).getPropertyValue('--media2'), 'true');
+ assert_equals(getComputedStyle(child).getPropertyValue('--media3'), '');
+ assert_equals(getComputedStyle(child).getPropertyValue('--media4'), '');
+ }, '@media works inside @container');
+</script>
+
+
+<style>
+ @container (width: 100px) {
+ @supports (width: 500kg) {
+ #child { --supports1:true; }
+ }
+ @supports (width: 500px) {
+ #child { --supports2:true; }
+ }
+ }
+
+ /* Same again, but with failing container query. */
+ @container (width: 200px) {
+ @supports (width: 500kg) {
+ #child { --supports3:true; }
+ }
+ @supports (width: 500px) {
+ #child { --supports4:true; }
+ }
+ }
+
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--supports1'), '');
+ assert_equals(getComputedStyle(child).getPropertyValue('--supports2'), 'true');
+ assert_equals(getComputedStyle(child).getPropertyValue('--supports3'), '');
+ assert_equals(getComputedStyle(child).getPropertyValue('--supports4'), '');
+ }, '@supports works inside @container');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-inside-multicol-with-table.html b/testing/web-platform/tests/css/css-contain/container-queries/container-inside-multicol-with-table.html
new file mode 100644
index 0000000000..8688159da3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-inside-multicol-with-table.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<title>CSS Container Queries Test: container inside multicol with table</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #multicol {
+ columns: 2;
+ }
+ .container {
+ container-type: inline-size;
+ width: 100px;
+ }
+ @container (width = 100px) {
+ #t1, #t2 { color: green; }
+ }
+</style>
+<div id="multicol">
+ <div class="container">
+ <div id="t1"></div>
+ </div>
+ <table>
+ <div class="container">
+ <div id="t2"></div>
+ </div>
+ </table>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const green = "rgb(0, 128, 0)";
+
+ test(() => {
+ assert_equals(getComputedStyle(t1).color, green);
+ }, "Matching size container inside table inside multicol");
+
+ test(() => {
+ assert_equals(getComputedStyle(t2).color, green);
+ }, "Matching size container inside multicol with table sibling");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-longhand-animation-type.html b/testing/web-platform/tests/css/css-contain/container-queries/container-longhand-animation-type.html
new file mode 100644
index 0000000000..aded2a3ec8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-longhand-animation-type.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<title>Container Queries - The container longhands are not animatable</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#propdef-container-name">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#propdef-container-type">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ @keyframes anim {
+ from {
+ --ref:PASS;
+ container-name: FAIL;
+ container-type: size;
+ }
+ to {
+ --ref:PASS;
+ container-name: FAIL;
+ container-type: size;
+ }
+ }
+ #container {
+ --ref:FAIL;
+ container-name: PASS;
+ container-type: inline-size;
+ animation: anim 1s linear paused;
+ }
+</style>
+<div id=container>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(container).getPropertyValue('--ref'), 'PASS');
+ }, 'Reference variable is applied');
+
+ test(() => {
+ assert_equals(getComputedStyle(container).getPropertyValue('container-name'), 'PASS');
+ }, 'container-name is not animatable');
+
+ test(() => {
+ assert_equals(getComputedStyle(container).getPropertyValue('container-type'), 'inline-size');
+ }, 'container-type is not animatable');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-name-computed.html b/testing/web-platform/tests/css/css-contain/container-queries/container-name-computed.html
new file mode 100644
index 0000000000..f58d54744e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-name-computed.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Computed values of container-name</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-name">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<div id="target"></div>
+<script>
+setup(() => assert_implements_container_queries());
+
+test_computed_value('container-name', 'initial', 'none');
+test_computed_value('container-name', 'unset', 'none');
+test_computed_value('container-name', 'foo');
+test_computed_value('container-name', 'FoO');
+test_computed_value('container-name', 'foo bar');
+test_computed_value('container-name', 'bar foo');
+test_computed_value('container-name', 'foo foo bar');
+test_computed_value('container-name', 'foo bar foo');
+test_computed_value('container-name', 'bar foo foo');
+test_computed_value('container-name', '\\!escaped');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-name-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-name-invalidation.html
new file mode 100644
index 0000000000..aad225def9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-name-invalidation.html
@@ -0,0 +1,74 @@
+<!doctype html>
+<title>container-name invalidation</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-name">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ div {
+ color: black;
+ }
+ #outer {
+ container-name: c1;
+ container-type: inline-size;
+ width: 300px;
+ }
+
+ #inner {
+ container-name: c2;
+ container-type: inline-size;
+ width: 200px;
+ }
+
+ #intermediate {
+ width: 250px;
+ }
+
+ @container c1 (width: 250px) {
+ #child {
+ color: green;
+ }
+ }
+</style>
+<div id=outer>
+ <div id=intermediate>
+ <div id=inner>
+ <div id=child>Test</div>
+ </div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(function(t) {
+ t.add_cleanup(() => { outer.style = ''; });
+
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 0, 0)');
+
+ outer.style.width = '250px';
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)');
+
+ outer.style.width = '251px';
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 0, 0)');
+ }, 'Changing a named container invalidates relevant descendants');
+
+ test(function(t) {
+ t.add_cleanup(() => {
+ outer.style = '';
+ intermediate.style = '';
+ });
+
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 0, 0)');
+
+ // #intermediate becomes the new container.
+ intermediate.style = 'container-name:c1; container-type:inline-size';
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)');
+
+ // #outer becomes the container again.
+ intermediate.style = '';
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 0, 0)');
+
+ outer.style.width = '250px';
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)');
+ }, 'Changing container-name invalidates relevant descendants');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-name-parsing.html b/testing/web-platform/tests/css/css-contain/container-queries/container-name-parsing.html
new file mode 100644
index 0000000000..4f385cca52
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-name-parsing.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Parsing of container-name</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-name">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<div id="target"></div>
+<script>
+setup(() => assert_implements_container_queries());
+
+test_valid_value('container-name', 'initial');
+test_valid_value('container-name', 'inherit');
+test_valid_value('container-name', 'unset');
+test_valid_value('container-name', 'revert');
+test_valid_value('container-name', 'none');
+test_valid_value('container-name', 'foo');
+test_valid_value('container-name', 'BAR');
+test_valid_value('container-name', 'foo bar');
+test_valid_value('container-name', 'foo foo');
+test_valid_value('container-name', '\\!escaped');
+test_valid_value('container-name', 'auto');
+test_valid_value('container-name', 'normal');
+
+test_invalid_value('container-name', 'none none');
+test_invalid_value('container-name', 'foo, bar');
+test_invalid_value('container-name', '#fff');
+test_invalid_value('container-name', '1px');
+test_invalid_value('container-name', 'default'); /* reserved */
+
+test_invalid_value('container-name', '"initial"');
+test_invalid_value('container-name', '"inherit"');
+test_invalid_value('container-name', '"unset"');
+test_invalid_value('container-name', '"revert"');
+test_invalid_value('container-name', '"none"');
+test_invalid_value('container-name', '"foo"');
+
+test_invalid_value('container-name', 'not');
+test_invalid_value('container-name', 'and');
+test_invalid_value('container-name', 'or');
+test_invalid_value('container-name', 'Not');
+test_invalid_value('container-name', 'aNd');
+test_invalid_value('container-name', 'oR');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-name-tree-scoped.html b/testing/web-platform/tests/css/css-contain/container-queries/container-name-tree-scoped.html
new file mode 100644
index 0000000000..e0890aab32
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-name-tree-scoped.html
@@ -0,0 +1,112 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Container Queries Test: Tree scoped container-name</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container">
+<link rel="help" href="https://drafts.csswg.org/css-scoping-1/#shadow-names">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+
+<div id="container-name-host">
+ <div>
+ <template shadowrootmode="open">
+ <style>
+ :host { container-name: foo; }
+ </style>
+ <slot></slot>
+ </template>
+ <div id="t1"></div>
+ </div>
+ <style>
+ #container-name-host > div {
+ container-type: inline-size;
+ }
+ #t1 { color: green; }
+ @container foo (width > 0px) {
+ #t1 { color: red; }
+ }
+ </style>
+</div>
+
+<div id="container-name-slotted">
+ <div>
+ <template shadowrootmode="open">
+ <style>
+ ::slotted(div) {
+ container-name: foo;
+ }
+ </style>
+ <slot></slot>
+ </template>
+ <div>
+ <div id="t2"></div>
+ </div>
+ </div>
+ <style>
+ #container-name-slotted > div > div {
+ container-type: inline-size;
+ }
+ #t2 { color: green; }
+ @container foo (width > 0px) {
+ #t2 { color: red; }
+ }
+ </style>
+
+ <div id="container-name-host-inner-container-rule">
+ <div id="t3host">
+ <template shadowrootmode="open">
+ <style>
+ :host { container-name: foo; }
+ #t3 { color: red; }
+ @container foo (width > 0px) {
+ #t3 { color: green; }
+ }
+ </style>
+ <div id="t3"></div>
+ </template>
+ </div>
+ </div>
+
+ <div id="container-name-host-inner-slotted">
+ <div>
+ <template shadowrootmode="open">
+ <style>
+ :host { container-name: foo; }
+ ::slotted(div) { color: red; }
+ @container foo (width > 0px) {
+ ::slotted(div) {
+ color: green;
+ }
+ }
+ </style>
+ <slot></slot>
+ </template>
+ <div id="t4"></div>
+ </div>
+ </div>
+</div>
+
+<script>
+ setup(() => {
+ assert_implements_container_queries();
+ });
+
+ const green = "rgb(0, 128, 0)";
+
+ test(() => {
+ assert_equals(getComputedStyle(t1).color, green);
+ }, "Outer scope query should not match container-name set by :host rule in shadow tree");
+
+ test(() => {
+ assert_equals(getComputedStyle(t2).color, green);
+ }, "Outer scope query should not match container-name set by ::slotted rule in shadow tree");
+
+ test(() => {
+ assert_equals(getComputedStyle(t3host.shadowRoot.querySelector('#t3')).color, green);
+ }, "Inner scope query should match container-name set by :host rule in shadow tree");
+
+ test(() => {
+ assert_equals(getComputedStyle(t4).color, green);
+ }, "Inner scope query containing ::slotted should match container-name set by :host rule in shadow tree");
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-nested.html b/testing/web-platform/tests/css/css-contain/container-queries/container-nested.html
new file mode 100644
index 0000000000..3ad35bd2be
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-nested.html
@@ -0,0 +1,239 @@
+<!doctype html>
+<title>@container (nested)</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+
+#outer {
+ container-name: outer;
+ container-type: size;
+ width: 100px;
+ height: 100px;
+}
+
+#inner {
+ container-name: inner;
+ container-type: size;
+ width: 50px;
+ height: 50px;
+}
+</style>
+<div id=outer>
+ <div id=inner>
+ <div id=child></div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+</script>
+
+<!--
+ "Implicit" refers to implicit container selection, i.e. understanding which
+ container to evaluate against by looking at the features used.
+-->
+
+<style>
+ @container (width: 50px) {
+ @container (height: 50px) {
+ #child { --implicit:true; }
+ }
+ }
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--implicit'), 'true');
+ }, 'Implicit');
+</script>
+
+
+<style>
+ @container (width: 70px) {
+ @container (height: 50px) {
+ #child { --implicit-outer-fail:true; }
+ }
+ }
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--implicit-outer-fail'), '');
+ }, 'Implicit, outer failing');
+</script>
+
+
+<style>
+ @container (width: 50px) {
+ @container (height: 70px) {
+ #child { --implicit-inner-fail:true; }
+ }
+ }
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--implicit-inner-fail'), '');
+ }, 'Implicit, inner failing');
+</script>
+
+
+<style>
+ @container outer (width: 100px) {
+ @container inner (height: 50px) {
+ #child { --named-outer-inner:true; }
+ }
+ }
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--named-outer-inner'), 'true');
+ }, 'Outer named, inner named');
+</script>
+
+
+<style>
+ @container inner (width: 50px) {
+ @container outer (height: 100px) {
+ #child { --named-outer-inner-reverse:true; }
+ }
+ }
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--named-outer-inner-reverse'), 'true');
+ }, 'Outer named, inner named (reverse)');
+</script>
+
+
+<style>
+ @container unknown (width: 100px) {
+ @container inner (height: 50px) {
+ #child { --named-failing-outer:true; }
+ }
+ }
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--named-failing-outer'), '');
+ }, 'Failing outer name');
+</script>
+
+<style>
+ @container outer (width: 100px) {
+ @container unknown (height: 50px) {
+ #child { --named-failing-inner:true; }
+ }
+ }
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--named-failing-inner'), '');
+ }, 'Failing inner name');
+</script>
+
+
+<style>
+ @container outer (width: 100px) {
+ @container (height: 50px) {
+ #child { --named-outer-inner-implicit:true; }
+ }
+ }
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--named-outer-inner-implicit'), 'true');
+ }, 'Outer named, inner implicit');
+</script>
+
+
+<style>
+ @container (width: 50px) {
+ @container inner (height: 50px) {
+ #child { --implicit-outer-inner-named:true; }
+ }
+ }
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--implicit-outer-inner-named'), 'true');
+ }, 'Inner named, outer implicit');
+</script>
+
+
+<style>
+ @container (width: 50px) {
+ @container outer (height: 100px) {
+ #child { --implicit-outer-inner-named-reverse:true; }
+ }
+ }
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--implicit-outer-inner-named-reverse'), 'true');
+ }, 'Inner named, outer implicit (reverse)');
+</script>
+
+
+<style>
+ @container (width > 1px) {
+ @container (width > 2px) {
+ @container (width > 3px) {
+ #child { --three-levels:true; }
+ }
+ }
+ }
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--three-levels'), 'true');
+ }, 'Three levels');
+</script>
+
+
+<style>
+ @container (width > 1px) {
+ @container (width > 2000px) {
+ @container (width > 3px) {
+ #child { --three-levels-middle-fail:true; }
+ }
+ }
+ }
+</style>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--three-levels-middle-fail'), '');
+ }, 'Three levels, middle fail');
+</script>
+
+
+<style>
+ @container (width: 50px) {
+ @container outer (height: 100px) {
+ #child { --inner-named-invalidation:true; }
+ }
+ }
+</style>
+<script>
+ test((t) => {
+ t.add_cleanup(() => { outer.style = ''; });
+ assert_equals(getComputedStyle(child).getPropertyValue('--inner-named-invalidation'), 'true');
+ outer.style.height = '200px';
+ assert_equals(getComputedStyle(child).getPropertyValue('--inner-named-invalidation'), '');
+ }, 'Named inner invalidation');
+</script>
+
+
+<style>
+ @container (width: 50px) {
+ @container outer (height: 100px) {
+ #child { --outer-implicit-invalidation:true; }
+ }
+ }
+</style>
+<script>
+ test((t) => {
+ t.add_cleanup(() => { inner.style = ''; });
+ assert_equals(getComputedStyle(child).getPropertyValue('--outer-implicit-invalidation'), 'true');
+ inner.style.width = '200px';
+ assert_equals(getComputedStyle(child).getPropertyValue('--outer-implicit-invalidation'), '');
+ }, 'Implicit outer invalidation');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-parsing.html b/testing/web-platform/tests/css/css-contain/container-queries/container-parsing.html
new file mode 100644
index 0000000000..87b3bdd48c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-parsing.html
@@ -0,0 +1,63 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Parsing of container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-name">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<div id="target"></div>
+<script>
+setup(() => assert_implements_container_queries());
+
+test_valid_value('container', 'initial');
+test_valid_value('container', 'inherit');
+test_valid_value('container', 'unset');
+test_valid_value('container', 'revert');
+test_valid_value('container', 'none');
+test_valid_value('container', 'none / normal', 'none');
+test_valid_value('container', 'inline-size');
+test_valid_value('container', 'none / inline-size', 'none / inline-size');
+test_valid_value('container', 'size');
+test_valid_value('container', 'block-size / size');
+test_valid_value('container', 'inline-size / inline-size');
+test_valid_value('container', 'size / size');
+test_valid_value('container', 'foo');
+test_valid_value('container', 'foo / normal', 'foo');
+test_valid_value('container', 'foo bar / size');
+test_valid_value('container', 'foo bar / normal', 'foo bar');
+test_valid_value('container', 'FOO / size');
+test_valid_value('container', 'FOO/size', 'FOO / size');
+test_valid_value('container', ' FOO /size', 'FOO / size');
+test_valid_value('container', 'normal / size');
+test_valid_value('container', 'auto / size');
+
+test_invalid_value('container', 'none none');
+test_invalid_value('container', 'none inline-size');
+test_invalid_value('container', 'none / inline-size none');
+test_invalid_value('container', 'none / inline-size normal');
+test_invalid_value('container', 'none / inline-size inline-size');
+test_invalid_value('container', 'none / inline-size block-size unknown');
+test_invalid_value('container', 'none / inline-size block-size');
+test_invalid_value('container', 'none / size block-size');
+test_invalid_value('container', 'none, none');
+test_invalid_value('container', 'none, normal');
+test_invalid_value('container', 'none / none');
+test_invalid_value('container', 'none / auto');
+test_invalid_value('container', 'none / foo');
+test_invalid_value('container', 'none / foo, bar');
+test_invalid_value('container', '#fff');
+test_invalid_value('container', '1px');
+test_invalid_value('container', 'default');
+test_invalid_value('container', '10px / inline-size');
+test_invalid_value('container', '#fefefe / inline-size');
+test_invalid_value('container', 'calc(3px) / inline-size');
+test_invalid_value('container', 'size 1 / name');
+test_invalid_value('container', 'none / block-size');
+test_invalid_value('container', 'name / block-size');
+test_invalid_value('container', ' NAME / block-size', 'NAME / block-size');
+test_invalid_value('container', 'NAME/block-size','NAME / block-size');
+test_invalid_value('container', 'block-size / block-size');
+test_invalid_value('container', 'none / size style');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-selection-unknown-features.html b/testing/web-platform/tests/css/css-contain/container-queries/container-selection-unknown-features.html
new file mode 100644
index 0000000000..8e0e34db9a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-selection-unknown-features.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<title>@container: selection using name and implicit selection</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ container-type: size;
+ width: 200px;
+ --foo: bar;
+ }
+ @container (width > 0px) {
+ div { color: green }
+ }
+ @container (width > 0px) or (foo: bar) {
+ #t1 { color: red }
+ }
+ @container (width > 0px) or foo(bar) {
+ #t2 { color: red }
+ }
+ @container style(--foo: bar) or (foo: bar) {
+ #t3 { color: red }
+ }
+</style>
+<div id="container">
+ <div id="t1">Green</div>
+ <div id="t2">Green</div>
+ <div id="t3">Green</div>
+ <div id="t4">Green</div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const green = "rgb(0, 128, 0)";
+ test(() => { assert_equals(getComputedStyle(t1).color, green); }, "width query with (foo: bar)");
+ test(() => { assert_equals(getComputedStyle(t2).color, green); }, "width query with foo(bar)");
+ test(() => { assert_equals(getComputedStyle(t3).color, green); }, "style query with (foo: bar)");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-selection.html b/testing/web-platform/tests/css/css-contain/container-queries/container-selection.html
new file mode 100644
index 0000000000..cef20f85a2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-selection.html
@@ -0,0 +1,183 @@
+<!doctype html>
+<title>@container: selection using name and implicit selection</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+
+ main { background-color: lightgray; }
+ main > div { background-color: skyblue; }
+ main > div > div { background-color: seagreen; }
+ main > div > div > div { background-color: tomato; }
+
+ main {
+ width: 64px;
+ height: 64px;
+ }
+
+ main div {
+ width: 50%;
+ height: 50%;
+ }
+
+ .inline { container-type: inline-size; }
+ .size { container-type: size; }
+
+ .a-inline { container: a / inline-size; }
+ .a-size { container: a / size; }
+
+ .b-size { container: inline- b / size; }
+ .b-size { container: b / size; }
+
+ .ab-size { container: a b / size; }
+
+ .a { container-name: a; contain: strict; }
+
+</style>
+
+<main>
+ <div class="inline">
+ <div class="size">
+ <span></span>
+ </div>
+ </div>
+</main>
+
+<main>
+ <div class="size">
+ <div class="inline">
+ <span></span>
+ </div>
+ </div>
+</main>
+
+<main>
+ <div class="inline">
+ <div class="inline">
+ <span></span>
+ </div>
+ </div>
+</main>
+
+<main>
+ <div class="a-size">
+ <div class="b-size">
+ <span></span>
+ </div>
+ </div>
+</main>
+
+<main>
+ <div class="a-size">
+ <div class="a-size">
+ <span></span>
+ </div>
+ </div>
+</main>
+
+<main>
+ <div class="a-size">
+ <div class="a">
+ <span></span>
+ </div>
+ </div>
+</main>
+
+<main>
+ <div class="a-size">
+ <div class="b-size">
+ <div class="a-inline">
+ <span></span>
+ </div>
+ </div>
+ </div>
+</main>
+
+<main>
+ <div class="a-inline">
+ <div class="b-size">
+ <span></span>
+ </div>
+ </div>
+</main>
+
+<main>
+ <div class="ab-size">
+ <div class="size">
+ <span></span>
+ </div>
+ </div>
+</main>
+
+<script>
+ setup(() => assert_implements_container_queries());
+
+ function test_query(prelude, selector, expected) {
+ test(t => {
+ let elements = document.querySelectorAll(selector);
+ assert_equals(elements.length, 1);
+ let element = elements[0];
+
+ let style = document.createElement('style');
+ t.add_cleanup(() => { style.remove(); });
+ style.innerText = `@container ${prelude} { span { --match:true; } } `;
+ document.body.append(style);
+
+ assert_equals(getComputedStyle(element).getPropertyValue('--match'), expected);
+ }, `${prelude} for ${selector}`);
+ }
+
+ // Test that a given container query applies to the specified element.
+ // The provided selector must unique identify the element.
+ function test_applied(prelude, selector) {
+ test_query(prelude, selector, 'true');
+ }
+
+ function test_rejected(prelude, selector) {
+ test_query(prelude, selector, '');
+ }
+
+ // For the following tests, the inner container has a size of 16x16px,
+ // and the outer container has a size of 32x32px.
+
+ // Implicit selection:
+ test_applied('(width: 16px)', '.size > .inline > span');
+ test_applied('(height: 16px)', '.inline > .size > span');
+ test_applied('(width: 16px)', '.inline > .size > span');
+ test_applied('(height: 32px)', '.size > .inline > span');
+ test_rejected('(height: 16px)', '.size > .inline > span');
+
+ // Name selection:
+ test_applied('a (width: 32px)', '.a-size > .b-size > span');
+ test_applied('b (width: 16px)', '.a-size > .b-size > span');
+ test_rejected('c (width)', '.a-size > .b-size > span');
+ test_applied('a (width: 16px)', '.a-size > .a-size > span');
+
+ // container-name alone does not establish a container:
+ test_applied('a (width: 32px)', '.a-size > .a > span');
+
+ // Can query container with multiple names:
+ test_applied('a (width: 32px)', '.ab-size > .size > span');
+ test_applied('b (width: 32px)', '.ab-size > .size > span');
+ test_rejected('c (width)', '.ab-size > .size > span');
+
+ // The following tests have three containers:
+ //
+ // outer -> 32x32px
+ // middle -> 16x16px
+ // inner -> 8x8px
+
+ // Combinations of name and implicit selection:
+ test_applied('a (width: 8px)', '.a-size > .b-size > .a-inline > span');
+ test_applied('b (width: 16px)', '.a-size > .b-size > .a-inline > span');
+ test_applied('a (height: 32px)', '.a-size > .b-size > .a-inline > span');
+ test_rejected('a (height)', '.a-inline > .b-size');
+
+ // Same tests as above, but logical versions:
+ test_applied('a (inline-size: 8px)', '.a-size > .b-size > .a-inline > span');
+ test_applied('b (inline-size: 16px)', '.a-size > .b-size > .a-inline > span');
+ test_applied('a (block-size: 32px)', '.a-size > .b-size > .a-inline > span');
+ test_rejected('a (block-size)', '.a-inline > .b-size');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-size-invalidation-after-load.html b/testing/web-platform/tests/css/css-contain/container-queries/container-size-invalidation-after-load.html
new file mode 100644
index 0000000000..cf5687aa39
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-size-invalidation-after-load.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<title>@container: invalidation of container size after load event</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ container-type: size;
+ width: 200px;
+ height: 4em;
+ border: 1px solid black;
+ }
+ @container (width > 300px) {
+ #child { color: green; }
+ }
+</style>
+<div id=container>
+ <div id=child>
+ Green
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ function waitForLoad(w) {
+ return new Promise(resolve => w.addEventListener('load', resolve));
+ }
+
+ promise_test(async () => {
+ await waitForLoad(window);
+ container.offsetTop;
+
+ container.style.width = '400px';
+ container.style.setProperty('--x', 'x'); // crbug.com/1321010
+
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)');
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-size-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-size-invalidation.html
new file mode 100644
index 0000000000..ab26971749
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-size-invalidation.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<title>@container-dependent elements respond to container size changes</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ container-type: size;
+ width: 200px;
+ height: 50px;
+ }
+ div { color: red; }
+ @container (min-width: 300px) {
+ div { color: green; }
+ }
+</style>
+<main id=container>
+ <div id=child>
+ Test
+ <p><span id=descendant>Deep</span></p>
+ </div>
+</main>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(function() {
+ assert_equals(getComputedStyle(child).color, 'rgb(255, 0, 0)');
+ container.style.width = '300px';
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)');
+ }, 'Children respond to changes in container size');
+
+ test(function() {
+ container.style = '';
+ assert_equals(getComputedStyle(descendant).color, 'rgb(255, 0, 0)');
+ container.style.width = '300px';
+ assert_equals(getComputedStyle(descendant).color, 'rgb(0, 128, 0)');
+ }, 'Descendants respond to changes in container size');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-size-nested-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-size-nested-invalidation.html
new file mode 100644
index 0000000000..a549f6d848
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-size-nested-invalidation.html
@@ -0,0 +1,62 @@
+<!doctype html>
+<title>Nested @container-dependent elements respond to outer container size changes</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #outer {
+ container-type: size;
+ container-name: outer;
+ width: 100px;
+ height: 100px;
+ }
+
+ /* Note that it's intentional that nothing queries this container. */
+ #inner {
+ container-type: size;
+ width: 42px;
+ height: 42px;
+ }
+
+ @container (width > 90px) {
+ #outer_child {
+ --outer:true;
+ }
+ }
+
+ @container outer (width > 70px) {
+ #inner_child {
+ --inner:true;
+ }
+ }
+</style>
+<div id=outer>
+ <div id=outer_child></div>
+ <div id=inner>
+ <div id=inner_child></div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(function() {
+ assert_equals(getComputedStyle(outer_child).getPropertyValue('--outer'), 'true');
+ assert_equals(getComputedStyle(inner_child).getPropertyValue('--inner'), 'true');
+
+ outer.style.width = '80px';
+
+ assert_equals(getComputedStyle(outer_child).getPropertyValue('--outer'), '');
+ assert_equals(getComputedStyle(inner_child).getPropertyValue('--inner'), 'true');
+
+ outer.style.width = '60px';
+
+ assert_equals(getComputedStyle(outer_child).getPropertyValue('--outer'), '');
+ assert_equals(getComputedStyle(inner_child).getPropertyValue('--inner'), '');
+
+ outer.style.width = '100px';
+
+ assert_equals(getComputedStyle(outer_child).getPropertyValue('--outer'), 'true');
+ assert_equals(getComputedStyle(inner_child).getPropertyValue('--inner'), 'true');
+ }, 'Queries that skip a container are invalidated correctly');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-size-shadow-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-size-shadow-invalidation.html
new file mode 100644
index 0000000000..b2e02a1091
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-size-shadow-invalidation.html
@@ -0,0 +1,53 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Container Queries Test: Invalidate size container query for Shadow DOM</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ .container {
+ container-type: inline-size;
+ width: 100px;
+ }
+ @container (width = 200px) {
+ .target { color: green; }
+ }
+</style>
+<div id="host_container" class="container">
+ <template shadowrootmode="open">
+ <div class="container">
+ <slot></slot>
+ </div>
+ </template>
+ <div class="target">Green</div>
+</div>
+<div id="non_host_container" class="container">
+ <div>
+ <template shadowrootmode="open">
+ <div class="container">
+ <slot></slot>
+ </div>
+ </template>
+ <div class="target">Green</div>
+ </div>
+</div>
+<script>
+ setup(() => {
+ assert_implements_container_queries();
+ });
+
+ const green = "rgb(0, 128, 0)";
+
+ test(() => {
+ document.body.offsetTop;
+ host_container.style.width = "200px";
+ assert_equals(getComputedStyle(document.querySelector("#host_container .target")).color, green);
+ }, "Host container child invalidated with container in shadow tree");
+
+ test(() => {
+ document.body.offsetTop;
+ non_host_container.style.width = "200px";
+ assert_equals(getComputedStyle(document.querySelector("#non_host_container .target")).color, green);
+ }, "Non-host container child invalidated with container in shadow tree");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-type-computed.html b/testing/web-platform/tests/css/css-contain/container-queries/container-type-computed.html
new file mode 100644
index 0000000000..0b5e033a0f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-type-computed.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Computed values of container-type</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<div id="target"></div>
+<script>
+setup(() => assert_implements_container_queries());
+
+test_computed_value('container-type', 'initial', 'normal');
+test_computed_value('container-type', 'unset', 'normal');
+test_computed_value('container-type', 'inline-size');
+test_computed_value('container-type', 'size');
+test_computed_value('container-type', 'normal');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-type-containment.html b/testing/web-platform/tests/css/css-contain/container-queries/container-type-containment.html
new file mode 100644
index 0000000000..66500a6a71
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-type-containment.html
@@ -0,0 +1,85 @@
+<!doctype html>
+<title>CSS Container Queries Test: applied containment for container-type</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<script>
+ setup(() => assert_implements_container_queries());
+</script>
+
+<style>
+ /* Note: background colors have no impact on the test result. They are
+ present to make it easier to visually verify that the test
+ does the right thing. */
+ .square {
+ width: 50px;
+ height: 50px;
+ background: tomato;
+ }
+ .half {
+ width: 25px;
+ height: 50px;
+ background: red;
+ }
+ div > div:nth-of-type(1) { background: skyblue; }
+ div > div:nth-of-type(2) { background: hotpink; }
+</style>
+
+<div id=test1 class=square>
+ <div id=float1 class=half style="float:left"></div>
+ <div id=child1 class=half style="container-type:inline-size"></div>
+</div>
+<script>
+ test(() => {
+ assert_equals(child1.offsetLeft, test1.offsetLeft + float1.offsetWidth);
+ }, 'container-type:inline-size turns on layout containment');
+</script>
+
+<hr>
+
+<div id=test2 class=square>
+ <div id=ref2 style="float:left">A</div>
+ <div id=child2 style="float:left; container-type:inline-size">A</div>
+</div>
+<script>
+ test(() => {
+ assert_equals(child2.offsetWidth, 0);
+ assert_equals(child2.offsetHeight, ref2.offsetHeight);
+ }, 'container-type:inline-size turns on inline-size containment');
+</script>
+
+<hr>
+
+<div id=test3 class=square>
+ <div id=child3 style="float:left; container-type:size">A</div>
+</div>
+<script>
+ test(() => {
+ assert_equals(child3.offsetHeight, 0);
+ assert_equals(child3.offsetWidth, 0);
+ }, 'container-type:size turns on full size containment');
+</script>
+
+<hr>
+
+<style>
+ #ref4::before, #child4::before {
+ content: counter(foo);
+ }
+</style>
+<div id=test4 class=square style="counter-set: foo 5">
+ <div id=ref4 style="float:left"></div>
+ <section style="container-type:inline-size">
+ <span style="counter-increment: foo 1000;"></span>
+ </section>
+ <section style="container-type:size">
+ <span style="counter-increment: foo 1000;"></span>
+ </section>
+ <div id=child4 style="float:left"></div>
+</div>
+<script>
+ test(() => {
+ assert_equals(child4.offsetWidth, ref4.offsetWidth);
+ }, 'container-type:inline/size turns on style containment');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-type-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-type-invalidation.html
new file mode 100644
index 0000000000..90e0b4acd1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-type-invalidation.html
@@ -0,0 +1,70 @@
+<!doctype html>
+<title>container-type invalidation</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ div {
+ color: black;
+ }
+ #outer {
+ width: 300px;
+ }
+
+ #intermediate {
+ width: 250px;
+ }
+
+ #inner {
+ width: 200px;
+ }
+
+ .container {
+ container-type: inline-size;
+ }
+
+ @container ((max-width: 200px) or (min-width: 300px)) {
+ #child { color: green; }
+ }
+
+</style>
+<div id=outer>
+ <div id=intermediate>
+ <div id=inner>
+ <div id=child>Test</div>
+ </div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(function(t) {
+ t.add_cleanup(() => {
+ for (let e of [outer, intermediate, inner])
+ e.classList.remove('container');
+ });
+
+ // No container.
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 0, 0)');
+
+ outer.classList.add('container');
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)');
+
+ // The container query does not match widths in the range [201, 299],
+ // and #intermediate has width:250px.
+ intermediate.classList.add('container');
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 0, 0)');
+
+ inner.classList.add('container');
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)');
+
+ // Should have no effect, #inner is the container.
+ outer.classList.remove('container');
+ intermediate.classList.remove('container');
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)');
+
+ inner.classList.remove('container');
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 0, 0)');
+ }, 'Changing the container type invalidates relevant descendants');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-type-layout-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-type-layout-invalidation.html
new file mode 100644
index 0000000000..3103de81f7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-type-layout-invalidation.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<title>container-type layout invalidation</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #div {
+ width: fit-content;
+ }
+</style>
+<div id=div>
+ content
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(function(t) {
+ t.add_cleanup(() => { div.style = ''; });
+
+ assert_greater_than(div.offsetWidth, 0);
+ assert_greater_than(div.offsetHeight, 0);
+
+ div.style.containerType = 'size';
+
+ assert_equals(div.offsetWidth, 0);
+ assert_equals(div.offsetHeight, 0);
+ }, 'Changing container-type invalidates layout');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-type-parsing.html b/testing/web-platform/tests/css/css-contain/container-queries/container-type-parsing.html
new file mode 100644
index 0000000000..5805a927b3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-type-parsing.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Parsing of container-type</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<div id="target"></div>
+<script>
+setup(() => assert_implements_container_queries());
+
+test_valid_value('container-type', 'initial');
+test_valid_value('container-type', 'inherit');
+test_valid_value('container-type', 'unset');
+test_valid_value('container-type', 'revert');
+test_valid_value('container-type', 'normal');
+test_valid_value('container-type', 'size');
+test_valid_value('container-type', 'inline-size');
+
+test_invalid_value('container-type', 'none');
+test_invalid_value('container-type', 'auto');
+test_invalid_value('container-type', 'block-size');
+test_invalid_value('container-type', 'normal normal');
+test_invalid_value('container-type', 'normal inline-size');
+test_invalid_value('container-type', 'inline-size normal');
+test_invalid_value('container-type', 'inline-size inline-size');
+test_invalid_value('container-type', 'inline-size block-size');
+test_invalid_value('container-type', 'block-size inline-size');
+test_invalid_value('container-type', 'size inline-size');
+test_invalid_value('container-type', 'inline-size size');
+test_invalid_value('container-type', 'normal, normal');
+test_invalid_value('container-type', 'foo');
+test_invalid_value('container-type', '"foo"');
+test_invalid_value('container-type', 'foo, bar');
+test_invalid_value('container-type', '#fff');
+test_invalid_value('container-type', '1px');
+test_invalid_value('container-type', 'default');
+test_invalid_value('container-type', 'size nonsense');
+test_invalid_value('container-type', 'style');
+test_invalid_value('container-type', 'inline-size style', 'style inline-size');
+test_invalid_value('container-type', 'style inline-size');
+test_invalid_value('container-type', 'style size');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-animation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-animation.html
new file mode 100644
index 0000000000..cf1b9a8f34
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-animation.html
@@ -0,0 +1,70 @@
+<!doctype html>
+<title>Container Relative Units: Animation</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ container-type: size;
+ width: 200px;
+ height: 200px;
+ }
+
+ @keyframes anim_cqw { from { top: 20cqw; } to { top: 40cqw; } }
+ @keyframes anim_cqh { from { top: 20cqh; } to { top: 40cqh; } }
+ @keyframes anim_cqi { from { top: 20cqi; } to { top: 40cqi; } }
+ @keyframes anim_cqb { from { top: 20cqb; } to { top: 40cqb; } }
+ @keyframes anim_cqmin { from { top: 20cqmin; } to { top: 40cqmin; } }
+ @keyframes anim_cqmax { from { top: 20cqmax; } to { top: 40cqmax; } }
+
+ #container > div {
+ animation-delay: -5s;
+ animation-play-state: paused;
+ animation-duration: 10s;
+ animation-timing-function: linear;
+ }
+
+ #element_cqw { animation-name: anim_cqw; }
+ #element_cqh { animation-name: anim_cqh; }
+ #element_cqi { animation-name: anim_cqi; }
+ #element_cqb { animation-name: anim_cqb; }
+ #element_cqmin { animation-name: anim_cqmin; }
+ #element_cqmax { animation-name: anim_cqmax; }
+
+</style>
+<div id=container>
+ <div id=element_cqw></div>
+ <div id=element_cqh></div>
+ <div id=element_cqi></div>
+ <div id=element_cqb></div>
+ <div id=element_cqmin></div>
+ <div id=element_cqmax></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const units = ['cqw', 'cqh', 'cqi', 'cqb', 'cqmin', 'cqmax'];
+
+ for (let unit of units) {
+ test(() => {
+ let element = document.getElementById(`element_${unit}`)
+ assert_equals(getComputedStyle(element).top, '60px');
+ }, `Animation using ${unit} unit`);
+
+ test(() => {
+ let element = document.getElementById(`element_${unit}`)
+ assert_equals(getComputedStyle(element).top, '60px');
+ try {
+ container.style.width = '300px';
+ container.style.height = '300px';
+ assert_equals(getComputedStyle(element).top, '90px');
+ } finally {
+ container.style = '';
+ }
+
+ assert_equals(getComputedStyle(element).top, '60px');
+ }, `Animation using ${unit} unit responds to changing container size`);
+ }
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-basic.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-basic.html
new file mode 100644
index 0000000000..166a003a29
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-basic.html
@@ -0,0 +1,54 @@
+<!doctype html>
+<title>Container Relative Units: cqi, cqb, etc</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ .inline { container-type: inline-size; }
+ .size { container-type: size; }
+ .inline.outer { width: 500px; }
+ .size.outer { height: 400px; }
+ .inline.inner { width: 300px; }
+</style>
+<div id=ref></div>
+<div class="inline outer">
+ <div class="size outer">
+ <div class="inline inner">
+ <div id=child>Test</div>
+ </div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ function assert_unit_equals(element, actual, expected) {
+ try {
+ element.style.padding = actual;
+ ref.style.padding = expected;
+ assert_equals(getComputedStyle(element).paddingLeft,
+ getComputedStyle(ref).paddingLeft);
+ } finally {
+ element.style = '';
+ ref.style = '';
+ }
+ }
+
+ test(function() {
+ assert_unit_equals(child, '0cqi', '0px');
+ assert_unit_equals(child, '1cqi', '3px');
+ assert_unit_equals(child, '10cqi', '30px');
+ assert_unit_equals(child, '10cqw', '30px');
+ assert_unit_equals(child, '10cqb', '40px');
+ assert_unit_equals(child, '10cqh', '40px');
+ assert_unit_equals(child, '10cqmin', '30px');
+ assert_unit_equals(child, '10cqmax', '40px');
+ }, 'Container relative units');
+
+ test(function() {
+ assert_unit_equals(child, '10cqi', '30px');
+ assert_unit_equals(child, '10cqb', '40px');
+ assert_unit_equals(child, 'calc(10cqi + 10cqb)', '70px');
+ assert_unit_equals(child, 'max(10cqi, 10cqb)', '40px');
+ }, 'Container relative units in math functions');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-computational-independence.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-computational-independence.html
new file mode 100644
index 0000000000..694b665c79
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-computational-independence.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>Container Relative Units: Computationally independent</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1/#computationally-independent">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const units = ['cqw', 'cqh', 'cqi', 'cqb', 'cqmin', 'cqmax'];
+
+ for (let unit of units) {
+ test(function() {
+ assert_throws_dom('SyntaxError', () => {
+ CSS.registerProperty({ name: '--x', inherits: false, syntax: '<length>', initialValue: `1${unit}` });
+ });
+ }, `Container relative unit ${unit} is not computationally independent`);
+ }
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-content-box.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-content-box.html
new file mode 100644
index 0000000000..89a76e868c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-content-box.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<title>Container Relative Units: evaluate against the content box</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+.size {
+ container-type: size;
+ width:100px;
+ height:50px;
+ border: 10px solid green;
+ padding: 10px;
+}
+.border-box {
+ box-sizing: border-box;
+}
+</style>
+<div id=ref></div>
+<div class="size">
+ <div id=child></div>
+</div>
+<div class="size border-box">
+ <div id=child2></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ function assert_unit_equals(element, actual, expected) {
+ try {
+ element.style.padding = actual;
+ ref.style.padding = expected;
+ assert_equals(getComputedStyle(element).paddingLeft,
+ getComputedStyle(ref).paddingLeft);
+ } finally {
+ element.style = '';
+ ref.style = '';
+ }
+ }
+
+ test(function() {
+ assert_unit_equals(child, '10cqi', '10px');
+ assert_unit_equals(child, '10cqw', '10px');
+ assert_unit_equals(child, '10cqb', '5px');
+ assert_unit_equals(child, '10cqh', '5px');
+ assert_unit_equals(child, '10cqmin', '5px');
+ assert_unit_equals(child, '10cqmax', '10px');
+ }, 'Container units are relative to the content box of the container');
+
+ test(function() {
+ assert_unit_equals(child2, '10cqi', '6px');
+ assert_unit_equals(child2, '10cqw', '6px');
+ assert_unit_equals(child2, '10cqb', '1px');
+ assert_unit_equals(child2, '10cqh', '1px');
+ assert_unit_equals(child2, '10cqmin', '1px');
+ assert_unit_equals(child2, '10cqmax', '6px');
+ }, 'Container units are relative to the content box of the container (box-sizing: border-box)');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient-invalidation.html
new file mode 100644
index 0000000000..665a14dcaa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient-invalidation.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>Container Relative Units in gradients</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<link rel="match" href="container-units-gradient-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+<style>
+ .container {
+ container-type: size;
+ width: 500px;
+ height: 400px;
+ display: flex;
+ flex-wrap: wrap;
+ }
+ .smaller {
+ width: 400px;
+ height: 300px;
+ }
+ .box {
+ width: 100px;
+ height: 100px;
+ margin: 5px;
+ }
+</style>
+<div class=container>
+ <div class=box style="background:linear-gradient(green 5cqw, blue 10cqh)"></div>
+ <div class=box style="background:linear-gradient(green 5cqi, blue 10cqb)"></div>
+ <div class=box style="background:linear-gradient(green 5cqmin, blue 10cqmax)"></div>
+ <div class=box style="background:radial-gradient(green 5cqw, blue 10cqh)"></div>
+ <div class=box style="background:conic-gradient(from 180deg at 10cqh, green, blue)"></div>
+</div>
+<script>
+ document.body.offsetTop;
+ document.querySelector('.container').classList.add('smaller');
+ waitForAtLeastOneFrame().then(takeScreenshot);
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient-ref.html
new file mode 100644
index 0000000000..dbdabd9bc4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<style>
+ .container {
+ width: 400px;
+ height: 300px;
+ display: flex;
+ flex-wrap: wrap;
+ }
+ .box {
+ width: 100px;
+ height: 100px;
+ margin: 5px;
+ }
+</style>
+<div class=container>
+ <div class=box style="background:linear-gradient(green 20px, blue 30px)"></div>
+ <div class=box style="background:linear-gradient(green 20px, blue 30px)"></div>
+ <div class=box style="background:linear-gradient(green 15px, blue 40px)"></div>
+ <div class=box style="background:radial-gradient(green 20px, blue 30px)"></div>
+ <div class=box style="background:conic-gradient(from 180deg at 30px, green, blue);"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient.html
new file mode 100644
index 0000000000..3d6f5378c2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-gradient.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>Container Relative Units in gradients</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<link rel="match" href="container-units-gradient-ref.html">
+<style>
+ .container {
+ container-type: size;
+ width: 400px;
+ height: 300px;
+ display: flex;
+ flex-wrap: wrap;
+ }
+ .box {
+ width: 100px;
+ height: 100px;
+ margin: 5px;
+ }
+</style>
+<div class=container>
+ <div class=box style="background:linear-gradient(green 5cqw, blue 10cqh)"></div>
+ <div class=box style="background:linear-gradient(green 5cqi, blue 10cqb)"></div>
+ <div class=box style="background:linear-gradient(green 5cqmin, blue 10cqmax)"></div>
+ <div class=box style="background:radial-gradient(green 5cqw, blue 10cqh)"></div>
+ <div class=box style="background:conic-gradient(from 180deg at 10cqh, green, blue);"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container-dynamic.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container-dynamic.html
new file mode 100644
index 0000000000..c1f929241c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container-dynamic.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<title>Container Relative Units: in @container prelude (dynamic)</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #outer {
+ container-type: size;
+ width: 40px;
+ height: 40px;
+ }
+ #container {
+ container-type: size;
+ width: 16px;
+ height: 16px;
+ }
+
+ @container ((width = 16px) and (width = 50cqw)) { #child { --cqw:true; } }
+
+</style>
+
+<div id=outer>
+ <div id=container>
+ <div id=child>Test</div>
+ </div>
+</div>
+
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(child).getPropertyValue('--cqw'), '');
+ outer.style.width = '32px';
+ assert_equals(getComputedStyle(child).getPropertyValue('--cqw'), 'true');
+ }, 'Query with container-relative units are responsive to changes');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container-fallback.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container-fallback.html
new file mode 100644
index 0000000000..3784499c38
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container-fallback.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<title>Container Relative Units: container relative units fall back to small viewport</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ iframe {
+ width: 200px;
+ height: 320px;
+ }
+</style>
+<iframe id=iframe srcdoc="
+ <style>
+ #parent {
+ container-type: inline-size;
+ width: 64px;
+ height: 50px;
+ }
+ #container {
+ container-type: size;
+ width: 32px;
+ height: 32px;
+ }
+
+ #target1, #target2 { color: green; }
+
+ /* Unit should evaluate against width of #parent */
+ @container ((height = 32px) and (height = 50cqw)) {
+ #target1 { color: blue; }
+ }
+
+ /* Unit should evaluate against height of iframe */
+ @container ((height = 32px) and (height = 10cqh)) {
+ #target2 { color: blue; }
+ }
+
+ </style>
+ <div id=parent>
+ <div id=container>
+ <div id=target1></div>
+ <div id=target2></div>
+ </div>
+ </div>
+"></iframe>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ function waitForLoad(w) {
+ return new Promise(resolve => w.addEventListener('load', resolve));
+ }
+
+ promise_test(async () => {
+ await waitForLoad(window);
+ let inner_target1 = iframe.contentDocument.querySelector('#target1');
+ let inner_target2 = iframe.contentDocument.querySelector('#target2');
+ assert_equals(getComputedStyle(inner_target1).color, 'rgb(0, 0, 255)');
+ assert_equals(getComputedStyle(inner_target2).color, 'rgb(0, 0, 255)');
+
+ iframe.style = 'height:400px';
+
+ // #target1 is not affected since it evaluated against another container.
+ // #target2 *is* affected, because it evaluated against the iframe size
+ // which just changed.
+ assert_equals(getComputedStyle(inner_target1).color, 'rgb(0, 0, 255)');
+ assert_equals(getComputedStyle(inner_target2).color, 'rgb(0, 128, 0)');
+ }, 'Use small viewport size as fallback');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container.html
new file mode 100644
index 0000000000..9ddca55ec1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-in-at-container.html
@@ -0,0 +1,111 @@
+<!doctype html>
+<title>Container Relative Units: in @container prelude</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ .size { container-type: size; }
+ .inline { container-type: inline-size; }
+ .ancestor {
+ container-type: size;
+ width: 64px;
+ height: 160px;
+ }
+ .parent {
+ container-type: inline-size;
+ width: 32px;
+ height: 77px;
+ }
+ .container {
+ container-type: size;
+ width: 16px;
+ height: 16px;
+ }
+
+ /* Unit should resolve against .parent width. */
+ @container ((width = 16px) and (width = 50cqw)) { #child1 { --cqw:true; } }
+
+ /* Unit should resolve against .ancestor height. */
+ @container ((width = 16px) and (width = 10cqh)) { #child1 { --cqh:true; } }
+
+ /* Unit should resolve against .parent width. */
+ @container ((width = 16px) and (width = 50cqi)) { #child1 { --cqi:true; } }
+
+ /* Unit should resolve against .ancestor height. */
+ @container ((width = 16px) and (width = 10cqb)) { #child1 { --cqb:true; } }
+
+ /* Unit should resolve against biggest of w/h. */
+ @container ((width = 16px) and (width = 10cqmax)) { #child1 { --cqmax:true; } }
+
+ /* Unit should resolve against smallest of w/h. */
+ @container ((width = 16px) and (width = 50cqmin)) { #child1 { --cqmin:true; } }
+
+ /* Flipped writing mode: */
+
+ /* Non-logical units are the same as above */
+ @container ((width = 16px) and (width = 50cqw)) { #child2 { --cqw:true; } }
+ @container ((width = 16px) and (width = 10cqh)) { #child2 { --cqh:true; } }
+ @container ((width = 16px) and (width = 10cqmax)) { #child2 { --cqmax:true; } }
+ @container ((width = 16px) and (width = 50cqmin)) { #child2 { --cqmin:true; } }
+
+ /* Unit should resolve against .ancestor height. */
+ @container ((width = 16px) and (width = 50cqb)) { #child2 { --cqi:true; } }
+
+ /* Unit should resolve against .parent width. */
+ @container ((width = 16px) and (width = 10cqi)) { #child2 { --cqb:true; } }
+</style>
+
+<div class=ancestor>
+ <div class=parent>
+ <div class=container>
+ <div id=child1>Test1</div>
+ </div>
+ </div>
+</div>
+
+<div class=ancestor>
+ <div class=parent>
+ <div class=container style="writing-mode:vertical-rl;">
+ <div id=child2>Test1</div>
+ </div>
+ </div>
+</div>
+
+<script>
+ setup(() => assert_implements_container_queries());
+
+ let units = [
+ 'cqw',
+ 'cqh',
+ 'cqi',
+ 'cqb',
+ 'cqmin',
+ 'cqmax',
+ ];
+
+ for (let unit of units) {
+ test(() => {
+ assert_equals(getComputedStyle(child1).getPropertyValue(`--${unit}`), 'true');
+ }, `${unit} unit resolves against appropriate container`);
+ }
+
+ // Ensure that the writing mode of the subject element is not relevant for
+ // container-relative units in the @container prelude.
+ for (let unit of units) {
+ test((t) => {
+ t.add_cleanup(() => {
+ child1.style = '';
+ });
+ child1.style.writingMode = 'vertical-rl';
+ assert_equals(getComputedStyle(child1).getPropertyValue(`--${unit}`), 'true');
+ }, `${unit} unit resolves against appropriate container (vertical writing-mode on subject)`);
+ }
+
+ for (let unit of units) {
+ test(() => {
+ assert_equals(getComputedStyle(child2).getPropertyValue(`--${unit}`), 'true');
+ }, `${unit} unit resolves against appropriate container (vertical writing-mode on container)`);
+ }
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-ineligible-container.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-ineligible-container.html
new file mode 100644
index 0000000000..8882d4a38b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-ineligible-container.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Container Relative Units: ineligible container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
+<style>
+ #grandparent, #parent { container-type: size; }
+ #grandparent { width: 300px; height: 250px; }
+ #parent { width: 200px; height: 150px; }
+ #target { width: 10cqw; height: 10cqh; }
+</style>
+<div id="log"></div>
+<div id="grandparent">
+ <div id="parent">
+ <div id="target"></div>
+ </div>
+</div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<script>
+ setup(() => assert_implements_container_queries());
+ const cases = {
+ "/* basic */": [20, 15],
+ "display: table": [30, 25],
+ "display: table-cell": [30, 25],
+ "display: inline": [30, 25],
+ "display: contents": [30, 25],
+ "display: none": [30, 25],
+ "container-type: normal": [30, 25],
+ "container-type: inline-size": [20, 25],
+ "container-type: inline-size; writing-mode: vertical-lr": [30, 15],
+ };
+ const parent = document.getElementById("parent");
+ const target = document.getElementById("target");
+ const cs = getComputedStyle(target);
+ for (let [style, [width, height]] of Object.entries(cases)) {
+ test(() => {
+ parent.style.cssText = style;
+ assert_equals(cs.width, width + "px", "width");
+ assert_equals(cs.height, height + "px", "height");
+ }, style);
+ }
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-invalidation.html
new file mode 100644
index 0000000000..abb766cd0c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-invalidation.html
@@ -0,0 +1,119 @@
+<!doctype html>
+<title>Container Relative Units: Invalidation</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #inline { container-type: inline-size; }
+ #size, #outer { container-type: size; }
+ .h600 { height: 600px; }
+ .w500 { width: 500px; }
+ .h400 { height: 400px; }
+ .w300 { width: 300px; }
+ .child {
+ padding-left: 10cqi;
+ padding-right: 10cqb;
+ }
+</style>
+<div id=ref></div>
+<div id=outer class="h600">
+ <div id=size class="w500 h400">
+ <div id=inline class="w300">
+ <div id=child class="child">Test</div>
+ <div><div id=deeper class="child">Test</div></div>
+ </div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ function assert_cqi_equals(element, expected) {
+ assert_equals(getComputedStyle(element).paddingLeft, expected);
+ }
+
+ function assert_cqb_equals(element, expected) {
+ assert_equals(getComputedStyle(element).paddingRight, expected);
+ }
+
+ test(function(t) {
+ assert_cqi_equals(child, '30px');
+ assert_cqi_equals(deeper, '30px');
+
+ try {
+ inline.style.containerType = 'normal';
+ assert_cqi_equals(child, '50px');
+ assert_cqi_equals(deeper, '50px');
+ } finally {
+ inline.style = '';
+ }
+
+ assert_cqi_equals(child, '30px');
+ assert_cqi_equals(deeper, '30px');
+ }, `cqi respond when selected container changes type (inline-size -> normal)`);
+
+ test(function() {
+ assert_cqb_equals(child, '40px');
+ assert_cqb_equals(deeper, '40px');
+
+ try {
+ size.style.containerType = 'normal';
+ assert_cqb_equals(child, '60px');
+ assert_cqb_equals(deeper, '60px');
+ } finally {
+ size.style = '';
+ }
+
+ assert_cqb_equals(child, '40px');
+ assert_cqb_equals(deeper, '40px');
+ }, `cqb respond when selected container changes type (size -> normal)`);
+
+ test(function() {
+ assert_cqb_equals(child, '40px');
+ assert_cqb_equals(deeper, '40px');
+
+ try {
+ inline.style.containerType = 'size';
+ inline.style.height = '200px';
+ assert_cqb_equals(child, '20px');
+ assert_cqb_equals(deeper, '20px');
+ } finally {
+ inline.style = '';
+ }
+
+ assert_cqb_equals(child, '40px');
+ assert_cqb_equals(deeper, '40px');
+ }, `cqb respond when intermediate container changes type (inline-size -> size)`);
+
+ test(function() {
+ assert_cqi_equals(child, '30px');
+ assert_cqi_equals(deeper, '30px');
+
+ try {
+ inline.style.width = '50px';
+ assert_cqi_equals(child, '5px');
+ assert_cqi_equals(deeper, '5px');
+ } finally {
+ inline.style = '';
+ }
+
+ assert_cqi_equals(child, '30px');
+ assert_cqi_equals(deeper, '30px');
+ }, 'cqi respond when selected container changes inline-size');
+
+ test(function() {
+ assert_cqb_equals(child, '40px');
+ assert_cqb_equals(deeper, '40px');
+
+ try {
+ size.style.height = '50px';
+ assert_cqb_equals(child, '5px');
+ assert_cqb_equals(deeper, '5px');
+ } finally {
+ size.style = '';
+ }
+
+ assert_cqb_equals(child, '40px');
+ assert_cqb_equals(deeper, '40px');
+ }, 'cqb respond when selected container changes block-size');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-media-queries.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-media-queries.html
new file mode 100644
index 0000000000..7b76f654e5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-media-queries.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<title>Container-relative units in @media</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+
+<style>
+ iframe {
+ width: 200px;
+ height: 100px;
+ }
+</style>
+
+<iframe id=iframe></iframe>
+
+<script>
+setup(() => assert_implements_container_queries());
+
+const doc = iframe.contentDocument;
+const win = iframe.contentWindow;
+
+function test_media_query(feature, result, description) {
+ test((t) => {
+ t.add_cleanup(() => { doc.body.innerHTML = ''; })
+ doc.body.innerHTML = `
+ <style>
+ body {
+ color: red;
+ }
+ @media (${feature}) {
+ body {
+ color: green;
+ }
+ }
+ </style>
+ `;
+ assert_equals(win.getComputedStyle(doc.body).color, result);
+ }, description);
+}
+
+function test_media_query_applies(feature) {
+ test_media_query(feature, 'rgb(0, 128, 0)', `@media(${feature}) applies`);
+}
+
+function test_media_query_does_not_apply(feature) {
+ test_media_query(feature, 'rgb(255, 0, 0)', `@media(${feature}) does not apply`);
+}
+
+// Container-relative units resolve against the "small viewport size" for
+// media queries.
+test_media_query_applies('width:100cqw');
+test_media_query_applies('width:100cqi');
+test_media_query_applies('width:100cqmax');
+test_media_query_applies('height:100cqh');
+test_media_query_applies('height:100cqb');
+test_media_query_applies('height:100cqmin');
+test_media_query_does_not_apply('width:90cqw');
+test_media_query_does_not_apply('height:90cqh');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-rule-cache-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-rule-cache-ref.html
new file mode 100644
index 0000000000..6c8261959f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-rule-cache-ref.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf-8">
+<style>
+ .container {
+ width: 100px;
+ }
+
+ .half {
+ height: 50%;
+ background-color: green;
+ }
+</style>
+<div class="container" style="height: 100px">
+ <div class="half"></div>
+</div>
+<div class="container" style="height: 200px">
+ <div class="half"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-rule-cache.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-rule-cache.html
new file mode 100644
index 0000000000..cc93f7793a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-rule-cache.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1832481">
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="match" href="container-units-rule-cache-ref.html">
+<style>
+ .container {
+ width: 100px;
+ container-type: size;
+ }
+
+ .half {
+ height: 50cqh;
+ background-color: green;
+ }
+</style>
+<div class="container" style="height: 100px">
+ <div class="half"></div>
+</div>
+<div class="container" style="height: 200px">
+ <div class="half"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-selection.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-selection.html
new file mode 100644
index 0000000000..16a44cd176
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-selection.html
@@ -0,0 +1,101 @@
+<!doctype html>
+<title>Container Relative Units: Advanced Container Selection</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ * { writing-mode: initial; }
+ .inline { container-type: inline-size; }
+ .size { container-type: size; }
+ .vertical { writing-mode: vertical-rl; }
+ .w500 { width: 500px; }
+ .h400 { height: 400px; }
+ .w300 { width: 300px; }
+ .h200 { height: 200px; }
+ .w100 { width: 100px; }
+</style>
+<div id=ref></div>
+<div id=c1>
+ <div id=c2>
+ <div id=c3>
+ <div id=c4>
+ <div id=child>Test</div>
+ </div>
+ </div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ function assert_unit_equals(element, actual, expected) {
+ try {
+ element.style.padding = actual;
+ ref.style.padding = expected;
+ assert_equals(getComputedStyle(element).paddingLeft,
+ getComputedStyle(ref).paddingLeft);
+ } finally {
+ element.style = '';
+ ref.style = '';
+ }
+ }
+
+ test(() => {
+ try {
+ c1.className = 'inline w500'; // Selected by nothing.
+ c2.className = 'size h400 w300'; // Selected by cqh, cqb.
+ c3.className = 'inline w100'; // Selected by cqw, cqi.
+ assert_unit_equals(child, '10cqw', '10px');
+ assert_unit_equals(child, '10cqi', '10px');
+ assert_unit_equals(child, '10cqh', '40px');
+ assert_unit_equals(child, '10cqb', '40px');
+ assert_unit_equals(child, '10cqmin', '10px');
+ assert_unit_equals(child, '10cqmax', '40px');
+
+ c3.className = ''; // cqw, cqi now selects c2 instead.
+ assert_unit_equals(child, '10cqw', '30px');
+ assert_unit_equals(child, '10cqi', '30px');
+ assert_unit_equals(child, '10cqh', '40px');
+ assert_unit_equals(child, '10cqb', '40px');
+ assert_unit_equals(child, '10cqmin', '30px');
+ assert_unit_equals(child, '10cqmax', '40px');
+
+ } finally {
+ for (let c of [c1, c2, c3, c4, child])
+ c.className = '';
+ }
+ }, 'Container units select the proper container');
+
+ test(() => {
+ try {
+ c1.className = 'size w500 h400';
+ c2.className = 'inline w300 h200';
+
+ // [cqi, cqb] corresponds to [cqw, cqh].
+ assert_unit_equals(child, '10cqw', '30px');
+ assert_unit_equals(child, '10cqi', '30px');
+ assert_unit_equals(child, '10cqh', '40px');
+ assert_unit_equals(child, '10cqb', '40px');
+
+ child.className = 'vertical';
+ // [cqi, cqb] now corresponds to [cqh, cqw].
+ assert_unit_equals(child, '10cqw', '30px');
+ assert_unit_equals(child, '10cqi', '40px');
+ assert_unit_equals(child, '10cqh', '40px');
+ assert_unit_equals(child, '10cqb', '30px');
+
+ c2.classList.add('vertical');
+ // The inline containment on #c2 now applies to the vertical axis.
+ // [cqi, cqb] still corresponds to [cqh, cqw], but we now expect
+ // cqh to resolve against #c2, and cqw to resolve against #c1.
+ assert_unit_equals(child, '10cqw', '50px');
+ assert_unit_equals(child, '10cqi', '20px');
+ assert_unit_equals(child, '10cqh', '20px');
+ assert_unit_equals(child, '10cqb', '50px');
+
+ } finally {
+ for (let c of [c1, c2, c3, c4, child])
+ c.className = '';
+ }
+ }, 'Units respond to the writing-mode of the element');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-shadow.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-shadow.html
new file mode 100644
index 0000000000..0e4172c90e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-shadow.html
@@ -0,0 +1,63 @@
+<!doctype html>
+<title>Container Relative Units: Shadow DOM</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #outer {
+ container-type: size;
+ width: 200px;
+ height: 200px;
+ }
+ #direct {
+ container-type: inline-size;
+ width: 50cqw;
+ height: 50cqh;
+ }
+ #nondirect {
+ width: 10cqw;
+ height: 10cqh;
+ background: green;
+ }
+</style>
+<div id=outer>
+ <div>
+ <template shadowrootmode="open">
+ <style>
+ #inner {
+ container-type: size;
+ width: 30px;
+ height: 30px;
+ }
+ </style>
+ <div id=inner>
+ <slot></slot>
+ </div>
+ </template>
+ <div>
+ <div id=direct>
+ <div id=nondirect>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+<script>
+ setup(() => {
+ assert_implements_container_queries();
+ });
+
+ test(() => {
+ let cs = getComputedStyle(direct);
+ assert_equals(cs.width, '100px');
+ assert_equals(cs.height, '100px');
+ }, 'Direct slotted child queries shadow-including ancestors');
+
+ test(() => {
+ let cs = getComputedStyle(nondirect);
+ assert_equals(cs.width, '10px'); // #direct
+ assert_equals(cs.height, '20px'); // #outer
+ }, 'Nondirect slotted child queries shadow-including ancestors');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-sharing-via-rule-node-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-sharing-via-rule-node-ref.html
new file mode 100644
index 0000000000..c664ce4ccf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-sharing-via-rule-node-ref.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<style>
+.test {
+ border: 1px solid;
+ max-width: max-content;
+}
+
+span {
+ display: block;
+ background-color: green;
+}
+</style>
+<div class="test">
+ <span style="width: 40px; height: 40px"></span>
+</div>
+<div class="test">
+ <span style="width: 100px; height: 100px"></span>
+</div>
+<div class="test">
+ <span style="width: 200px; height: 200px"></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-sharing-via-rule-node.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-sharing-via-rule-node.html
new file mode 100644
index 0000000000..e1a5c71451
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-sharing-via-rule-node.html
@@ -0,0 +1,53 @@
+<!doctype html>
+<meta charset="utf-8">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1835179">
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="match" href="container-units-sharing-via-rule-node-ref.html">
+<style>
+.test {
+ position: relative;
+ z-index: 0;
+ border: 1px solid;
+ max-width: max-content;
+}
+
+.container {
+ position: absolute;
+ container-type: size;
+ inset: 0;
+}
+
+.container-content {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100cqi;
+ height: 100cqb;
+ background-color: green;
+}
+
+span {
+ display: block;
+ background-color: red;
+}
+</style>
+<div class="test">
+ <div class="container">
+ <div class="container-content"></div>
+ </div>
+ <span style="width: 40px; height: 40px"></span>
+</div>
+<div class="test">
+ <div class="container">
+ <div class="container-content"></div>
+ </div>
+ <span style="width: 100px; height: 100px"></span>
+</div>
+<div class="test">
+ <div class="container">
+ <div class="container-content"></div>
+ </div>
+ <span style="width: 200px; height: 200px"></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-small-viewport-fallback.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-small-viewport-fallback.html
new file mode 100644
index 0000000000..6c8851681f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-small-viewport-fallback.html
@@ -0,0 +1,70 @@
+<!doctype html>
+<title>Container Relative Units: fall back to small viewport</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ iframe {
+ width: 200px;
+ height: 40px;
+ }
+</style>
+<iframe id=iframe srcdoc="
+ <style>
+ #container {
+ container-type: inline-size;
+ width: 70px;
+ height: 30px;
+ }
+ #target {
+ left: 10cqw;
+ top: 10cqh;
+ right: 10cqi;
+ bottom: 10cqb;
+ margin-left: 10cqmax;
+ margin-right: 10cqmin;
+ }
+ </style>
+ <div id=container>
+ <div id=target></div>
+ </div>
+"></iframe>
+
+<script>
+ setup(() => assert_implements_container_queries());
+
+ function waitForLoad(w) {
+ return new Promise(resolve => w.addEventListener('load', resolve));
+ }
+
+ promise_test(async () => {
+ await waitForLoad(window);
+ let inner_target = iframe.contentDocument.querySelector('#target');
+
+ // Since there's an inline-size container, cqw/cqi should evaluate against
+ // that.
+ assert_equals(getComputedStyle(inner_target).left, '7px'); // 10cqw
+ assert_equals(getComputedStyle(inner_target).right, '7px'); // 10cqi
+
+ // However, there is no size container, so cqh/cqb should evaluate against
+ // the small viewport size.
+ assert_equals(getComputedStyle(inner_target).top, '4px'); // 10cqh
+ assert_equals(getComputedStyle(inner_target).bottom, '4px'); // 10cqb
+
+ assert_equals(getComputedStyle(inner_target).marginLeft, '7px'); // 10cqmax
+ assert_equals(getComputedStyle(inner_target).marginRight, '4px'); // 10cqmin
+
+ iframe.style = 'width:400px;height:80px';
+
+ // Not affected by resize:
+ assert_equals(getComputedStyle(inner_target).left, '7px'); // 10cqw
+ assert_equals(getComputedStyle(inner_target).right, '7px'); // 10cqi
+
+ // Affected:
+ assert_equals(getComputedStyle(inner_target).top, '8px'); // 10cqh
+ assert_equals(getComputedStyle(inner_target).bottom, '8px'); // 10cqb
+ assert_equals(getComputedStyle(inner_target).marginLeft, '8px'); // 10cqmax
+ assert_equals(getComputedStyle(inner_target).marginRight, '7px'); // 10cqmin
+ }, 'Use small viewport size as fallback');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-svglength.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-svglength.html
new file mode 100644
index 0000000000..8bb227c049
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-svglength.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<title>CSS Container Queries Test: container-relative units in SVGLength</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<link rel="help" href="https://svgwg.org/svg2-draft/types.html#InterfaceSVGLength">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<script src="/resources/SVGAnimationTestCase-testharness.js"></script>
+<style>
+ #container {
+ container-type: size;
+ width: 200px;
+ height: 150px;
+ }
+</style>
+<div id=container>
+ <svg id=rootSVGElement>
+ <rect id="rect1" width="10cqw" height="10cqh"/>
+ <rect id="rect2" width="10cqi" height="10cqb"/>
+ <rect id="rect3" width="10cqmin" height="10cqmax"/>
+ <rect id="rect4" width="calc(10cqmin + 10cqmax)" height="calc(10cqw + 3px)"/>
+ <rect id="rect_dynamic"/>
+ <rect id="rect_animated" width="42px" height="42px" fill="green">
+ <animate id=animation attributeName=width from="5cqw" to="10cqw" begin="0s" dur="4s"/>
+ </rect>
+ </svg>
+</div>
+<script>
+ setup(() => {
+ assert_implements_container_queries();
+ container.offsetTop;
+ });
+
+ function cleanup() {
+ rect_dynamic.removeAttribute('width');
+ rect_dynamic.removeAttribute('height');
+ }
+
+ test(() => {
+ assert_equals(rect1.width.baseVal.unitType, SVGLength.SVG_LENGTHTYPE_UNKNOWN);
+ }, 'unitType with container-relative units');
+
+ test(() => {
+ assert_equals(rect1.width.baseVal.value, 20);
+ assert_equals(rect1.height.baseVal.value, 15);
+ }, 'cqw,cqh can be resolved');
+
+ test(() => {
+ assert_equals(rect2.width.baseVal.value, 20);
+ assert_equals(rect2.height.baseVal.value, 15);
+ }, 'cqi,cqb can be resolved');
+
+ test(() => {
+ assert_equals(rect3.width.baseVal.value, 15);
+ assert_equals(rect3.height.baseVal.value, 20);
+ }, 'cqmin,cqmax can be resolved');
+
+ test(() => {
+ assert_equals(rect4.width.baseVal.value, 35);
+ assert_equals(rect4.height.baseVal.value, 23);
+ }, 'calc() with container-relative units can be resolved');
+
+ test((t) => {
+ t.add_cleanup(cleanup);
+ rect_dynamic.setAttribute('width', '20cqw');
+ rect_dynamic.setAttribute('height', '20cqh');
+ assert_equals(rect_dynamic.width.baseVal.value, 40);
+ assert_equals(rect_dynamic.height.baseVal.value, 30);
+
+ rect_dynamic.width.baseVal.value = 80;
+ rect_dynamic.height.baseVal.value = 45;
+ assert_equals(rect_dynamic.getAttribute('width'), '80');
+ assert_equals(rect_dynamic.getAttribute('height'), '45');
+ }, 'Can modify value with container-relative units');
+
+ smil_async_test((t) => {
+ t.add_cleanup(cleanup);
+ let assert_width = (expected) => {
+ let epsilon = 1.0;
+ return () => {
+ assert_approx_equals(rect_animated.width.animVal.value, expected, epsilon);
+ };
+ };
+ const expectedValues = [
+ // [animationId, time, sampleCallback]
+ ["animation", 0.0, assert_width(10)],
+ ["animation", 2.0, assert_width(15)],
+ ["animation", 3.999, assert_width(20)],
+ ["animation", 4, assert_width(42)],
+ ];
+
+ runAnimationTest(t, expectedValues);
+ });
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/container-units-typed-om.html b/testing/web-platform/tests/css/css-contain/container-queries/container-units-typed-om.html
new file mode 100644
index 0000000000..6da3306fdf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/container-units-typed-om.html
@@ -0,0 +1,59 @@
+<!doctype html>
+<title>Container Relative Units: CSS Typed OM</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-lengths">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<div id=element></div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const units = ['cqw', 'cqh', 'cqi', 'cqb', 'cqmin', 'cqmax'];
+ const functions = {
+ cqw: CSS.cqw,
+ cqh: CSS.cqh,
+ cqi: CSS.cqi,
+ cqb: CSS.cqb,
+ cqmin: CSS.cqmin,
+ cqmax: CSS.cqmax,
+ };
+
+ for (let unit of units) {
+ let func = functions[unit];
+
+ test(() => {
+ assert_equals(`${func(10)}`, `10${unit}`);
+ }, `CSS.${unit} function`);
+
+ test(() => {
+ try {
+ element.style.top = `10${unit}`;
+ let value = element.attributeStyleMap.get('top');
+ assert_equals(value.value, 10);
+ assert_equals(value.unit, unit);
+ } finally {
+ element.style = '';
+ }
+ }, `Reify value with ${unit} unit`);
+
+ test(() => {
+ try {
+ element.attributeStyleMap.set('top', `10${unit}`);
+ assert_equals(element.style.top, `10${unit}`);
+ } finally {
+ element.style = '';
+ }
+ }, `Set value with ${unit} unit (string)`);
+
+ test(() => {
+ try {
+ element.attributeStyleMap.set('top', func(10));
+ assert_equals(element.style.top, `10${unit}`);
+ } finally {
+ element.style = '';
+ }
+ }, `Set value with ${unit} unit (CSS.${unit})`);
+ }
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/counters-flex-circular.html b/testing/web-platform/tests/css/css-contain/container-queries/counters-flex-circular.html
new file mode 100644
index 0000000000..d60049e26c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/counters-flex-circular.html
@@ -0,0 +1,76 @@
+<!doctype html>
+<title>CSS Container Queries Test: counters inside container should not affect container size via flex layout</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #flex {
+ width: 200px;
+ display: flex;
+ flex-direction: row;
+ counter-reset: my-count 0;
+ }
+ /* #item1 grows to use remaining space given #item2's content */
+ #item1 {
+ flex-grow: 1;
+ height: 100px;
+ }
+ #container {
+ container-type: size;
+ }
+ #item2 {
+ flex-grow: 0;
+ font: 50px/1 Ahem;
+ }
+ /* #item2 size depends on generated content which depends on my-count
+ counter. */
+ #item2::before {
+ display: inline-block;
+ content: counter(my-count);
+ }
+ /* The counter-increment inside the container should not affect the size of
+ #item2 because of style containment. Otherwise we would have a
+ circularity. */
+ @container (min-width: 125px) {
+ #inner {
+ counter-increment: my-count 10;
+ background-color: green;
+ }
+ }
+</style>
+<div id="flex">
+ <div id="item1">
+ <div id="container">
+ <div id="inner"></div>
+ </div>
+ </div>
+ <div id="item2"></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const item1_width = parseInt(getComputedStyle(item1).width);
+ const item2_width = parseInt(getComputedStyle(item2).width);
+ const container_width = parseInt(getComputedStyle(container).width);
+ const inner_width = parseInt(getComputedStyle(inner).width);
+
+ test(() => {
+ assert_equals(item1_width, container_width);
+ assert_equals(item1_width, inner_width);
+ }, "#item1, #container, and #inner should all have the same width: " + item1_width);
+
+ test(() => {
+ let expected_background = container_width >= 125 ? "rgb(0, 128, 0)" : "rgba(0, 0, 0, 0)";
+ assert_equals(getComputedStyle(inner).backgroundColor, expected_background);
+ }, "The container query should match the layed out width");
+
+ test(() => {
+ assert_equals(item1_width + item2_width, 200);
+ }, "The sum of the item widths should match the flexbox width");
+
+ test(() => {
+ assert_equals(parseInt(getComputedStyle(item2, "::before").width), item2_width);
+ }, "The size of the flex item #2 should be given by its contents");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/counters-in-container-dynamic.html b/testing/web-platform/tests/css/css-contain/container-queries/counters-in-container-dynamic.html
new file mode 100644
index 0000000000..d85ab6cb42
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/counters-in-container-dynamic.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<title>CSS Container Queries Test: counter updates</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type">
+<link rel="match" href="counters-ref.html">
+<style>
+ #container {
+ container-type: size;
+ width: 200px;
+ height: 200px;
+ }
+
+ #counter::before {
+ content: counter(my-counter);
+ }
+
+ @container (min-width: 300px) {
+ #counter {
+ counter-reset: my-counter 100;
+ }
+ }
+</style>
+<p>Pass if you see the number 100 below.</p>
+<div id="container">
+ <div id="counter"></div>
+</div>
+<script>
+ container.offsetTop;
+ container.style.width = "400px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/counters-in-container.html b/testing/web-platform/tests/css/css-contain/container-queries/counters-in-container.html
new file mode 100644
index 0000000000..376f52ea7c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/counters-in-container.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<title>CSS Container Queries Test: counters depending on container queries</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-type">
+<link rel="match" href="counters-ref.html">
+<style>
+ #container {
+ container-type: size;
+ width: 200px;
+ height: 200px;
+ }
+
+ #counter::before {
+ content: counter(my-counter);
+ }
+
+ @container (min-width: 200px) {
+ #counter {
+ counter-reset: my-counter 100;
+ }
+ }
+</style>
+<p>Pass if you see the number 100 below.</p>
+<div id="container">
+ <div id="counter"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/counters-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/counters-ref.html
new file mode 100644
index 0000000000..303c1e89bd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/counters-ref.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<p>Pass if you see the number 100 below.</p>
+<div>100</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/br-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/br-crash.html
new file mode 100644
index 0000000000..6631ba2fd5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/br-crash.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<title>Don't crash for blocky &lt;br> (etc) with inline-size containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#contain-property">
+<link rel="help" href="https://crbug.com/1313444">
+<br style="container-type:inline-size; display:block;">
+<wbr style="container-type:inline-size; display:block;">
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/canvas-as-container-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/canvas-as-container-crash.html
new file mode 100644
index 0000000000..ae7fe8dc16
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/canvas-as-container-crash.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<title>CSS Container Queries Test: Absolute positioned canvas container crash</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://crbug.com/1289850">
+<p>Pass if there is no crash.</p>
+<canvas id="canv" style="display:block;position:absolute;container-type:inline-size"></canvas>
+<script>
+ canv.offsetTop;
+ canv.appendChild(document.createElement("span"));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1289718-000-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1289718-000-crash.html
new file mode 100644
index 0000000000..f30461919a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1289718-000-crash.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1289718">
+<div style="container-type:inline-size;">
+ <span style="columns:2;"></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1289718-001-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1289718-001-crash.html
new file mode 100644
index 0000000000..ce530fb2c8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1289718-001-crash.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1289718">
+<div style="container-type:inline-size;">
+ <video style="columns:2;"></video>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1346969-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1346969-crash.html
new file mode 100644
index 0000000000..37c74cf8cb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1346969-crash.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>Chrome crash bug 1346969</title>
+<link rel="help" href="https://crbug.com/1346969">
+<table id="table"> </table>
+<script>
+ document.body.offsetTop;
+ table.style.containerType = "inline-size";
+ table.style.appearance = "auto";
+ table.style.columnCount = 2;
+ table.createTBody();
+ table.createCaption();
+ document.body.offsetTop;
+ table.style.whiteSpace = "pre-wrap";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1362391-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1362391-crash.html
new file mode 100644
index 0000000000..d4e1fec400
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1362391-crash.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<title>DCHECK failure for style recalc from layout tree rebuild</title>
+<link rel="help" href="https://crbug.com/1362391">
+<div style="display:table-column-group">
+ <div style="container-type:size">
+ <image title="crash"></image>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1429955-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1429955-crash.html
new file mode 100644
index 0000000000..bdf4002753
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1429955-crash.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1429955.html">
+<div id="mc" style="display:list-item; width:0; columns:2; container-type:size;">
+ <div id="abs" style="position:absolute; container-type:inline-size;">line</div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1505250-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1505250-crash.html
new file mode 100644
index 0000000000..befbfd33af
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-bug-1505250-crash.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>::first-letter depending on size container query with changing list-style-type</title>
+<link rel="help" href="https://crbug.com/1505250">
+<style>
+ div::first-letter{
+ color: green;
+ }
+ div:only-of-type {
+ container-type: size;
+ list-style: my-circle inside;
+ }
+</style>
+<div>X
+ <div></div>
+ <script>document.body.offsetTop</script>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-custom-highlight-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-custom-highlight-crash.html
new file mode 100644
index 0000000000..61e5075ed4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-custom-highlight-crash.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<title>Empty ::highlight styles inside @container causes crash</title>
+<link rel="help" href="https://crbug.com/1486352">
+<style>
+ @container (width) {
+ section::highlight(custom-highlight) {
+ --foo: bar;
+ }
+ }
+</style>
+<section style="container-type:inline-size"></section>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-layout-root-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-layout-root-crash.html
new file mode 100644
index 0000000000..e3e709a240
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-layout-root-crash.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<html class="reftest-wait">
+<link rel="help" href="https://crbug.com/1371820">
+<style>
+ body, div, img { container-type: size; }
+</style>
+<p>Pass if no crash.</p>
+<div id="div"><img id="img" alt="a"></div>
+<script>
+ requestAnimationFrame(() => requestAnimationFrame(() => {
+ // Adds a layout root inside the div size container.
+ img.alt = img.src = "b";
+ // Marks div size container for layout which skips style recalc for the sub-tree.
+ div.style.width = "500px";
+ document.documentElement.classList.remove("reftest-wait");
+ }));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-quotes-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-quotes-crash.html
new file mode 100644
index 0000000000..363f96fd02
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-quotes-crash.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<title>Container Queries Test: Quotes update outside container being laid out causes crash</title>
+<link rel="help" href="https://crbug.com/1313003">
+<style>
+ div { container-type: size }
+</style>
+<div style="float: right">
+ <span></span>
+ <div style="position:absolute"><q></q></div>
+ <q></q>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-remove-insert-evaluator-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-remove-insert-evaluator-crash.html
new file mode 100644
index 0000000000..986f6b0bf6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/chrome-remove-insert-evaluator-crash.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>Removing and re-inserting a container should crash</title>
+<link rel="help" href="https://crbug.com/1342750">
+<style>
+ #container { container-type: inline-size }
+</style>
+<div id="outer">
+ <div id="container"></div>
+</div>
+<script>
+ container.offsetTop;
+ let removed = container;
+ container.remove();
+ outer.appendChild(removed);
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/columns-in-table-001-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/columns-in-table-001-crash.html
new file mode 100644
index 0000000000..fe421500da
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/columns-in-table-001-crash.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<title>CSS Container Queries Test: TR container with multicol TD crashes Chrome</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://crbug.com/1291471">
+<p>Pass if test does not crash.</p>
+<table>
+ <tr style="container-type:size;">
+ <td style="columns:2"></td>
+ </tr>
+</table>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/columns-in-table-002-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/columns-in-table-002-crash.html
new file mode 100644
index 0000000000..24b9f1aab2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/columns-in-table-002-crash.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>CSS Container Queries Test: container with multicol table-header-group crashes Chrome</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://crbug.com/1307656">
+<p>Pass if test does not crash.</p>
+<div id="container" style="container-type:inline-size">
+ <span style="display:table-header-group;columns:1"></span>
+ <span style="display:table-header-group;"></span>
+</div>
+<script>
+ // This originally caused a crash.
+ document.body.offsetTop;
+ // Additionally make sure we don't crash when the container is re-attached.
+ container.style.display = "inline-block";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/container-in-canvas-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/container-in-canvas-crash.html
new file mode 100644
index 0000000000..215c6a04db
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/container-in-canvas-crash.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<title>Don't crash with a container query container inside canvas</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3">
+<link rel="help" href="https://crbug.com/1321471">
+<canvas>
+ <div>
+ <div style="container-type: size">
+ <div>Test</div>
+ </div>
+ </div>
+</canvas>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/container-type-change-chrome-legacy-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/container-type-change-chrome-legacy-crash.html
new file mode 100644
index 0000000000..609142a2c5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/container-type-change-chrome-legacy-crash.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>CSS Container Queries Test: Changing container-type in Chrome legacy layout</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://crbug.com/1286773">
+<p>Pass if there is no crash.</p>
+<span style="column-count: 1"><table></table></span>
+<video id="video"></video>
+<input id="input"></input>
+<script>
+ document.body.offsetTop;
+ video.style.containerType = "inline-size";
+ document.body.offsetLeft;
+ video.style.columnCount = "1";
+ input.setAttribute("type", "button");
+ document.body.offsetTop;
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/dialog-backdrop-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/dialog-backdrop-crash.html
new file mode 100644
index 0000000000..3bbdf160cf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/dialog-backdrop-crash.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<style>
+ html {
+ overflow: hidden;
+ }
+
+ dialog {
+ container-type: size;
+ width: 100px;
+ height: 100px;
+ }
+
+ @container (width > 1px) {
+ dialog::backdrop {
+ margin: 10px;
+ background-color: green;
+ }
+ }
+</style>
+<dialog id=dialog>
+ Hello World
+</dialog>
+<script>
+ dialog.showModal();
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/dirty-rowgroup-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/dirty-rowgroup-crash.html
new file mode 100644
index 0000000000..2a66cd452a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/dirty-rowgroup-crash.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<div style='container-type: size;'></div>
+<table>
+ <tbody id='id_0'></tbody>
+ <th id='id_1'>
+ <tr>
+ <th></th>
+ </tr>
+ </th>
+</table>
+<script>
+ const tbody = document.getElementById('id_0')
+ tbody.getBoundingClientRect();
+ const theader = document.getElementById('id_1')
+ tbody.outerText = 'foo';
+ theader.setAttribute('rowspan', 100)
+ tbody.getBoundingClientRect();
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-000-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-000-crash.html
new file mode 100644
index 0000000000..e7b789345c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-000-crash.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898">
+<style>
+ @container (max-width: 500px) {
+ #target {
+ display: flex;
+ }
+ }
+</style>
+<div id="container" style="columns:2; container-type:inline-size; width:600px;">
+ <div id="target"></div>
+</div>
+<script>
+ document.body.offsetTop;
+ container.style.width = "400px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-001-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-001-crash.html
new file mode 100644
index 0000000000..0c0648c15b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-001-crash.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898">
+<style>
+ @container (max-width: 500px) {
+ #target {
+ display: flex;
+ }
+ }
+</style>
+<div id="container" style="columns:2; container-type:inline-size; width:400px;">
+ <div id="target"></div>
+</div>
+<script>
+ document.body.offsetTop;
+ container.style.width = "600px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-002-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-002-crash.html
new file mode 100644
index 0000000000..ef3052d2c9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-002-crash.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898">
+<style>
+ @container (max-width: 250px) {
+ #target {
+ display: flex;
+ }
+ }
+</style>
+<div id="ancestor" style="columns:2; column-gap:0; width:600px;">
+ <div style="container-type:inline-size;">
+ <div id="target"></div>
+ </div>
+</div>
+<script>
+ document.body.offsetTop;
+ ancestor.style.width = "400px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-003-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-003-crash.html
new file mode 100644
index 0000000000..a86f25a773
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/flex-in-columns-003-crash.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898">
+<style>
+ @container (max-width: 250px) {
+ #target {
+ display: flex;
+ }
+ }
+</style>
+<div id="ancestor" style="columns:2; column-gap:0; width:400px;">
+ <div style="container-type:inline-size;">
+ <div id="target"></div>
+ </div>
+</div>
+<script>
+ document.body.offsetTop;
+ ancestor.style.width = "600px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/focus-inside-content-visibility-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/focus-inside-content-visibility-crash.html
new file mode 100644
index 0000000000..1bf68d6686
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/focus-inside-content-visibility-crash.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<title>Container Queries Test: size change detected while focusing inside content-visibility: auto container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#using-cv-auto">
+<link rel="help" href="https://crbug.com/1270848">
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+
+<style>
+.spacer { height: 3000px; }
+.auto { content-visibility: auto; }
+#container {
+ border: 1px solid black;
+ width: 100px;
+ height: 100px;
+
+ container-type: size;
+}
+#input {
+ width: 100%;
+ visibility: hidden;
+}
+@container (min-width: 150px) {
+ #input { visibility: visible; }
+}
+
+</style>
+
+<div class=spacer></div>
+<div class=auto>
+ <div id=container>
+ <input id=input type=text></input>
+ </div>
+</div>
+
+<script>
+function focus() {
+ container.style.width = "200px";
+ input.focus();
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(focus));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/force-sibling-style-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/force-sibling-style-crash.html
new file mode 100644
index 0000000000..093a01b809
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/force-sibling-style-crash.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>getComputedStyle on sibling of style-dirty container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://crbug.com/1306385">
+<div id=ancestor style="--x:foo">
+ <div id=container style="container-type:size;width:100px;">
+ <span>Test</span>
+ </div>
+ <div id=target></div>
+</div>
+<script>
+ ancestor.offsetTop;
+ ancestor.style.setProperty('--x', 'bar');
+ container.style.width = '200px';
+ getComputedStyle(target).getPropertyValue('--x');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-000-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-000-crash.html
new file mode 100644
index 0000000000..56cf6cfdbb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-000-crash.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898">
+<style>
+ @container (max-width: 500px) {
+ #target {
+ display: grid;
+ }
+ }
+</style>
+<div id="container" style="columns:2; container-type:inline-size; width:600px;">
+ <div id="target"></div>
+</div>
+<script>
+ document.body.offsetTop;
+ container.style.width = "400px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-001-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-001-crash.html
new file mode 100644
index 0000000000..b9cf100533
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-001-crash.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898">
+<style>
+ @container (max-width: 500px) {
+ #target {
+ display: grid;
+ }
+ }
+</style>
+<div id="container" style="columns:2; container-type:inline-size; width:400px;">
+ <div id="target"></div>
+</div>
+<script>
+ document.body.offsetTop;
+ container.style.width = "600px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-002-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-002-crash.html
new file mode 100644
index 0000000000..762ad44f24
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-002-crash.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898">
+<style>
+ @container (max-width: 250px) {
+ #target {
+ display: grid;
+ }
+ }
+</style>
+<div id="ancestor" style="columns:2; column-gap:0; width:600px;">
+ <div style="container-type:inline-size;">
+ <div id="target"></div>
+ </div>
+</div>
+<script>
+ document.body.offsetTop;
+ ancestor.style.width = "400px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-003-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-003-crash.html
new file mode 100644
index 0000000000..11089e6902
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/grid-in-columns-003-crash.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898">
+<style>
+ @container (max-width: 250px) {
+ #target {
+ display: grid;
+ }
+ }
+</style>
+<div id="ancestor" style="columns:2; column-gap:0; width:400px;">
+ <div style="container-type:inline-size;">
+ <div id="target"></div>
+ </div>
+</div>
+<script>
+ document.body.offsetTop;
+ ancestor.style.width = "600px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/iframe-init-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/iframe-init-crash.html
new file mode 100644
index 0000000000..e915c2479f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/iframe-init-crash.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<audio controls style='container-type: size'></audio>
+<iframe>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-multicol-inside-container-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-multicol-inside-container-crash.html
new file mode 100644
index 0000000000..7e209f7ffd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-multicol-inside-container-crash.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>CSS Container Queries Test: Inline multicol inside size container - crash</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://crbug.com/829028">
+<style>
+ #container {
+ container-type: size;
+ width: 200px;
+ height: 100px;
+ }
+ @container (width <= 200px) {
+ #multicol {
+ column-count: 2;
+ column-gap: 0;
+ }
+ }
+</style>
+<p>Test passes if it doesn't crash.</p>
+<div id="container">
+ <span id="multicol"><div></div></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-with-columns-000-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-with-columns-000-crash.html
new file mode 100644
index 0000000000..733b2c4ee9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-with-columns-000-crash.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898">
+<style>
+ @container (max-width: 500px) {
+ #target {
+ columns: 2;
+ }
+ }
+</style>
+<div id="container" style="container-type:inline-size; width:600px;">
+ <span id="target"></span>
+</div>
+<script>
+ document.body.offsetTop;
+ container.style.width = "400px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-with-columns-001-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-with-columns-001-crash.html
new file mode 100644
index 0000000000..3b9bdf32bd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/inline-with-columns-001-crash.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898">
+<style>
+ @container (max-width: 500px) {
+ #target {
+ columns: 2;
+ }
+ }
+</style>
+<div id="container" style="container-type:inline-size; width:400px;">
+ <span id="target"></span>
+</div>
+<script>
+ document.body.offsetTop;
+ container.style.width = "600px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/input-column-group-container-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/input-column-group-container-crash.html
new file mode 100644
index 0000000000..5e520a45cf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/input-column-group-container-crash.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>CSS Container Queries Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<link rel="help" href="https://crbug.com/1282782">
+<p>Pass if this test does not crash</p>
+<span style="column-count: 1">
+ <span style="display:table-column-group"></span>
+ <input id="inp">
+</span>
+<script>
+ document.body.offsetTop;
+ document.body.style.setProperty("container", "inline-size");
+ inp.setAttribute("type", "image");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/input-placeholder-inline-size-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/input-placeholder-inline-size-crash.html
new file mode 100644
index 0000000000..4b1284e5cb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/input-placeholder-inline-size-crash.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>CSS Container Queries Test: Crash: input inline-size container with placeholder</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://crbug.com/1288692">
+<p>Pass if this test does not crash</p>
+<input id="input" style="container-type:size">
+<script>
+ document.body.offsetTop;
+ input.style.position = "absolute";
+ input.setAttribute("placeholder", "placeholder");
+ document.body.offsetTop;
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/marker-gcs-after-disconnect-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/marker-gcs-after-disconnect-crash.html
new file mode 100644
index 0000000000..3680c79512
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/marker-gcs-after-disconnect-crash.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>Don't crash during getComputedStyle which removes ::marker</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3">
+<link rel="help" href="https://crbug.com/1349732">
+<style>
+#container {
+ width: 100px;
+ height: 100px;
+ container-type: size;
+}
+@container (width) {
+ span { color: green; }
+}
+</style>
+<ul>
+ <li id="target"></li>
+</ul>
+<div id=container>
+ <span>PASS if no crash</span>
+</div>
+<script>
+let li = document.querySelector('li');
+getComputedStyle(target, '::marker').width;
+li.style.listStyleType = 'none';
+getComputedStyle(target, '::marker').width;
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/math-block-container-child-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/math-block-container-child-crash.html
new file mode 100644
index 0000000000..00b6836655
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/math-block-container-child-crash.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>CSS Container Queries Test: Math block container child crash</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://crbug.com/1294268">
+<p>Pass if there is no crash.</p>
+<math id="m" style="display:block math"></math>
+<script>
+ let div = document.createElement("div");
+ div.style.containerType = "size";
+ m.appendChild(div);
+ div.appendChild(document.createElement("span"));
+ document.body.offsetTop;
+ div.style.color = "green";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/mathml-container-type-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/mathml-container-type-crash.html
new file mode 100644
index 0000000000..538c1b5445
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/mathml-container-type-crash.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>container-type invalidation crash test</title>
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1878188">
+<math>
+ <malignmark id="target" style="container-type: size"/>
+</math>
+<script>
+ onload = () => target.style.containerType = "inline-size"
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/orthogonal-replaced-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/orthogonal-replaced-crash.html
new file mode 100644
index 0000000000..10474fd984
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/orthogonal-replaced-crash.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<title>Chrome crash for replaced in orthogonal flow query container</title>
+<link rel="help" href="https://crbug.com/1325673">
+<p>Pass if no crash.</p>
+<iframe></iframe>
+<style>
+ body {
+ container-type: size;
+ writing-mode: vertical-rl;
+ }
+</style>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/pseudo-container-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/pseudo-container-crash.html
new file mode 100644
index 0000000000..f998c3a446
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/pseudo-container-crash.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>CSS Container Queries Test: No crash when ::after is a container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container">
+<link rel="help" href="https://crbug.com/1225381">
+<style>
+ div::after {
+ container-type: size;
+ content: '';
+ display: block;
+ }
+</style>
+<div>
+ PASS if no crash
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/remove-dom-child-change-style.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/remove-dom-child-change-style.html
new file mode 100644
index 0000000000..739af63ccb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/remove-dom-child-change-style.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1494659">
+<div id="container" style="container-type:inline-size;">
+ <div id="other"></div>
+ <div id="foo"></div>
+</div>
+<script>
+ document.body.offsetTop;
+ container.style.width = "100px";
+ other.style.color = "pink";
+ foo.remove();
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/reversed-ol-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/reversed-ol-crash.html
new file mode 100644
index 0000000000..fa4d35380c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/reversed-ol-crash.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>Don't crash with intermediate container in reversed list</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-style">
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-style">
+<link rel="help" href="https://crbug.com/1377644">
+<style>
+.container {
+ container-type: size;
+}
+
+/* Prevent double layout due to scrollbar speculation */
+html {
+ overflow: hidden;
+}
+
+@container (width > 1px) {
+ .item {
+ display: list-item;
+ }
+}
+</style>
+<ol reversed>
+ <li>A</li>
+ <div class=container>
+ <div class=item>
+ B
+ </div>
+ </div>
+</ol>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/size-change-during-transition-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/size-change-during-transition-crash.html
new file mode 100644
index 0000000000..80be45b8fd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/size-change-during-transition-crash.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>Container Queries - Size change during transitions crash</title>
+<script src="/common/reftest-wait.js"></script>
+<link rel="help" href="https://crbug.com/1451359">
+<style>
+ #outer {
+ container-type: inline-size;
+ width: 100px;
+ }
+ #inner {
+ background-color: black;
+ transition: background-color 60s;
+ }
+ #inner.target {
+ background-color: white;
+ }
+ @container (width > 200px) {
+ #inner.target {
+ background-color: lime;
+ }
+ }
+</style>
+<p>Pass if no crash.</p>
+<div id="outer">
+ <div id="inner">Look at my background</div>
+</div>
+<script>
+ inner.offsetTop;
+ inner.className = "target";
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ outer.style.width = "300px";
+ takeScreenshot();
+ });
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/svg-layout-root-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/svg-layout-root-crash.html
new file mode 100644
index 0000000000..75a3839add
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/svg-layout-root-crash.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<title>@container changing display of SVG element should not crash</title>
+<link rel="help" href="https://crbug.com/1245689">
+<iframe id="frame" style="width: 200px"></iframe>
+<script>
+ frame.srcdoc = `
+ <style>
+ #container {
+ container-type: inline-size;
+ }
+ @container (min-width: 300px) {
+ .hide { display: none; }
+ }
+ </style>
+ <div id="container">
+ <div class="hide"><svg></svg></div>
+ </div>`;
+
+ requestAnimationFrame(() =>
+ requestAnimationFrame(() =>
+ requestAnimationFrame(() => frame.style.width = "400px")));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/svg-text-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/svg-text-crash.html
new file mode 100644
index 0000000000..aadba08679
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/svg-text-crash.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<title>SVG text element with size container-type should not crash</title>
+<link rel="help" href="https://crbug.com/1298319">
+<style>
+ text { container-type: inline-size; }
+</style>
+<p>Pass if no crash.</p>
+<svg><text></text></svg>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-000-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-000-crash.html
new file mode 100644
index 0000000000..566a4eb1eb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-000-crash.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898">
+<style>
+ @container (max-width: 500px) {
+ #target {
+ display: table;
+ }
+ }
+</style>
+<div id="container" style="columns:2; container-type:inline-size; width:600px;">
+ <div id="target"></div>
+</div>
+<script>
+ document.body.offsetTop;
+ container.style.width = "400px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-001-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-001-crash.html
new file mode 100644
index 0000000000..4fab9de88f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-001-crash.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898">
+<style>
+ @container (max-width: 500px) {
+ #target {
+ display: table;
+ }
+ }
+</style>
+<div id="container" style="columns:2; container-type:inline-size; width:400px;">
+ <div id="target"></div>
+</div>
+<script>
+ document.body.offsetTop;
+ container.style.width = "600px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-002-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-002-crash.html
new file mode 100644
index 0000000000..4f0cdc0740
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-002-crash.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898">
+<style>
+ @container (max-width: 250px) {
+ #target {
+ display: table;
+ }
+ }
+</style>
+<div id="ancestor" style="columns:2; column-gap:0; width:600px;">
+ <div style="container-type:inline-size;">
+ <div id="target"></div>
+ </div>
+</div>
+<script>
+ document.body.offsetTop;
+ ancestor.style.width = "400px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-003-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-003-crash.html
new file mode 100644
index 0000000000..436da592d9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-003-crash.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276898">
+<style>
+ @container (max-width: 250px) {
+ #target {
+ display: table;
+ }
+ }
+</style>
+<div id="ancestor" style="columns:2; column-gap:0; width:400px;">
+ <div style="container-type:inline-size;">
+ <div id="target"></div>
+ </div>
+</div>
+<script>
+ document.body.offsetTop;
+ ancestor.style.width = "600px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-004-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-004-crash.html
new file mode 100644
index 0000000000..daed42f009
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-004-crash.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>CSS Container Queries Crash Test</title>
+<link rel="help" href="https://crbug.com/1338055">
+<p>Pass if no crash</p>
+<div style="container-type:inline-size">
+ <span style="columns: 1">
+ <canvas>
+ <script>
+ document.body.offsetTop;
+ </script>
+ <div style="container-type:inline-size">
+ <span style="display:table-column-group"></span>
+ </div>
+ </canvas>
+ </span>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-005-crash.html b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-005-crash.html
new file mode 100644
index 0000000000..60d6f9d3a1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/crashtests/table-in-columns-005-crash.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<title>CSS Container Queries Crash Test</title>
+<link rel="help" href="https://crbug.com/1336334">
+<li style="container-type:inline-size">
+ <span style="columns:2">
+ <table></table>
+ </span>
+</li>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/custom-layout-container-001.https.html b/testing/web-platform/tests/css/css-contain/container-queries/custom-layout-container-001.https.html
new file mode 100644
index 0000000000..8f301e8ebf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/custom-layout-container-001.https.html
@@ -0,0 +1,66 @@
+<!doctype html>
+<html class=reftest-wait>
+<title>CSS Container Queries Test: Size queries on CSS Layout API containers</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://drafts.css-houdini.org/css-layout-api/">
+<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/worklet-reftest.js"></script>
+<style>
+ #test1 {
+ width: 400px;
+ height: 100px;
+ }
+ #outer {
+ display: inline; /* Shouldn't pass without layout api support */
+ display: layout(half);
+ height: 100px;
+ container-type: inline-size;
+ }
+ @container (width = 400px) {
+ #inner {
+ display: inline; /* Shouldn't pass without layout api support */
+ display: layout(half);
+ height: 100px;
+ container-type: inline-size;
+ }
+ }
+ @container (width = 200px) {
+ #green {
+ background-color: green;
+ height: 100px;
+ }
+ }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id="test1">
+ <div id="outer">
+ <div id="inner">
+ <div id="green"></div>
+ </div>
+ </div>
+</div>
+
+<script id="code" type="text/worklet">
+ registerLayout("half", class {
+ async intrinsicSizes() {}
+ async layout(children, edges, constraints, styleMap) {
+ const childInlineSize = constraints.fixedInlineSize / 2;
+ const childFragments = await Promise.all(children.map((child) => {
+ return child.layoutNextFragment({fixedInlineSize: childInlineSize});
+ }));
+
+ for (let childFragment of childFragments) {
+ childFragment.inlineOffset = 0;
+ childFragment.blockOffset = 0;
+ }
+ const autoBlockSize = 100;
+ return {autoBlockSize, childFragments};
+ }
+ });
+</script>
+
+<script>
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, document.getElementById("code").textContent);
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/custom-property-style-queries.html b/testing/web-platform/tests/css/css-contain/container-queries/custom-property-style-queries.html
new file mode 100644
index 0000000000..29b5004af0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/custom-property-style-queries.html
@@ -0,0 +1,436 @@
+<!doctype html>
+<title>CSS Container Queries Test: custom property style queries</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#style-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #outer {
+ container-name: outer;
+ --inner: false;
+ --outer: true;
+ --inner-no-space:false;
+ --outer-no-space:true;
+ --inner-space-after:false ;
+ --outer-space-after:true ;
+ }
+ #inner {
+ --inner: true;
+ --outer: false;
+ --inner-no-space:true;
+ --outer-no-space:false;
+ --inner-space-after:true ;
+ --outer-space-after:false ;
+ }
+</style>
+<div id="outer">
+ <div id="inner">
+ <div id="target"></div>
+ </div>
+</div>
+<script>
+ const green = "rgb(0, 128, 0)";
+
+ function test_evaluation(query, expected) {
+ test((t) => {
+ let style_node = document.createElement('style');
+ t.add_cleanup(() => {
+ style_node.remove();
+ });
+ style_node.innerText = `@container ${query} { #target { --applied:true; } }`;
+
+ assert_equals(getComputedStyle(target).getPropertyValue('--applied'), '');
+ document.head.append(style_node);
+ assert_equals(getComputedStyle(target).getPropertyValue('--applied'), expected ? 'true' : '');
+ }, `${query}`);
+ }
+
+ setup(() => assert_implements_container_queries());
+
+ test_evaluation('style(--inner: true)', true);
+ test_evaluation('style(--inner:true)', true);
+ test_evaluation('style(--inner:true )', true);
+ test_evaluation('style(--inner: true )', true);
+ test_evaluation('style(--inner-no-space: true)', true);
+ test_evaluation('style(--inner-no-space:true)', true);
+ test_evaluation('style(--inner-no-space:true )', true);
+ test_evaluation('style(--inner-no-space: true )', true);
+ test_evaluation('style(--inner-space-after: true)', true);
+ test_evaluation('style(--inner-space-after:true)', true);
+ test_evaluation('style(--inner-space-after:true )', true);
+ test_evaluation('style(--inner-space-after: true )', true);
+ test_evaluation('style(--outer: true)', false);
+ test_evaluation('style(--outer:true)', false);
+ test_evaluation('style(--outer:true )', false);
+ test_evaluation('style(--outer: true )', false);
+ test_evaluation('style(--outer-no-space: true)', false);
+ test_evaluation('style(--outer-no-space:true)', false);
+ test_evaluation('style(--outer-no-space:true )', false);
+ test_evaluation('style(--outer-no-space: true )', false);
+ test_evaluation('style(--outer-space-after: true)', false);
+ test_evaluation('style(--outer-space-after:true)', false);
+ test_evaluation('style(--outer-space-after:true )', false);
+ test_evaluation('style(--outer-space-after: true )', false);
+ test_evaluation('outer style(--inner: true)', false);
+ test_evaluation('outer style(--inner:true)', false);
+ test_evaluation('outer style(--inner:true )', false);
+ test_evaluation('outer style(--inner: true )', false);
+ test_evaluation('outer style(--inner-no-space: true)', false);
+ test_evaluation('outer style(--inner-no-space:true)', false);
+ test_evaluation('outer style(--inner-no-space:true )', false);
+ test_evaluation('outer style(--inner-no-space: true )', false);
+ test_evaluation('outer style(--inner-space-after: true)', false);
+ test_evaluation('outer style(--inner-space-after:true)', false);
+ test_evaluation('outer style(--inner-space-after:true )', false);
+ test_evaluation('outer style(--inner-space-after: true )', false);
+ test_evaluation('outer style(--outer: true)', true);
+ test_evaluation('outer style(--outer:true)', true);
+ test_evaluation('outer style(--outer:true )', true);
+ test_evaluation('outer style(--outer: true )', true);
+ test_evaluation('outer style(--outer-no-space: true)', true);
+ test_evaluation('outer style(--outer-no-space:true)', true);
+ test_evaluation('outer style(--outer-no-space:true )', true);
+ test_evaluation('outer style(--outer-no-space: true )', true);
+ test_evaluation('outer style(--outer-space-after: true)', true);
+ test_evaluation('outer style(--outer-space-after:true)', true);
+ test_evaluation('outer style(--outer-space-after:true )', true);
+ test_evaluation('outer style(--outer-space-after: true )', true);
+</script>
+
+<style>
+ #important {
+ --foo: bar;
+ }
+ @container style(--foo: bar !important) {
+ #important-child { color: green; }
+ }
+</style>
+<div id="important">
+ <div id="important-child"></div>
+</div>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#important-child")).color, green);
+ }, "Query custom property with !important declaration");
+</script>
+
+<style>
+ #var-query {
+ --foo: baz;
+ --bar: baz;
+ }
+ @container style(--foo: var(--bar)) {
+ #var-subst { color: green; }
+ }
+ @container not style(--foo: var(--unknown)) {
+ #var-subst-unknown { color: green; }
+ }
+ @container not style(--foo: var(--unknown, nomatch)) {
+ #var-subst-unknown-fallback { color: green; }
+ }
+ @container style(--foo: var(--unknown, baz)) {
+ #var-subst-matching-fallback { color: green; }
+ }
+ @container style(--baz: var(--unknown)) {
+ #var-subst-unknown-matching { color: green; }
+ }
+</style>
+<div id="var-query">
+ <div id="var-subst"></div>
+ <div id="var-subst-unknown"></div>
+ <div id="var-subst-unknown-fallback"></div>
+ <div id="var-subst-matching-fallback"></div>
+ <div id="var-subst-unknown-matching"></div>
+</div>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#var-subst")).color, green);
+ }, "Query custom property using var()");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#var-subst-unknown")).color, green);
+ }, "Query custom property including unknown var() reference");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#var-subst-unknown-fallback")).color, green);
+ }, "Query custom property including unknown var() reference with non-matching fallback");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#var-subst-matching-fallback")).color, green);
+ }, "Query custom property including unknown var() reference with matching fallback");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#var-subst-unknown-matching")).color, green);
+ }, "Query custom property matching guaranteed-invalid values");
+</script>
+
+<style>
+ #revert {
+ --foo: revert;
+ }
+ #revert-layer {
+ --foo: revert-layer;
+ }
+ #revert-child, #revert-layer-child {
+ color: green;
+ }
+ @container style(--foo: revert) {
+ #revert-child { color: red; }
+ }
+ @container style(--foo: revert-layer) {
+ #revert-layer-child { color: red; }
+ }
+</style>
+<div id="revert">
+ <div id="revert-child"></div>
+</div>
+<div id="revert-layer">
+ <div id="revert-layer-child"></div>
+</div>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#revert-child")).color, green);
+ }, "Style query with revert keyword is false");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#revert-layer-child")).color, green);
+ }, "Style query with revert-layer keyword is false");
+</script>
+
+<style>
+ #defaulting {
+ --inherit: baz;
+ --inherit-no: baz;
+ }
+ #defaulting-container {
+ --inherit-no: bar;
+ --unset-no: baz;
+ --initial-no: baz;
+ }
+ @container style(--initial: initial) {
+ #initial { color: green; }
+ }
+ @container not style(--initial) {
+ #initial-implicit { color: green; }
+ }
+ @container not style(--initial-no: initial) {
+ #initial-no { color: green; }
+ }
+ @container style(--initial-no) {
+ #initial-no-implicit { color: green; }
+ }
+ @container style(--inherit: inherit) {
+ #inherit { color: green; }
+ }
+ @container not style(--inherit-no: inherit) {
+ #inherit-no { color: green; }
+ }
+ @container style(--unset: unset) {
+ #unset { color: green; }
+ }
+ @container not style(--unset-no: unset) {
+ #unset-no { color: green; }
+ }
+</style>
+<div id="defaulting">
+ <div id="defaulting-container">
+ <div id="initial"></div>
+ <div id="initial-implicit"></div>
+ <div id="initial-no"></div>
+ <div id="initial-no-implicit"></div>
+ <div id="inherit"></div>
+ <div id="inherit-no"></div>
+ <div id="unset"></div>
+ <div id="unset-no"></div>
+ </div>
+</div>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#initial")).color, green);
+ }, "Style query 'initial' matching");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#initial-implicit")).color, green);
+ }, "Style query matching negated value-less query against initial value");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#initial-no")).color, green);
+ }, "Style query 'initial' not matching");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#initial-no-implicit")).color, green);
+ }, "Style query matching value-less query against non-initial value");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#inherit")).color, green);
+ }, "Style query 'inherit' matching");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#inherit-no")).color, green);
+ }, "Style query 'inherit' not matching");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#unset")).color, green);
+ }, "Style query 'unset' matching");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#unset-no")).color, green);
+ }, "Style query 'unset' not matching");
+</script>
+
+<style>
+ @property --reg-length {
+ syntax: "<length>";
+ inherits: false;
+ initial-value: 10px;
+ }
+
+ #registered {
+ container-type: inline-size;
+ width: 200px;
+ font-size: 20px;
+ }
+
+ #reg-container-px {
+ --reg-length: 10px;
+ }
+ @container style(--reg-length: 10px) {
+ #reg-px { color: green; }
+ }
+ @container style(--reg-length: initial) {
+ #reg-px-initial { color: green; }
+ }
+ @container not style(--reg-length) {
+ #reg-px-initial-implicit { color: green; }
+ }
+
+ #reg-container-font-relative {
+ --reg-length: 10px;
+ }
+ @container style(--reg-length: 0.5em) {
+ #reg-font-relative { color: green; }
+ }
+
+ #reg-container-font-relative-2 {
+ --reg-length: 0.5em;
+ }
+ @container style(--reg-length: 10px) {
+ #reg-font-relative-2 { color: green; }
+ }
+
+ #reg-container-container-relative {
+ width: 100px;
+ --reg-length: 100px;
+ }
+ @container style(--reg-length: 50cqi) {
+ #reg-container-relative { color: green; }
+ }
+
+ #reg-container-initial {
+ --reg-length: 10px;
+ }
+ @container style(--reg-length: 10px) {
+ #reg-initial-value { color: green; }
+ }
+ @container style(--reg-length: initial) {
+ #reg-initial-keyword { color: green; }
+ }
+ @container not style(--reg-length) {
+ #reg-initial-implicit { color: green; }
+ }
+</style>
+<div id="registered">
+ <div id="reg-container-px">
+ <div id="reg-px"></div>
+ <div id="reg-px-initial"></div>
+ <div id="reg-px-initial-implicit"></div>
+ </div>
+ <div id="reg-container-font-relative">
+ <div id="reg-font-relative"></div>
+ </div>
+ <div id="reg-container-font-relative-2">
+ <div id="reg-font-relative-2"></div>
+ </div>
+ <div id="reg-container-container-relative">
+ <div id="reg-container-relative"></div>
+ </div>
+ <div id="reg-container-initial">
+ <div id="reg-initial-value"></div>
+ <div id="reg-initial-keyword"></div>
+ <div id="reg-initial-implicit"></div>
+ </div>
+</div>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#reg-px")).color, green);
+ }, "Match registered <length> custom property with px.");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#reg-px-initial")).color, green);
+ }, "Match registered <length> custom property with px via initial keyword.");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#reg-font-relative")).color, green);
+ }, "Match registered <length> custom property with em in query.");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#reg-font-relative-2")).color, green);
+ }, "Match registered <length> custom property with em in computed value.");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#reg-container-relative")).color, green);
+ }, "Match registered <length> custom property with cqi unit.");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#reg-initial-value")).color, green);
+ }, "Match registered <length> custom property with initial value.");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#reg-initial-keyword")).color, green);
+ }, "Match registered <length> custom property with initial value via initial keyword.");
+</script>
+
+<style>
+ #original-text {
+ --number: 100.00;
+ --spaces: a b;
+ }
+ @container style(--number: 100.00) {
+ #original-text-number {
+ color: green;
+ }
+ }
+ @container style(--number: 100.0) {
+ #original-text-number {
+ color: red;
+ }
+ }
+ @container style(--number: 100) {
+ #original-text-number {
+ color: red;
+ }
+ }
+ @container style(--spaces: a b) {
+ #original-text-spaces {
+ color: green;
+ }
+ }
+ @container style(--number: a b) {
+ #original-text-spaces {
+ color: red;
+ }
+ }
+</style>
+<div id="original-text">
+ <div id="original-text-number"></div>
+ <div id="original-text-spaces"></div>
+</div>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#original-text-number")).color, green);
+ }, "Should only match exact string for numbers in non-registered custom properties");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#original-text-spaces")).color, green);
+ }, "Spaces should not collapse in non-registered custom properties");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/custom-property-style-query-change.html b/testing/web-platform/tests/css/css-contain/container-queries/custom-property-style-query-change.html
new file mode 100644
index 0000000000..6669ede31d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/custom-property-style-query-change.html
@@ -0,0 +1,89 @@
+<!doctype html>
+<title>CSS Container Queries Test: custom property style query changes</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#style-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container { container-name: my-container; }
+ #child, #grandchild { color: red; }
+ @container style(--target: child) {
+ #child { color: green; }
+ }
+ @container my-container style(--target: grandchild) {
+ #grandchild { color: green; }
+ }
+</style>
+<div id="container">
+ <div id="child"></div>
+ <div>
+ <div id="grandchild"></div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const green = "rgb(0, 128, 0)";
+ const red = "rgb(255, 0, 0)";
+
+ test(() => {
+ assert_equals(getComputedStyle(child).color, red);
+ assert_equals(getComputedStyle(grandchild).color, red);
+ }, "Initially no queries match.");
+
+ test(() => {
+ container.style.setProperty("--target", "child");
+ assert_equals(getComputedStyle(child).color, green);
+ assert_equals(getComputedStyle(grandchild).color, red);
+ }, "Target child");
+
+ test(() => {
+ container.style.setProperty("--target", "grandchild");
+ assert_equals(getComputedStyle(child).color, red);
+ assert_equals(getComputedStyle(grandchild).color, green);
+ }, "Target grandchild");
+</script>
+
+<style>
+ @property --length {
+ syntax: "<length>";
+ inherits: false;
+ initial-value: 0px;
+ }
+
+ #reg_container {
+ container-name: my-reg-container;
+ font-size: 50px;
+ }
+ #reg_child, #reg_grandchild { color: red; }
+ @container style(--length: 100px) {
+ #reg_child { color: green; }
+ }
+ @container my-reg-container style(--length: 200px) {
+ #reg_grandchild { color: green; }
+ }
+</style>
+<div id="reg_container">
+ <div id="reg_child"></div>
+ <div>
+ <div id="reg_grandchild"></div>
+ </div>
+</div>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(reg_child).color, red);
+ assert_equals(getComputedStyle(reg_grandchild).color, red);
+ }, "Initially no queries for registered property match.");
+
+ test(() => {
+ reg_container.style.setProperty("--length", "2em");
+ assert_equals(getComputedStyle(reg_child).color, green);
+ assert_equals(getComputedStyle(reg_grandchild).color, red);
+ }, "Registered property query child");
+
+ test(() => {
+ reg_container.style.setProperty("--length", "200px");
+ assert_equals(getComputedStyle(reg_child).color, red);
+ assert_equals(getComputedStyle(reg_grandchild).color, green);
+ }, "Registered property query grandchild");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/deep-nested-inline-size-containers.html b/testing/web-platform/tests/css/css-contain/container-queries/deep-nested-inline-size-containers.html
new file mode 100644
index 0000000000..00bc8b0a6b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/deep-nested-inline-size-containers.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<title>CSS Container Queries Test: Deeply nested inline-size container queries</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style id="test_style">
+ .container { container-type: inline-size; }
+ #outer { width: 200px; }
+</style>
+<div id="outer" class="container"></div>
+<script>
+ setup(() => {
+ assert_implements_container_queries();
+
+ // Create 50 nested inline-size containers where a child container is 1px
+ // narrower than its parent
+ let sheet = test_style.sheet;
+ let container = outer;
+ for (let width = 200; width > 150; --width) {
+ sheet.insertRule(`
+ @container (width = ${width}px) {
+ .container { max-width: ${width-1}px; }
+ }
+ `);
+ let child = document.createElement("div");
+ child.className = "container";
+ container.appendChild(child);
+ container = child;
+ }
+ });
+
+ test(() => {
+ let expected_width = 200;
+ for (let container of document.querySelectorAll(".container"))
+ assert_equals(container.offsetWidth, expected_width--);
+ }, "Test that all container widths match");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/dialog-backdrop-create.html b/testing/web-platform/tests/css/css-contain/container-queries/dialog-backdrop-create.html
new file mode 100644
index 0000000000..ef74973add
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/dialog-backdrop-create.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<title>CSS Container Queries Test: ::backdrop appearing conditionally on dialog container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<link rel="match" href="top-layer-dialog-backdrop-ref.html">
+<style>
+ html {
+ /* Prevent multiple layout passes due to scrollbars */
+ overflow: hidden;
+ background: red;
+ }
+ dialog {
+ container-type: size;
+ width: 100px;
+ height: 100px;
+ visibility: hidden;
+ }
+ dialog::backdrop {
+ visibility: visible;
+ display: none;
+ background-color: green;
+ }
+ @container (width > 1px) {
+ dialog::backdrop {
+ display: block;
+ }
+ }
+</style>
+<dialog id="dialog"></dialog>
+<script>
+ dialog.showModal();
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/dialog-backdrop-remove.html b/testing/web-platform/tests/css/css-contain/container-queries/dialog-backdrop-remove.html
new file mode 100644
index 0000000000..47b4030492
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/dialog-backdrop-remove.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<title>CSS Container Queries Test: ::backdrop disappearing conditionally on dialog container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<link rel="match" href="top-layer-dialog-backdrop-ref.html">
+<style>
+ html {
+ /* Prevent multiple layout passes due to scrollbars */
+ overflow: hidden;
+ background: green;
+ }
+ dialog {
+ container-type: size;
+ width: 100px;
+ height: 100px;
+ visibility: hidden;
+ }
+ dialog::backdrop {
+ display: block;
+ background-color: red;
+ }
+ @container (width > 1px) {
+ dialog::backdrop {
+ display: none;
+ }
+ }
+</style>
+<dialog id="dialog"></dialog>
+<script>
+ dialog.showModal();
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/display-contents-dynamic-style-queries.html b/testing/web-platform/tests/css/css-contain/container-queries/display-contents-dynamic-style-queries.html
new file mode 100644
index 0000000000..782cf56655
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/display-contents-dynamic-style-queries.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<title>CSS Container Queries Test: Invalidate style queries and display:contents</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#style-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container.contents {
+ --foo: bar;
+ display: contents;
+ }
+ #target {
+ color: red;
+ }
+ @container style(--foo: bar) {
+ #target {
+ color: green;
+ }
+ }
+</style>
+<div id="container">
+ <div id="target">This should be green</div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(target).color, "rgb(255, 0, 0)");
+ }, "Initially the color is red");
+
+ test(() => {
+ container.className = "contents";
+ assert_equals(getComputedStyle(target).color, "rgb(0, 128, 0)");
+ }, "After display and --foo changes, style() query causes the color to be green");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/display-contents.html b/testing/web-platform/tests/css/css-contain/container-queries/display-contents.html
new file mode 100644
index 0000000000..d96a46d06a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/display-contents.html
@@ -0,0 +1,93 @@
+<!doctype html>
+<title>@container and display:contents</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-size">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<script>
+ setup(() => assert_implements_container_queries());
+</script>
+<style>
+ .container {
+ container-type: inline-size;
+ width: 30px;
+ height: 30px;
+ background: tomato;
+ }
+ .big {
+ width: 50px;
+ height: 50px;
+ background: skyblue;
+ }
+ .contents {
+ display: contents;
+ }
+
+ @container (width: 30px) {
+ .target { --x:30; }
+ }
+
+ @container (width: 50px) {
+ .target { --x:50; }
+ }
+
+ main {
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+</style>
+
+<main>
+ <!-- Container is display:contents -->
+ <div class="container contents">
+ <div>
+ <div class="target" id=target1></div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target1);
+ assert_equals(s.getPropertyValue('--x'), '');
+ }, 'getComputedStyle when container is display:contents');
+ </script>
+
+ <!-- Container becomes display:contents -->
+ <div id=container2 class="container">
+ <div>
+ <div class="target" id=target2></div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target2);
+ assert_equals(s.getPropertyValue('--x'), '30');
+ container2.classList.add('contents');
+ assert_equals(s.getPropertyValue('--x'), '');
+ container2.classList.remove('contents');
+ assert_equals(s.getPropertyValue('--x'), '30');
+ }, 'getComputedStyle when container becomes display:contents');
+ </script>
+
+ <!-- Intermediate container becomes display:contents -->
+ <div class="container">
+ <div>
+ <div id=container3 class="container">
+ <div>
+ <div class="target" id=target3></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target3);
+ assert_equals(s.getPropertyValue('--x'), '30');
+ container3.classList.add('contents');
+ assert_equals(s.getPropertyValue('--x'), '');
+ container3.classList.remove('contents');
+ assert_equals(s.getPropertyValue('--x'), '30');
+ }, 'getComputedStyle when intermediate container becomes display:contents');
+ </script>
+</main>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/display-in-container-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/display-in-container-ref.html
new file mode 100644
index 0000000000..fd8e9ef0c1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/display-in-container-ref.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<style>
+ .container, .not_a_container {
+ width: auto;
+ height: 100px;
+ border: 1px solid black;
+ margin-bottom: 10px;
+ }
+ span {
+ border: 1px solid green;
+ margin: 2px;
+ }
+</style>
+<div style="width:150px">
+ <div class=container>
+ <main>
+ <div style="display:flex">
+ <span style="flex:1">Test1</span>
+ <span style="flex:1">Test2</span>
+ <span style="flex:1">Test3</span>
+ </div>
+ </main>
+ </div>
+</div>
+<div style="width:200px">
+ <div class=container>
+ <main>
+ <div>
+ <span style="display:block">Test1</span>
+ <span style="display:block">Test2</span>
+ <span style="display:block">Test3</span>
+ </div>
+ </main>
+ </div>
+</div>
+<div style="width:150px">
+ <div class=not_a_container>
+ <main>
+ <div>
+ <span>Test1</span>
+ <span>Test2</span>
+ <span>Test3</span>
+ </div>
+ </main>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/display-in-container.html b/testing/web-platform/tests/css/css-contain/container-queries/display-in-container.html
new file mode 100644
index 0000000000..a2a4cd731c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/display-in-container.html
@@ -0,0 +1,69 @@
+<!doctype html>
+<title>CSS Container Queries Test: @container queries affecting display type</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<link rel="match" href="display-in-container-ref.html">
+<style>
+ .container, .not_a_container {
+ width: auto;
+ height: 100px;
+ border: 1px solid black;
+ margin-bottom: 10px;
+ }
+ .container {
+ container-type: size;
+ }
+ span {
+ border: 1px solid green;
+ margin: 2px;
+ }
+
+ /* Note: 150px - 2px, since .container has a 1px border */
+ @container (min-width: 148px) {
+ div { display: flex; }
+ span { flex: 1; }
+ }
+
+ /* Note: 200px - 2px, since .container has a 1px border */
+ @container (min-width: 198px) {
+ div { display: revert; }
+ span { display: block; }
+ }
+
+ /* Should not apply: */
+ @container (min-width: 199px) {
+ * { color: red; background-color: red; }
+ }
+</style>
+<div style="width:150px">
+ <div class=container>
+ <main>
+ <div>
+ <span>Test1</span>
+ <span>Test2</span>
+ <span>Test3</span>
+ </div>
+ </main>
+ </div>
+</div>
+<div style="width:200px">
+ <div class=container>
+ <main>
+ <div>
+ <span>Test1</span>
+ <span>Test2</span>
+ <span>Test3</span>
+ </div>
+ </main>
+ </div>
+</div>
+<div style="width:150px">
+ <div class=not_a_container>
+ <main>
+ <div>
+ <span>Test1</span>
+ <span>Test2</span>
+ <span>Test3</span>
+ </div>
+ </main>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/display-none.html b/testing/web-platform/tests/css/css-contain/container-queries/display-none.html
new file mode 100644
index 0000000000..8d07ec09dd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/display-none.html
@@ -0,0 +1,393 @@
+<!doctype html>
+<title>@container in display:none</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-size">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<script>
+ setup(() => assert_implements_container_queries());
+</script>
+<style>
+ .container {
+ container-type: size;
+ width: 30px;
+ height: 30px;
+ background: tomato;
+ }
+ .small {
+ width: 10px;
+ height: 10px;
+ }
+ .big {
+ width: 50px;
+ height: 50px;
+ background: skyblue;
+ }
+ .auto {
+ width: auto;
+ }
+ .none {
+ display: none;
+ }
+ .pseudo::before {
+ content: "foo";
+ }
+ .pseudo_none::before {
+ content: "foo";
+ display: none;
+ }
+
+ @container (width: 30px) {
+ .target { --x:30; }
+ }
+
+ @container (width: 50px) {
+ .target { --x:50; }
+ }
+
+ main {
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+</style>
+
+<main>
+ <!-- Target element is display:none -->
+ <div class="container">
+ <div>
+ <div>
+ <div class="target none" id=target1></div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target1);
+ assert_equals(s.getPropertyValue('--x'), '30');
+ }, 'getComputedStyle when element is display:none');
+ </script>
+
+ <!-- Parent is display:none -->
+ <div class="container">
+ <div>
+ <div class="none">
+ <div class="target" id=target2></div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target2);
+ assert_equals(s.getPropertyValue('--x'), '30');
+ }, 'getComputedStyle when parent is display:none');
+ </script>
+
+ <!-- Ancestor is display:none -->
+ <div class="container">
+ <div class="none">
+ <div>
+ <div class="target" id=target3></div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target3);
+ assert_equals(s.getPropertyValue('--x'), '30');
+ }, 'getComputedStyle when ancestor is display:none');
+ </script>
+
+ <!-- Container is display:none -->
+ <div class="container none">
+ <div>
+ <div>
+ <div class="target" id=target4></div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target4);
+ assert_equals(s.getPropertyValue('--x'), '');
+ }, 'getComputedStyle when container is display:none');
+ </script>
+
+ <!-- Target element is display:none in nested container -->
+ <div class="container big">
+ <div>
+ <div>
+ <div class="container">
+ <div>
+ <div>
+ <div class="target none" id=target5></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target5);
+ assert_equals(s.getPropertyValue('--x'), '30');
+ }, 'getComputedStyle when element in nested container is display:none');
+ </script>
+
+ <!-- Inner container is display:none -->
+ <div class="container big">
+ <div>
+ <div>
+ <div class="container none">
+ <div>
+ <div>
+ <div class="target" id=target6></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target6);
+ assert_equals(s.getPropertyValue('--x'), '');
+ }, 'getComputedStyle when inner container is display:none');
+ </script>
+
+ <!-- Intermediate ancestor is display:none -->
+ <div class="container big">
+ <div class="none">
+ <div>
+ <div class="container">
+ <div>
+ <div>
+ <div class="target" id=target7></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target7);
+ assert_equals(s.getPropertyValue('--x'), '');
+ }, 'getComputedStyle when intermediate ancestor is display:none');
+ </script>
+
+ <!-- Outer container is display:none -->
+ <div class="container big none">
+ <div>
+ <div>
+ <div class="container">
+ <div>
+ <div>
+ <div class="target" id=target8></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target8);
+ assert_equals(s.getPropertyValue('--x'), '');
+ }, 'getComputedStyle when outer container is display:none');
+ </script>
+
+ <!-- Nothing is display:none initially, but target becomes display:none -->
+ <div class="container">
+ <div>
+ <div>
+ <div class="target" id=target9></div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target9);
+ assert_equals(s.getPropertyValue('--x'), '30');
+ target9.classList.add('none');
+ assert_equals(s.getPropertyValue('--x'), '30');
+ }, 'getComputedStyle when element becomes display:none');
+ </script>
+
+ <!-- Nothing is display:none initially, but parent becomes display:none -->
+ <div class="container">
+ <div>
+ <div id=parent10>
+ <div class="target" id=target10></div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target10);
+ assert_equals(s.getPropertyValue('--x'), '30');
+ parent10.classList.add('none');
+ assert_equals(s.getPropertyValue('--x'), '30');
+ }, 'getComputedStyle when parent becomes display:none');
+ </script>
+
+ <!-- Nothing is display:none initially, but ancestor becomes display:none -->
+ <div class="container">
+ <div id=ancestor11>
+ <div>
+ <div class="target" id=target11></div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target11);
+ assert_equals(s.getPropertyValue('--x'), '30');
+ ancestor11.classList.add('none');
+ assert_equals(s.getPropertyValue('--x'), '30');
+ }, 'getComputedStyle when ancestor becomes display:none');
+ </script>
+
+ <!-- Nothing is display:none initially, but container becomes display:none -->
+ <div class="container" id=container12>
+ <div>
+ <div>
+ <div class="target" id=target12></div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target12);
+ assert_equals(s.getPropertyValue('--x'), '30');
+ container12.classList.add('none');
+ assert_equals(s.getPropertyValue('--x'), '');
+ }, 'getComputedStyle when container becomes display:none');
+ </script>
+
+ <!-- Intermediate container becomes display:none -->
+ <div class="container big">
+ <div>
+ <div>
+ <div class="container" id=container13>
+ <div>
+ <div>
+ <div class="target" id=target13></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target13);
+ assert_equals(s.getPropertyValue('--x'), '30');
+ container13.classList.add('none');
+ assert_equals(s.getPropertyValue('--x'), '');
+ }, 'getComputedStyle when intermediate container becomes display:none');
+ </script>
+
+ <!-- Pseudo-element is display:none -->
+ <div class="container">
+ <div>
+ <div>
+ <div class="target pseudo_none" id=target14></div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target14, '::before');
+ assert_equals(s.getPropertyValue('content'), '"foo"');
+ assert_equals(s.getPropertyValue('--x'), '30');
+ }, 'getComputedStyle when ::before is display:none');
+ </script>
+
+ <!-- Pseudo-element with display:none originating element -->
+ <div class="container">
+ <div>
+ <div>
+ <div class="target pseudo none" id=target15></div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target15, '::before');
+ assert_equals(s.getPropertyValue('content'), '"foo"');
+ assert_equals(s.getPropertyValue('--x'), '30');
+ }, 'getComputedStyle when originating element is display:none');
+ </script>
+
+ <!-- Pseudo-element with display:none ancestor -->
+ <div class="container">
+ <div class="none">
+ <div>
+ <div class="target pseudo" id=target16></div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target16, '::before');
+ assert_equals(s.getPropertyValue('content'), '"foo"');
+ assert_equals(s.getPropertyValue('--x'), '30');
+ }, 'getComputedStyle on ::before when ancestor element is display:none');
+ </script>
+
+ <!-- Pseudo-element with in display:none container -->
+ <div class="container none">
+ <div>
+ <div>
+ <div class="target pseudo" id=target17></div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ let s = getComputedStyle(target17, '::before');
+ assert_equals(s.getPropertyValue('content'), '"foo"');
+ assert_equals(s.getPropertyValue('--x'), '');
+ }, 'getComputedStyle on ::before when container is display:none');
+ </script>
+
+ <!-- Target in display:none with layout dirty outer element -->
+ <div class=small id="outer18">
+ <div class="container auto">
+ <div class="none">
+ <div>
+ <div class="target" id=target18></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ target18.offsetTop;
+ let s = getComputedStyle(target18);
+ assert_equals(s.getPropertyValue('--x'), '');
+
+ outer18.classList.remove('small');
+ outer18.classList.add('big');
+ assert_equals(s.getPropertyValue('--x'), '50');
+ }, 'getComputedStyle when in display:none with layout dirty outer element');
+ </script>
+
+ <!-- Intermediate container has forced style -->
+ <div class="container">
+ <div class="none">
+ <div id="inner19" class="container">
+ <div id="target19" class="target"></div>
+ </div>
+ </div>
+ </div>
+ <script>
+ test(function() {
+ getComputedStyle(inner19).getPropertyValue('--x');
+ let s = getComputedStyle(target19);
+ assert_equals(s.getPropertyValue('--x'), '');
+ }, 'getComputedStyle when display:none inner container has forced style');
+ </script>
+</main>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/fieldset-legend-change-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/fieldset-legend-change-ref.html
new file mode 100644
index 0000000000..b6e8dc6038
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/fieldset-legend-change-ref.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<p>Pass if the rendered legend below is "PASS"</p>
+<fieldset style="width:400px"><legend>PASS</legend></fieldset>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/fieldset-legend-change.html b/testing/web-platform/tests/css/css-contain/container-queries/fieldset-legend-change.html
new file mode 100644
index 0000000000..15b44a0e52
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/fieldset-legend-change.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<title>CSS Container Queries Test: inline-size query changes rendered legend in fieldset</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="match" href="fieldset-legend-change-ref.html">
+<p>Pass if the rendered legend below is "PASS"</p>
+<style>
+ fieldset {
+ width: 200px;
+ container-type: inline-size;
+ }
+ .wide { width: 400px; }
+
+ @container (min-width: 300px) {
+ #fail {
+ display: none;
+ }
+ }
+</style>
+<fieldset id="fieldset">
+ <legend id="fail">FAIL</legend>
+ <legend>PASS</legend>
+</fieldset>
+<script>
+ fieldset.offsetTop;
+ fieldset.className = "wide";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/font-relative-calc-dynamic.html b/testing/web-platform/tests/css/css-contain/container-queries/font-relative-calc-dynamic.html
new file mode 100644
index 0000000000..54f01d45a3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/font-relative-calc-dynamic.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<title>CSS Container Queries Test: font-relative calc - dynamic</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ body { font-size: 10px; }
+ body.larger { font-size: 20px; }
+ #container {
+ container-type: inline-size;
+ width: 100px;
+ color: red;
+ }
+ #intermediate {
+ font-size: 8px;
+ }
+ @container (width: calc(1em + 80px)) {
+ #target { color: green; }
+ }
+</style>
+<div id="container">
+ <div id=intermediate>
+ <div id="target"></div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(target).color, 'rgb(255, 0, 0)');
+ document.body.className = 'larger';
+ assert_equals(getComputedStyle(target).color, 'rgb(0, 128, 0)');
+ }, 'font-relative calc() is responsive to container font-size changes');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/font-relative-units-dynamic.html b/testing/web-platform/tests/css/css-contain/container-queries/font-relative-units-dynamic.html
new file mode 100644
index 0000000000..9dfaceeed6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/font-relative-units-dynamic.html
@@ -0,0 +1,328 @@
+<!doctype html>
+<title>CSS Container Queries Test: font-relative units - dynamic</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<script>
+
+setup(() => assert_implements_container_queries());
+
+// Inflate a <template> subtree into #main, run the test function,
+// then clean up.
+function test_template(template_element, test_fn, description) {
+ test((t) => {
+ assert_equals(template_element.tagName, "TEMPLATE");
+ t.add_cleanup(() => main.replaceChildren());
+ main.append(template_element.content.cloneNode(true));
+ test_fn(t);
+ }, description);
+}
+
+const green = "rgb(0, 128, 0)";
+const red = "rgb(255, 0, 0)";
+
+</script>
+
+<style>
+ main {
+ color: red;
+ }
+ #container {
+ container-type: inline-size;
+ width: 100px;
+ }
+ #container > div {
+ font-size: 16px;
+ }
+</style>
+
+<main id=main>
+</main>
+
+<template>
+ <style>
+ main { font-size: 10px; }
+ main.larger { font-size: 20px; }
+ @container (width: 5em) {
+ #test { color: green }
+ }
+ </style>
+ <div id="container">
+ <div>
+ <div id="test"></div>
+ </div>
+ </div>
+</template>
+<script>
+test_template(document.currentScript.previousElementSibling, (t) => {
+ t.add_cleanup(() => main.classList.remove("larger"));
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, red);
+ main.classList.add("larger");
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, green);
+}, 'em units respond to changes');
+</script>
+
+<template>
+ <style>
+ :root { font-size: 10px; }
+ :root.larger { font-size: 50px; }
+ @container (width: 2rem) {
+ #test { color: green }
+ }
+ </style>
+ <div id="container">
+ <div>
+ <div id="test"></div>
+ </div>
+ </div>
+</template>
+<script>
+test_template(document.currentScript.previousElementSibling, (t) => {
+ t.add_cleanup(() => document.documentElement.classList.remove("larger"));
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, red);
+ document.documentElement.classList.add("larger");
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, green);
+}, 'rem units respond to changes');
+</script>
+
+<template>
+ <style>
+ main { font-size: 10px; }
+ main.larger { font-size: 20px; }
+ @container (width <= 15ex) {
+ #test { color: green }
+ }
+ </style>
+ <div id="container">
+ <div>
+ <div id="test"></div>
+ </div>
+ </div>
+</template>
+<script>
+test_template(document.currentScript.previousElementSibling, (t) => {
+ t.add_cleanup(() => main.classList.remove("larger"));
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, red);
+ main.classList.add("larger");
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, green);
+}, 'ex units respond to changes');
+</script>
+
+<template>
+ <style>
+ :root { font-size: 10px; }
+ :root.larger { font-size: 20px; }
+ @container (width <= 12rex) {
+ #test { color: green }
+ }
+ </style>
+ <div id="container">
+ <div>
+ <div id="test"></div>
+ </div>
+ </div>
+</template>
+<script>
+test_template(document.currentScript.previousElementSibling, (t) => {
+ t.add_cleanup(() => document.documentElement.classList.remove("larger"));
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, red);
+ document.documentElement.classList.add("larger");
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, green);
+}, 'rex units respond to changes');
+</script>
+
+<template>
+ <style>
+ main { font-size: 10px; }
+ main.larger { font-size: 20px; }
+ @container (width <= 15ch) {
+ #test { color: green }
+ }
+ </style>
+ <div id="container">
+ <div>
+ <div id="test"></div>
+ </div>
+ </div>
+</template>
+<script>
+test_template(document.currentScript.previousElementSibling, (t) => {
+ t.add_cleanup(() => main.classList.remove("larger"));
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, red);
+ main.classList.add("larger");
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, green);
+}, 'ch units respond to changes');
+</script>
+
+<template>
+ <style>
+ @import url("/fonts/ahem.css");
+ main { font-family: 'Ahem'; font-size: 10px; }
+ main.larger { font-size: 20px; }
+ @container (width <= 7cap) {
+ #test { color: green }
+ }
+ </style>
+ <div id="container">
+ <div>
+ <div id="test"></div>
+ </div>
+ </div>
+</template>
+<script>
+test_template(document.currentScript.previousElementSibling, (t) => {
+ t.add_cleanup(() => main.classList.remove("larger"));
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, red);
+ main.classList.add("larger");
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, green);
+}, 'cap units respond to changes');
+</script>
+
+<template>
+ <style>
+ :root { font-size: 10px; }
+ :root.larger { font-size: 20px; }
+ @container (width <= 15rch) {
+ #test { color: green }
+ }
+ </style>
+ <div id="container">
+ <div>
+ <div id="test"></div>
+ </div>
+ </div>
+</template>
+<script>
+test_template(document.currentScript.previousElementSibling, (t) => {
+ t.add_cleanup(() => document.documentElement.classList.remove("larger"));
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, red);
+ document.documentElement.classList.add("larger");
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, green);
+}, 'rch units respond to changes');
+</script>
+
+<template>
+ <style>
+ main {
+ font-size: 10px;
+ line-height: 5;
+ }
+ main.larger { font-size: 20px; }
+ @container (width <= 1lh) {
+ #test { color: green }
+ }
+ </style>
+ <div id="container">
+ <div>
+ <div id="test"></div>
+ </div>
+ </div>
+</template>
+<script>
+test_template(document.currentScript.previousElementSibling, (t) => {
+ t.add_cleanup(() => main.classList.remove("larger"));
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, red);
+ main.classList.add("larger");
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, green);
+}, 'lh units respond to changes');
+</script>
+
+<template>
+ <style>
+ :root {
+ font-size: 10px;
+ line-height: 5;
+ }
+ :root.larger {
+ font-size: 20px;
+ }
+ @container (width <= 1rlh) {
+ #test { color: green }
+ }
+ </style>
+ <div id="container">
+ <div>
+ <div id="test"></div>
+ </div>
+ </div>
+</template>
+<script>
+test_template(document.currentScript.previousElementSibling, (t) => {
+ t.add_cleanup(() => document.documentElement.classList.remove("larger"));
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, red);
+ document.documentElement.classList.add("larger");
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, green);
+}, 'rlh units respond to changes');
+</script>
+
+<template>
+ <style>
+ main { font-size: 10px; }
+ main.larger { font-size: 20px; }
+ @container (width <= 8ic) {
+ #test { color: green }
+ }
+ </style>
+ <div id="container">
+ <div>
+ <div id="test"></div>
+ </div>
+ </div>
+</template>
+<script>
+test_template(document.currentScript.previousElementSibling, (t) => {
+ t.add_cleanup(() => main.classList.remove("larger"));
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, red);
+ main.classList.add("larger");
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, green);
+}, 'ic units respond to changes');
+</script>
+
+
+<template>
+ <style>
+ :root { font-size: 10px; }
+ :root.larger { font-size: 20px; }
+ @container (width <= 8ric) {
+ #test { color: green }
+ }
+ </style>
+ <div id="container">
+ <div>
+ <div id="test"></div>
+ </div>
+ </div>
+</template>
+<script>
+test_template(document.currentScript.previousElementSibling, (t) => {
+ t.add_cleanup(() => document.documentElement.classList.remove("larger"));
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, red);
+ document.documentElement.classList.add("larger");
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, green);
+}, 'ric units respond to changes');
+</script>
+
+<template>
+ <style>
+ @import url("/fonts/ahem.css");
+ :root { font-family: 'Ahem'; font-size: 10px; }
+ :root.larger { font-size: 20px; }
+ @container (width <= 7rcap) {
+ #test { color: green }
+ }
+ </style>
+ <div id="container">
+ <div style="font-family: monospace;">
+ <div id="test"></div>
+ </div>
+ </div>
+</template>
+<script>
+test_template(document.currentScript.previousElementSibling, (t) => {
+ t.add_cleanup(() => document.documentElement.classList.remove("larger"));
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, red);
+ document.documentElement.classList.add("larger");
+ assert_equals(getComputedStyle(main.querySelector("#test")).color, green);
+}, 'rcap units respond to changes');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/font-relative-units.html b/testing/web-platform/tests/css/css-contain/container-queries/font-relative-units.html
new file mode 100644
index 0000000000..ba4a60dda2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/font-relative-units.html
@@ -0,0 +1,118 @@
+<!doctype html>
+<title>CSS Container Queries Test: font-relative units</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ @import url("/fonts/ahem.css");
+ :root { font-family: 'Ahem'; font-size: 10px; line-height: 10px; }
+ #em_container {
+ container-type: inline-size;
+ width: 100px;
+ font-size: 100px;
+ }
+ #ex_container {
+ container-type: inline-size;
+ font-size: 50px;
+ width: 10ex;
+ height: 50rex;
+ }
+ #cap_container {
+ container-type: inline-size;
+ font-size: 50px;
+ width: 10cap;
+ }
+ #ch_container {
+ container-type: inline-size;
+ font-size: 50px;
+ width: 10ch;
+ }
+ #ic_container {
+ container-type: inline-size;
+ font-size: 50px;
+ width: 10ic;
+ }
+ #lh_container {
+ container-type: inline-size;
+ line-height: 50px;
+ width: 10lh;
+ }
+ @container (width: 1em) {
+ #em_test { color: green }
+ }
+ @container (width: 10rem) {
+ #rem_test { color: green }
+ }
+ @container (width: 10cap) {
+ #cap_test { color: green }
+ }
+ @container (width: 50rcap) {
+ #rcap_test { color: green }
+ }
+ @container (width: 10ex) {
+ #ex_test { color: green }
+ }
+ @container (width: 50rex) {
+ #rex_test { color: green }
+ }
+ @container (width: 10ch) {
+ #ch_test { color: green }
+ }
+ @container (width: 50rch) {
+ #rch_test { color: green }
+ }
+ @container (width: 10ic) {
+ #ic_test { color: green }
+ }
+ @container (width: 50ric) {
+ #ric_test { color: green }
+ }
+ @container (width: 10lh) {
+ #lh_test { color: green }
+ }
+ @container (width: 50rlh) {
+ #rlh_test { color: green }
+ }
+</style>
+<div id="em_container">
+ <div id="em_test"></div>
+ <div id="rem_test"></div>
+</div>
+<div id="cap_container">
+ <div id="cap_test"></div>
+ <div id="rcap_test"></div>
+</div>
+<div id="ex_container">
+ <div id="ex_test"></div>
+ <div id="rex_test"></div>
+</div>
+<div id="ch_container">
+ <div id="ch_test"></div>
+ <div id="rch_test"></div>
+</div>
+<div id="ic_container">
+ <div id="ic_test"></div>
+ <div id="ric_test"></div>
+</div>
+<div id="lh_container">
+ <div id="lh_test"></div>
+ <div id="rlh_test"></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const green = "rgb(0, 128, 0)";
+ test(() => assert_equals(getComputedStyle(em_test).color, green), "em relative inline-size");
+ test(() => assert_equals(getComputedStyle(rem_test).color, green), "rem relative inline-size");
+ test(() => assert_equals(getComputedStyle(ex_test).color, green), "ex relative inline-size");
+ test(() => assert_equals(getComputedStyle(rex_test).color, green), "rex relative inline-size");
+ test(() => assert_equals(getComputedStyle(ch_test).color, green), "ch relative inline-size");
+ test(() => assert_equals(getComputedStyle(rch_test).color, green), "rch relative inline-size");
+ test(() => assert_equals(getComputedStyle(ic_test).color, green), "ic relative inline-size");
+ test(() => assert_equals(getComputedStyle(ric_test).color, green), "ric relative inline-size");
+ test(() => assert_equals(getComputedStyle(lh_test).color, green), "lh relative inline-size");
+ test(() => assert_equals(getComputedStyle(rlh_test).color, green), "rlh relative inline-size");
+ test(() => assert_equals(getComputedStyle(cap_test).color, green), "cap relative inline-size");
+ test(() => assert_equals(getComputedStyle(rcap_test).color, green), "rcap relative inline-size");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/fragmented-container-001.html b/testing/web-platform/tests/css/css-contain/container-queries/fragmented-container-001.html
new file mode 100644
index 0000000000..886f179054
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/fragmented-container-001.html
@@ -0,0 +1,48 @@
+<!doctype html>
+<title>CSS Container Queries Test: Query fragmented inline-size container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #multicol {
+ width: 400px;
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ height: 100px;
+ }
+ #float {
+ float: left;
+ width: 100px;
+ height: 50px;
+ }
+ #container {
+ container-type: inline-size;
+ display: flow-root;
+ height: 200px;
+ }
+ #first-child {
+ break-after: column;
+ }
+ @container (width = 100px) {
+ #first-child { color: green; }
+ #second-child { color: green; }
+ }
+</style>
+<div id="multicol">
+ <div id="float"></div>
+ <div id="container">
+ <div id="first-child"></div>
+ <div id="second-child"></div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ const green = "rgb(0, 128, 0)";
+ assert_equals(getComputedStyle(document.querySelector("#first-child")).color, green);
+ assert_equals(getComputedStyle(document.querySelector("#second-child")).color, green);
+ }, "Children of fragmented inline-size container should match inline-size of first fragment");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/get-animations.html b/testing/web-platform/tests/css/css-contain/container-queries/get-animations.html
new file mode 100644
index 0000000000..dca41c6ada
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/get-animations.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<title>getAnimations depending on container query</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ container-type: inline-size;
+ width: 100px;
+ }
+ #div { color: red; }
+ @keyframes test {
+ from { color: green; }
+ to { color: green; }
+ }
+ @container (min-width: 200px) {
+ #div { animation: test 1s linear forwards; }
+ }
+</style>
+<div id=container>
+ <div id=div>Green</div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(div).color, 'rgb(255, 0, 0)');
+
+ container.style = 'width:300px';
+ assert_equals(div.getAnimations().length, 1);
+ assert_equals(getComputedStyle(div).color, 'rgb(0, 128, 0)');
+ }, 'Calling getAnimations updates layout of parent frame if needed');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/grid-container.html b/testing/web-platform/tests/css/css-contain/container-queries/grid-container.html
new file mode 100644
index 0000000000..60278e09c6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/grid-container.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<title>CSS Container Queries Test: Grid container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #grid {
+ display: grid;
+ container-type: inline-size;
+ width: 400px;
+ grid-template-columns: 1fr 1fr;
+ }
+ @container (width = 400px) {
+ #grid div { color: green }
+ }
+</style>
+<div id="grid">
+ <div id="item1"></div>
+ <div id="item2"></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(item1).color, "rgb(0, 128, 0)");
+ assert_equals(getComputedStyle(item2).color, "rgb(0, 128, 0)");
+ }, "Check that grid items can query grid container");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/grid-item-container.html b/testing/web-platform/tests/css/css-contain/container-queries/grid-item-container.html
new file mode 100644
index 0000000000..f1c66efc26
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/grid-item-container.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<title>CSS Container Queries Test: Grid item container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #grid {
+ width: 300px;
+ display: grid;
+ grid-template-columns: 2fr 1fr;
+ }
+ .item {
+ container-type: inline-size;
+ }
+ @container (width > 50px) {
+ .item div { color: lime; }
+ }
+ @container (width > 150px) {
+ .item div { color: green; }
+ }
+</style>
+<div id="grid">
+ <div class="item">
+ <div id="target1"></div>
+ </div>
+ <div class="item">
+ <div id="target2"></div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(target1).color, "rgb(0, 128, 0)", "First item container should be 200px wide");
+ assert_equals(getComputedStyle(target2).color, "rgb(0, 255, 0)", "Second item container should be 100px wide");
+ }, "Check that children can query grid item containers");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/idlharness.html b/testing/web-platform/tests/css/css-contain/container-queries/idlharness.html
new file mode 100644
index 0000000000..ac1a677bb9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/idlharness.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<title>CSS Container Queries: CSSContainer Rule IDL tests</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/WebIDLParser.js"></script>
+<script src="/resources/idlharness.js"></script>
+<!-- used to provide objects -->
+<style>
+ @container cont (width = 100px) {
+ @container (inline-size > 200em) {
+ #id { color: lime }
+ }
+ #id { color: green }
+ }
+</style>
+<script>
+ idl_test(
+ ['css-contain-3'],
+ ['css-conditional', 'cssom', 'dom'],
+ idl_array => {
+ idl_array.add_objects({
+ CSSContainerRule: ['sheet.cssRules[0]',
+ 'sheet.cssRules[0].cssRules[0]'],
+ });
+ self.sheet = document.styleSheets[0];
+ }
+ );
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/iframe-in-container-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/iframe-in-container-invalidation.html
new file mode 100644
index 0000000000..f43d1ce789
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/iframe-in-container-invalidation.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<title>@container-dependent elements respond to size changes of an @container-dependent iframe</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ container-type: size;
+ width: 200px;
+ height: 200px;
+ }
+ iframe {
+ width: 200px;
+ height: 40px;
+ }
+ @container (width > 300px) {
+ iframe { width: 400px; }
+ }
+</style>
+<div id=container>
+ <iframe id=iframe srcdoc="
+ <style>
+ div#container {
+ container-type: size;
+ height: 20px;
+ }
+ div#child { color: red; }
+ @container (width > 300px) {
+ div#child { color: green; }
+ }
+ </style>
+ <div id=container>
+ <div id=child>Test</div>
+ </div>
+ "></iframe>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ function waitForLoad(w) {
+ return new Promise(resolve => w.addEventListener('load', resolve));
+ }
+
+ promise_test(async () => {
+ await waitForLoad(window);
+ let inner_div = iframe.contentDocument.querySelector('div#child');
+ assert_equals(getComputedStyle(inner_div).color, 'rgb(255, 0, 0)');
+
+ // Changing the size of the outer container changes the size of the iframe,
+ // which in turn should change the size of the inner container (inside that
+ // iframe).
+ container.style.width = '400px';
+ container.style.setProperty('--x', 'x'); // crbug.com/1312940
+
+ assert_equals(getComputedStyle(inner_div).color, 'rgb(0, 128, 0)');
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/iframe-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/iframe-invalidation.html
new file mode 100644
index 0000000000..51f2be9cfa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/iframe-invalidation.html
@@ -0,0 +1,43 @@
+<!doctype html>
+<title>@container-dependent elements respond to iframe size changes</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ iframe {
+ width: 200px;
+ height: 40px;
+ }
+</style>
+<iframe id=iframe srcdoc="
+ <style>
+ div#container {
+ container-type: size;
+ height: 20px;
+ }
+ div#child { color: red; }
+ @container (min-width: 300px) {
+ div#child { color: green; }
+ }
+ </style>
+ <div id=container>
+ <div id=child>Test</div>
+ </div>
+"></iframe>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ function waitForLoad(w) {
+ return new Promise(resolve => w.addEventListener('load', resolve));
+ }
+
+ promise_test(async () => {
+ await waitForLoad(window);
+ let inner_div = iframe.contentDocument.querySelector('div#child');
+ assert_equals(getComputedStyle(inner_div).color, 'rgb(255, 0, 0)');
+
+ iframe.style = 'width:400px';
+ assert_equals(getComputedStyle(inner_div).color, 'rgb(0, 128, 0)');
+ })
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/ineligible-containment.html b/testing/web-platform/tests/css/css-contain/container-queries/ineligible-containment.html
new file mode 100644
index 0000000000..36ce68d864
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/ineligible-containment.html
@@ -0,0 +1,51 @@
+<!doctype html>
+<title>Containers ineligible for containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-size">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #outer, #inner1, #inner2 {
+ width: 200px;
+ container-type: inline-size;
+ }
+ #inner1 {
+ display: table;
+ }
+ p {
+ color: green;
+ }
+ @container (min-width: 1px) {
+ p { color: red; }
+ }
+</style>
+<div id=outer>
+ <div id=inner1>
+ <p id=p1>Test1</p>
+ </div>
+ <div id=inner2>
+ <p id=p2>Test1</p>
+ </div>
+</main>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(function(t) {
+ // #inner1 is the container, but it does not satisfy the containment
+ // requirements, hence the query should fail.
+ assert_equals(getComputedStyle(p1).color, 'rgb(0, 128, 0)');
+ }, 'Container ineligible for containment');
+
+ test(function(t) {
+ t.add_cleanup(() => { inner2.style = ''; });
+
+ assert_equals(getComputedStyle(p2).color, 'rgb(255, 0, 0)');
+
+ inner2.style = 'display:table';
+
+ // #inner2 is still the container, but it no longer satisfies the
+ // containment requirements.
+ assert_equals(getComputedStyle(p2).color, 'rgb(0, 128, 0)');
+ }, 'Changing containment eligibility invalidates style');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/inheritance-from-container.html b/testing/web-platform/tests/css/css-contain/container-queries/inheritance-from-container.html
new file mode 100644
index 0000000000..97dfff2fd0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/inheritance-from-container.html
@@ -0,0 +1,43 @@
+<!doctype html>
+<title>Containers and inheritance</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+#outer {
+ visibility: hidden;
+}
+#outer.visible {
+ visibility: visible;
+}
+#container {
+ container-type: inline-size;
+}
+#container.visible {
+ visibility: visible;
+}
+</style>
+<div id=outer><div id=container><span id=inner>PASS</span></div></div>
+<script>
+setup(() => assert_implements_container_queries());
+
+test((t) => {
+ assert_equals(getComputedStyle(inner).visibility, "hidden");
+}, "Initial state");
+
+test((t) => {
+ outer.classList.add("visible");
+ assert_equals(getComputedStyle(inner).visibility, "visible");
+}, "Test that visibility inherits via container after mutation");
+
+test((t) => {
+ outer.classList.remove("visible");
+ assert_equals(getComputedStyle(inner).visibility, "hidden");
+}, "Return to initial state");
+
+test((t) => {
+ container.classList.add("visible");
+ assert_equals(getComputedStyle(inner).visibility, "visible");
+}, "Test that visibility inherits from container after mutation");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/inline-size-and-min-width.html b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-and-min-width.html
new file mode 100644
index 0000000000..8ddcbc614c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-and-min-width.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<title>CSS Container Queries Test: query of inline-size container is affected by min-width property</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ container-type: inline-size;
+ min-width: 200px;
+ width: fit-content;
+ }
+ @container (min-width: 200px) {
+ #child { color: green }
+ }
+</style>
+<div id="container">
+ <div id="child">Green</div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(child).color, "rgb(0, 128, 0)");
+ }, "min-width of inline-size container affects container size");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/inline-size-bfc-floats-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-bfc-floats-ref.html
new file mode 100644
index 0000000000..ecd72b7516
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-bfc-floats-ref.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<p>You should see the text "no red" to the left of the third float and no red.</p>
+<div style="width:400px">
+ <div style="float:right;width:200px;height:150px;background:blue"></div>
+ <div style="float:left;width:250px;height:100px;background:blue"></div>
+ <div style="float:right;width:300px;height:100px;background:blue"></div>
+ <div style="height:200px;display:flow-root">No red</div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/inline-size-bfc-floats.html b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-bfc-floats.html
new file mode 100644
index 0000000000..88b81c6759
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-bfc-floats.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<title>CSS Container Queries Test: inline-size constrained by floats - layout moving forwards</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#containment-inline-size">
+<link rel="match" href="inline-size-bfc-floats-ref.html">
+<style>
+ .float { float: left; background-color: blue; }
+ .right { float: right; }
+
+ #outer { width: 400px; }
+ #float1 { width: 200px; height: 150px; }
+ #float2 { width: 250px; height: 100px; }
+ #float3 { width: 300px; height: 100px; }
+
+ #container { container-type: inline-size; }
+
+ /* Initially, text + 200px of red content (#content1 + #content2) is too tall
+ to make #container fit by #float1 */
+ .content { height: 100px; background-color: red; }
+
+ /* Trying to fit #container beside #float2 causes the width to remove
+ #content1. text + 100px of red content (#content2) is too tall to fit
+ beside #float2. It would at this point fit beside #float1, but that would
+ cause the width to increase again, and the spec says layout always moves
+ forward. */
+ @container (width < 200px) {
+ #content1 { display: none }
+ }
+
+ /* Trying to fit #container beside #float3 causes the rest of the red content
+ (#content2) to disappear. */
+ @container (width < 150px) {
+ #content2 { display: none }
+ }
+</style>
+<p>You should see the text "no red" to the left of the third float and no red.</p>
+<div id="outer">
+ <div id="float1" class="float right"></div>
+ <div id="float2" class="float left"></div>
+ <div id="float3" class="float right"></div>
+
+ <div id="container">
+ No red
+ <div id="content1" class="content"></div>
+ <div id="content2" class="content"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/inline-size-containment-vertical-rl.html b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-containment-vertical-rl.html
new file mode 100644
index 0000000000..38c88f2df7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-containment-vertical-rl.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<title>CSS Container Queries Test: query of inline-size container in vertical-rl</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<style>
+ #ancestry { writing-mode: vertical-rl; }
+ #keg { container-type: inline-size; }
+ @container (max-height: 200px) {
+ #target { width: 400px; }
+ }
+ @container (min-height: 400px) {
+ #target { width: 20px; }
+ }
+</style>
+<div id="ancestry">
+ <div id="keg">
+ <div id="target">
+ <div style="width:50px;"></div>
+ </div>
+ </div>
+</div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(()=> {
+ ancestry.style.height = "100px";
+ assert_equals(keg.offsetWidth, 400);
+
+ ancestry.style.height = "300px";
+ assert_equals(keg.offsetWidth, 50);
+
+ ancestry.style.height = "500px";
+ assert_equals(keg.offsetWidth, 20);
+ }, "inline-size containment only");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/inline-size-containment.html b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-containment.html
new file mode 100644
index 0000000000..d519322bd2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/inline-size-containment.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<title>CSS Container Queries Test: query of inline-size container is affected by min-width property</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<style>
+ #keg { container-type: inline-size; }
+ @container (max-width: 200px) {
+ #target { height: 400px; }
+ }
+ @container (min-width: 400px) {
+ #target { height: 20px; }
+ }
+</style>
+<div id="ancestry">
+ <div id="keg">
+ <div id="target">
+ <div style="height:50px;"></div>
+ </div>
+ </div>
+</div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(()=> {
+ ancestry.style.width = "100px";
+ assert_equals(keg.offsetHeight, 400);
+
+ ancestry.style.width = "300px";
+ assert_equals(keg.offsetHeight, 50);
+
+ ancestry.style.width = "500px";
+ assert_equals(keg.offsetHeight, 20);
+ }, "inline-size containment only");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/inner-first-line-non-matching-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/inner-first-line-non-matching-ref.html
new file mode 100644
index 0000000000..99e9c334bf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/inner-first-line-non-matching-ref.html
@@ -0,0 +1,3 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<div style="color:green">This text should be green.</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/inner-first-line-non-matching.html b/testing/web-platform/tests/css/css-contain/container-queries/inner-first-line-non-matching.html
new file mode 100644
index 0000000000..5f39124e51
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/inner-first-line-non-matching.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>CSS Container Queries Test: Non-matching ::first-line in @container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<link rel="match" href="inner-first-line-non-matching-ref.html">
+<style>
+ #outer::first-line { color: green }
+ @container (width > 99999px) {
+ #inner::first-line { color: red }
+ }
+</style>
+<div id="outer">
+ <div id="inner">This text should be green.</div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/layout-dependent-focus.html b/testing/web-platform/tests/css/css-contain/container-queries/layout-dependent-focus.html
new file mode 100644
index 0000000000..a16370ac56
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/layout-dependent-focus.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<title>CSS Container Queries: Input losing focus as a result of a size query</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ container-type: inline-size;
+ width: 200px;
+ }
+ #container.narrow {
+ width: 100px;
+ }
+ @container (width = 100px) {
+ #inner.hide { visibility: hidden; }
+ }
+</style>
+<div id="outer">
+ <div id="container">
+ <input type="text" id="inner">
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ let hide_test = async_test("Verify that onblur is called on hidden input");
+ onload = () => {
+ inner.addEventListener("blur", () => hide_test.done());
+ inner.focus();
+ inner.className = "hide";
+ container.className = "narrow";
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ hide_test.step(() => assert_unreached("Event listener for 'blur' not called"));
+ });
+ });
+ };
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/multicol-container-001.html b/testing/web-platform/tests/css/css-contain/container-queries/multicol-container-001.html
new file mode 100644
index 0000000000..3032170ac6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/multicol-container-001.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<title>CSS Container Queries Test: Query multicol container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #multicol {
+ container-type: inline-size;
+ width: 400px;
+ column-count: 2;
+ column-gap: 0;
+ }
+ @container (width = 400px) {
+ #first-child { color: green; }
+ #second-child { color: green; }
+ }
+</style>
+<div id="multicol">
+ <div id="first-child">First</div>
+ <div id="second-child">Second</div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ const green = "rgb(0, 128, 0)";
+ assert_equals(getComputedStyle(document.querySelector("#first-child")).color, green);
+ assert_equals(getComputedStyle(document.querySelector("#second-child")).color, green);
+ }, "Children of multicol inline-size container should match inline-size of the container");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/multicol-inside-container.html b/testing/web-platform/tests/css/css-contain/container-queries/multicol-inside-container.html
new file mode 100644
index 0000000000..9fc8393a51
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/multicol-inside-container.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<title>CSS Container Queries Test: Multicol inside size container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
+<style>
+ #container {
+ container-type: size;
+ width: 200px;
+ height: 100px;
+ }
+ @container (width <= 200px) {
+ #multicol {
+ column-count: 2;
+ column-gap: 0;
+ }
+ }
+ #green {
+ display: inline-block;
+ width: 100%;
+ height: 100px;
+ background-color: green;
+ vertical-align: bottom;
+ }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id="container">
+ <div id="multicol"><div id="green"></div></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/nested-query-containers.html b/testing/web-platform/tests/css/css-contain/container-queries/nested-query-containers.html
new file mode 100644
index 0000000000..83cc3c2fec
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/nested-query-containers.html
@@ -0,0 +1,125 @@
+<!DOCTYPE html>
+<title>Nested query containers affecting each other</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-size">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ body > section {
+ contain: strict;
+ width: 500px;
+ }
+</style>
+<body>
+<script>
+promise_setup(() => {
+ assert_implements_container_queries();
+ return new Promise(resolve => {
+ addEventListener("load", () => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ document.body.className = "run";
+ resolve();
+ });
+ });
+ }, {once: true});
+ });
+});
+
+function booleanTuples(n) {
+ const tuple = new Array(n);
+ function* recursion(i) {
+ if (i == n) {
+ yield tuple.slice();
+ return;
+ }
+ tuple[i] = false;
+ yield* recursion(i + 1);
+ tuple[i] = true;
+ yield* recursion(i + 1);
+ }
+ return recursion(0);
+}
+
+// The following display values evaluate container queries to unknown.
+const testCases = [
+ {
+ display: "inline",
+ expected: {
+ width: depth => depth % 2 ? 0 : 500 - depth,
+ height: depth => 0,
+ },
+ },
+ {
+ display: "contents",
+ expected: {
+ width: depth => depth % 2 ? 0 : 500 - depth,
+ height: depth => 0,
+ },
+ },
+ {
+ display: "table-cell",
+ expected: {
+ width: depth => depth % 2 ? 2 : 0,
+ height: depth => depth % 2 ? 2 : 0,
+ },
+ },
+ {
+ display: "table",
+ expected: {
+ width: depth => depth % 2 ? 4 : 0,
+ height: depth => depth % 2 ? 4 : 0,
+ },
+ },
+];
+
+let testNum = 1;
+for (let testCase of testCases) {
+ for (let tuple of booleanTuples(3)) {
+ const section = document.createElement("section");
+ const id = "test" + testNum;
+ section.id = id;
+ const style = document.createElement("style");
+ style.textContent = `
+ :where(body${tuple[0] ? ".run" : ""}) > #${id} {
+ container-type: size;
+ container-name: name;
+ }
+ :where(body${tuple[1] ? ".run" : ""}) > #${id} div {
+ container-type: size;
+ container-name: name;
+ border: solid;
+ border-width: 1px;
+ }
+ @container name (width >= 0) {
+ :where(body${tuple[2] ? ".run" : ""}) > #${id} div {
+ display: ${testCase.display};
+ border-style: dotted;
+ }
+ }
+ `;
+ section.appendChild(style);
+ section.insertAdjacentHTML(
+ "beforeend",
+ "<div><div><div><div><div><div></div></div></div></div></div></div>"
+ );
+ document.body.appendChild(section);
+ promise_test(async function() {
+ let div = section.querySelector("div");
+ let depth = 1;
+ while (div) {
+ const cs = getComputedStyle(div);
+ assert_equals(cs.display, depth % 2 ? testCase.display : "block");
+ assert_equals(cs.borderStyle, depth % 2 ? "dotted" : "solid", "borderStyle");
+ assert_equals(div.clientWidth, testCase.expected.width(depth), "clientWidth");
+ assert_equals(div.clientHeight, testCase.expected.height(depth), "clientHeight");
+ div = div.firstElementChild;
+ depth += 1;
+ }
+ }, id + " - " + testCase.display + " - 0b" + tuple.map(Number).join(""));
+ testNum += 1;
+ }
+}
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/nested-size-style-container-invalidation.html b/testing/web-platform/tests/css/css-contain/container-queries/nested-size-style-container-invalidation.html
new file mode 100644
index 0000000000..8d04bf589a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/nested-size-style-container-invalidation.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<title>Nested size/style @container-dependent elements respond to container size changes</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ container-type: size;
+ width: 1000px;
+ }
+ #container.narrow {
+ width: 600px;
+ }
+ #target {
+ color: red;
+ }
+ @container (width < 800px) {
+ @container style(--foo: bar) {
+ #target { color: green; }
+ }
+ }
+</style>
+<div id="container">
+ <div style="--foo: bar">
+ <div id="target">Green?</div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(target).color, "rgb(255, 0, 0)");
+ }, "Initially red");
+
+ test(() => {
+ container.className = "narrow";
+ assert_equals(getComputedStyle(target).color, "rgb(0, 128, 0)");
+ }, "Green after reducing width");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/never-match-container.html b/testing/web-platform/tests/css/css-contain/container-queries/never-match-container.html
new file mode 100644
index 0000000000..9d5ff6d227
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/never-match-container.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<title>CSS Container Queries Test: @container querying size of elements without layout containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<script>
+ setup(() => assert_implements_container_queries());
+</script>
+<style>
+ #outer-container {
+ width: 100px;
+ container-type: inline-size;
+ }
+ #container-inline, #svg-container {
+ width: 100px;
+ container-type: inline-size;
+ }
+ @container (width >= 0px) {
+ #inner { color: red; }
+ #svg-inner { fill: red; }
+ }
+</style>
+<div id="outer-container">
+ <span id="container-inline">
+ <span id="inner">Not red</span>
+ </span>
+ <svg>
+ <g id="svg-container">
+ <text x="0" y="20" id="svg-inner">Not red</text>
+ </g>
+ </svg>
+</div>
+<script>
+ const red = "rgb(255, 0, 0)";
+
+ test(() => {
+ assert_not_equals(getComputedStyle(inner).color, red);
+ }, "Size @container query against inline box never matches");
+
+ test(() => {
+ assert_not_equals(getComputedStyle(document.querySelector("#svg-inner")).fill, red);
+ }, "Size @container query against svg element never matches");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/orthogonal-wm-container-query.html b/testing/web-platform/tests/css/css-contain/container-queries/orthogonal-wm-container-query.html
new file mode 100644
index 0000000000..1ad52bf499
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/orthogonal-wm-container-query.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<title>CSS Container Queries Test: Orthogonal writing-mode change in @container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+ #container {
+ container-type: size;
+ width: 50vw;
+ height: 50vh;
+ }
+ #orthogonal {
+ font: 50px/1 Ahem;
+ }
+ @container (max-width: 100px) {
+ #orthogonal {
+ writing-mode: vertical-lr;
+ }
+ }
+</style>
+<div id="container">
+ <div id="orthogonal">XX</div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(orthogonal.offsetWidth, container.offsetWidth);
+ }, "Initial non-orthogonal width");
+
+ test(() => {
+ container.style.width = "100px";
+ assert_equals(orthogonal.offsetWidth, 50);
+ assert_not_equals(orthogonal.offsetWidth, container.offsetWidth);
+ }, "Orthogonal width");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/percentage-padding-orthogonal.html b/testing/web-platform/tests/css/css-contain/container-queries/percentage-padding-orthogonal.html
new file mode 100644
index 0000000000..0c419d18a9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/percentage-padding-orthogonal.html
@@ -0,0 +1,66 @@
+<!doctype html>
+<title>CSS Container Queries Test: @container queries affecting height affecting percentage padding</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #vertical {
+ width: 500px;
+ writing-mode: vertical-lr;
+ }
+
+ #padded {
+ width: 100%;
+ box-sizing: border-box;
+ padding-right: 100%;
+ background-color: orange;
+ }
+
+ #horizontal {
+ writing-mode: horizontal-tb;
+ width: 100%;
+ }
+
+ #container {
+ width: 100%;
+ container-type: inline-size;
+ background-color: green;
+ }
+
+ #first, #second { height: 50px; }
+
+ @container (width <= 400px) {
+ #second { display: none; }
+ }
+</style>
+<div id="vertical">
+ <div id="padded">
+ <div id="horizontal">
+ <div id="container">
+ <div id="first"></div>
+ <div id="second"></div>
+ </div>
+ </div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => assert_equals(padded.offsetHeight, 100),
+ "#container height measured with 500px width. Both container children visible");
+ test(() => assert_equals(container.offsetWidth, 400),
+ "#container width 400px after padding is applied.");
+ test(() => assert_equals(container.offsetHeight, 50),
+ "#container width 400px after padding is applied. #second is removed from the rendering");
+
+ // Reduce width by 1px to test that a re-layout is not stateful.
+ vertical.style.width = "499px";
+
+ test(() => assert_equals(padded.offsetHeight, 100),
+ "#container height measured with 499px width. Both container children visible");
+ test(() => assert_equals(container.offsetWidth, 399),
+ "#container width 399px after padding is applied. #second is removed from the rendering");
+ test(() => assert_equals(container.offsetHeight, 50),
+ "#container width 399x after padding is applied. #second is removed from the rendering");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-001.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-001.html
new file mode 100644
index 0000000000..0baef0bfc2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-001.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<title>CSS Container Queries Test: Container for elements with pseudo elements</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ :root {
+ color: black;
+ }
+
+ .container {
+ container-type: size;
+ width: 200px;
+ height: 40px;
+ }
+
+ @container (min-width: 300px) {
+ #container1 div::before { content: "before"; }
+ #container1 div::after { content: "after"; }
+ #container2 li::marker { color: green; }
+ }
+</style>
+<main id=container1 class=container>
+ <div>test</div>
+</main>
+<main id=container2 class=container>
+ <ol>
+ <li>One</li>
+ </ol>
+</main>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(function() {
+ let div = document.querySelector('#container1 > div');
+ assert_equals(getComputedStyle(div, '::before').content, 'none');
+ assert_equals(getComputedStyle(div, '::after').content, 'none');
+
+ container1.style.width = '300px';
+ assert_equals(getComputedStyle(div, '::before').content, '"before"');
+ assert_equals(getComputedStyle(div, '::after').content, '"after"');
+
+ container1.style = '';
+ assert_equals(getComputedStyle(div, '::before').content, 'none');
+ assert_equals(getComputedStyle(div, '::after').content, 'none');
+ }, 'Pseudo-elements ::before and ::after respond to container size changes');
+
+ test(function() {
+ let li = document.querySelector('#container2 li');
+ assert_equals(getComputedStyle(li, '::marker').color, 'rgb(0, 0, 0)');
+
+ container2.style.width = '300px';
+ assert_equals(getComputedStyle(li, '::marker').color, 'rgb(0, 128, 0)');
+
+ container2.style = '';
+ assert_equals(getComputedStyle(li, '::marker').color, 'rgb(0, 0, 0)');
+ }, 'Pseudo-element ::marker responds to container size changes');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002-ref.html
new file mode 100644
index 0000000000..da96a826cf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<title>CSS Test Reference</title>
+<div>PASS</div>
+<div>PASS</div>
+<div>PASS</div>
+<div>PASS</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002.html
new file mode 100644
index 0000000000..a44c64c700
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>CSS Container Queries Test: Container for ::before/::after pseudo elements</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<link rel="match" href="pseudo-elements-002-ref.html">
+<style>
+ .container { container-type: inline-size; }
+
+ @container (max-width: 100px) { #c1::before { content: "PASS" } }
+ @container (min-width: 150px) { #c1::before { content: "FAIL" } }
+
+ @container (max-width: 100px) { #c2::before { content: "PASS" } }
+ @container (min-width: 150px) { #c2::before { content: "FAIL" } }
+
+ @container (max-width: 100px) { #c3::after { content: "PASS" } }
+ @container (min-width: 150px) { #c3::after { content: "FAIL" } }
+
+ @container (max-width: 100px) { #c4::after { content: "PASS" } }
+ @container (min-width: 150px) { #c4::after { content: "FAIL" } }
+</style>
+<div id="c1" class="container" style="width:100px"></div>
+<div id="c2" class="container" style="width:200px"></div>
+<div id="c3" class="container" style="width:100px"></div>
+<div id="c4" class="container" style="width:200px"></div>
+<script>
+ document.body.offsetTop;
+ c2.style.width = "100px";
+ c4.style.width = "100px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002b-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002b-ref.html
new file mode 100644
index 0000000000..5783b77fec
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002b-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<title>CSS Test Reference</title>
+<div><span style="color:green">P</span>ASS if P is green.</div>
+<div><span style="color:green">P</span>ASS if P is green.</div>
+<div><span style="color:green">P</span>ASS if P is green.</div>
+<div><span style="color:green">P</span>ASS if P is green.</div>
+<div style="color:green">PASS if text is green.</div>
+<div style="color:green">PASS if text is green.</div>
+<div style="color:green">PASS if text is green.</div>
+<div style="color:green">PASS if text is green.</div>
+<div style="color:green">PASS if text is green.</div>
+<div style="color:green">PASS if text is green.</div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002b.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002b.html
new file mode 100644
index 0000000000..e1874e035b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-002b.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<title>CSS Container Queries Test: Container for ::first-letter/::first-line pseudo elements</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<link rel="match" href="pseudo-elements-002b-ref.html">
+<style>
+ .container { container-type: inline-size; }
+
+ @container (max-width: 300px) { #c5::first-letter { color: green } }
+ @container (max-width: 300px) { #c6::first-letter { color: green } }
+
+ @container (min-width: 400px) { #c7::first-letter { color: green } }
+ @container (min-width: 400px) { #c8::first-letter { color: green } }
+
+ @container (max-width: 300px) { #c9::first-line { color: green } }
+ @container (max-width: 300px) { #c10::first-line { color: green } }
+
+ @container (min-width: 400px) { #c11::first-line { color: green } }
+ @container (min-width: 400px) { #c12::first-line { color: green } }
+
+ #c13::first-line { color: red }
+ @container (min-width: 400px) { #c13::first-line { color: green } }
+ @container (min-width: 400px) { #c14::first-line { color: green } }
+</style>
+<div class="container" style="width:400px">
+ <div id="c5" class="container" style="width:300px">PASS if P is green.</div>
+</div>
+<div class="container" style="width:400px">
+ <div id="c6" class="container" style="width:400px">PASS if P is green.</div>
+</div>
+<div id="c7" class="container" style="width:400px">
+ <div class="container" style="width:300px">PASS if P is green.</div>
+</div>
+<div id="c8" class="container" style="width:300px">
+ <div class="container" style="width:300px">PASS if P is green.</div>
+</div>
+<div class="container" style="width:400px">
+ <div id="c9" class="container" style="width:300px">PASS if text is green.</div>
+</div>
+<div class="container" style="width:400px">
+ <div id="c10" class="container" style="width:400px">PASS if text is green.</div>
+</div>
+<div id="c11" class="container" style="width:400px">
+ <div class="container" style="width:300px">PASS if text is green.</div>
+</div>
+<div id="c12" class="container" style="width:300px">
+ <div class="container" style="width:300px">PASS if text is green.</div>
+</div>
+<div id="c13" class="container" style="width:300px">PASS if text is green.</div>
+<div id="c14" class="container" style="width:300px">PASS if text is green.</div>
+<script>
+ document.body.offsetTop;
+ c6.style.width = "300px";
+ c8.style.width = "400px";
+ c10.style.width = "300px";
+ c12.style.width = "400px";
+ c13.style.width = "400px";
+ c14.style.width = "400px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-003.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-003.html
new file mode 100644
index 0000000000..2d7647f710
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-003.html
@@ -0,0 +1,69 @@
+<!doctype html>
+<title>@container: originating element container for pseudo elements</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ .container { container-type: inline-size; }
+ #target { display: list-item; }
+ @container (max-width: 200px) {
+ #target::before { content: "PASS"; color: green; }
+ #target::after { color: green; }
+ #target::marker { color: green; }
+ #target::first-line { color: green; }
+ #target::first-letter { color: green; }
+ }
+ @container ((min-width: 300px) and (max-width: 350px)) {
+ #outer::first-line { color: green; }
+ #outer::first-letter { color: green; }
+ }
+ dialog::backdrop { background-color: lime; }
+ @container (max-width: 100px) {
+ dialog::backdrop { background-color: green; }
+ }
+</style>
+<div style="width: 400px" class="container">
+ <div style="width: 300px" class="container">
+ <div id="target" class="container" style="width: 200px">First-line</div>
+ <dialog id="dialog" class="container" style="width: 100px"></dialog>
+ </div>
+ <div style="width: 400px" class="container">
+ <div id="outer" style="width: 300px" class="container">
+ <div class="container" style="width: 200px">First-line</div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const green = "rgb(0, 128, 0)";
+ const lime = "rgb(0, 255, 0)";
+
+ test(() => {
+ assert_equals(getComputedStyle(target, "::before").color, green);
+ }, "Originating element container for ::before");
+ test(() => {
+ assert_equals(getComputedStyle(target, "::after").color, green);
+ }, "Originating element container for ::after");
+ test(() => {
+ assert_equals(getComputedStyle(target, "::marker").color, green);
+ }, "Originating element container for ::marker");
+ test(() => {
+ assert_equals(getComputedStyle(target, "::first-line").color, green);
+ }, "Originating element container for ::first-line");
+ test(() => {
+ assert_equals(getComputedStyle(target, "::first-letter").color, green);
+ }, "Originating element container for ::first-letter");
+ test(() => {
+ assert_equals(getComputedStyle(outer, "::first-line").color, green);
+ }, "Originating element container for outer ::first-line");
+ test(() => {
+ assert_equals(getComputedStyle(outer, "::first-letter").color, green);
+ }, "Originating element container for outer ::first-letter");
+ test((t) => {
+ t.add_cleanup(() => dialog.close());
+ assert_equals(getComputedStyle(dialog, "::backdrop").backgroundColor, lime, "::backdrop not rendered");
+ dialog.showModal();
+ assert_equals(getComputedStyle(dialog, "::backdrop").backgroundColor, green, "::backdrop rendered");
+ }, "Originating element container for ::backdrop");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-004.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-004.html
new file mode 100644
index 0000000000..db199f2205
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-004.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<title>@container: originating element container for pseudo elements</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #target { container-type: inline-size; }
+ #target::before,
+ #target::after,
+ #target::marker,
+ #target::first-line,
+ #target::first-letter,
+ #target::backdrop {
+ color: red;
+ }
+ @container (width >= 300px) {
+ #target::before,
+ #target::after,
+ #target::marker,
+ #target::first-line,
+ #target::first-letter,
+ #target::backdrop {
+ color: green;
+ }
+ }
+</style>
+<div id="outer" style="width: 200px">
+ <div id="target"></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const green = "rgb(0, 128, 0)";
+ const red = "rgb(255, 0, 0)";
+
+ const pseudo_elements = ["::before", "::after", "::marker", "::first-line", "::first-letter", "::backdrop"];
+
+ pseudo_elements.forEach((pseudo_element) => {
+ test(() => {
+ assert_equals(getComputedStyle(target, pseudo_element).color, red);
+ }, `Initial color for ${pseudo_element}`);
+ });
+
+ outer.style.width = "300px";
+
+ pseudo_elements.forEach((pseudo_element) => {
+ test(() => {
+ assert_equals(getComputedStyle(target, pseudo_element).color, green);
+ }, `Color for ${pseudo_element} depending on container`);
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-005.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-005.html
new file mode 100644
index 0000000000..575b66d6f8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-005.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<title>CSS Container Queries Test: Style container for pseudo elements</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #c1 {
+ --theme: green;
+ }
+ @container style(--theme: green) {
+ #c1::before {
+ content: "";
+ color: green;
+ display: block;
+ height: 100px;
+ }
+ }
+</style>
+<div id="c1"></div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ let style = getComputedStyle(c1, "::before");
+ assert_equals(style.color, "rgb(0, 128, 0)");
+ assert_equals(style.height, "100px");
+ }, "::before pseudo element querying style() of originating element");
+</script>
+
+<style>
+ #c2 {
+ --theme: red;
+ }
+ #c2::before { color: red }
+ #c2.green {
+ --theme: green;
+ }
+ @container style(--theme: green) {
+ #c2::before {
+ content: "";
+ color: green;
+ }
+ }
+</style>
+<div id="c2"></div>
+<script>
+ test(() => {
+ let style = getComputedStyle(c2, "::before");
+ assert_equals(style.color, "rgb(255, 0, 0)");
+ }, "::before pseudo element not matching style()");
+
+ test(() => {
+ c2.className = "green";
+ let style = getComputedStyle(c2, "::before");
+ assert_equals(style.color, "rgb(0, 128, 0)");
+ }, "::before pseudo element matching style() query after class change");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-006.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-006.html
new file mode 100644
index 0000000000..65aee97f75
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-006.html
@@ -0,0 +1,66 @@
+<!doctype html>
+<title>@container: originating element container for pseudo elements</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ .container { container-type: inline-size; }
+ #target { display: list-item; }
+ @container (max-width: 200px) {
+ #target::before { content: "PASS"; font-size: 10cqw; }
+ #target::after { font-size: 10cqw; }
+ #target::marker { font-size: 10cqw; }
+ #target::first-line { font-size: 10cqw; }
+ #target::first-letter { font-size: 10cqw; }
+ }
+ @container ((min-width: 300px) and (max-width: 350px)) {
+ #outer::first-line { font-size: 10cqw; }
+ #outer::first-letter { font-size: 10cqw; }
+ }
+ dialog::backdrop { font-size: 0px; }
+ @container (max-width: 100px) {
+ dialog::backdrop { font-size: 10cqw; }
+ }
+</style>
+<div style="width: 400px" class="container">
+ <div style="width: 300px" class="container">
+ <div id="target" class="container" style="width: 200px">First-line</div>
+ <dialog id="dialog" class="container" style="width: 100px"></dialog>
+ </div>
+ <div style="width: 400px" class="container">
+ <div id="outer" style="width: 300px" class="container">
+ <div class="container" style="width: 200px">First-line</div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(target, "::before").fontSize, "20px");
+ }, "Originating element container for ::before");
+ test(() => {
+ assert_equals(getComputedStyle(target, "::after").fontSize, "20px");
+ }, "Originating element container for ::after");
+ test(() => {
+ assert_equals(getComputedStyle(target, "::marker").fontSize, "20px");
+ }, "Originating element container for ::marker");
+ test(() => {
+ assert_equals(getComputedStyle(target, "::first-line").fontSize, "20px");
+ }, "Originating element container for ::first-line");
+ test(() => {
+ assert_equals(getComputedStyle(target, "::first-letter").fontSize, "20px");
+ }, "Originating element container for ::first-letter");
+ test(() => {
+ assert_equals(getComputedStyle(outer, "::first-line").fontSize, "30px");
+ }, "Originating element container for outer ::first-line");
+ test(() => {
+ assert_equals(getComputedStyle(outer, "::first-letter").fontSize, "30px");
+ }, "Originating element container for outer ::first-letter");
+ test((t) => {
+ t.add_cleanup(() => dialog.close());
+ assert_equals(getComputedStyle(dialog, "::backdrop").fontSize, "0px", "::backdrop not rendered");
+ dialog.showModal();
+ assert_equals(getComputedStyle(dialog, "::backdrop").fontSize, "10px", "::backdrop rendered");
+ }, "Originating element container for ::backdrop");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-007.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-007.html
new file mode 100644
index 0000000000..951f4226f4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-007.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<title>@container: originating element container for pseudo elements</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #target { container-type: inline-size; }
+ #target::before,
+ #target::after,
+ #target::marker,
+ #target::first-line,
+ #target::first-letter,
+ #target::backdrop {
+ font-size: 0px;
+ }
+ @container (width >= 300px) {
+ #target::before,
+ #target::after,
+ #target::marker,
+ #target::first-line,
+ #target::first-letter,
+ #target::backdrop {
+ font-size: 10cqw;
+ }
+ }
+</style>
+<div id="outer" style="width: 200px">
+ <div id="target"></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const pseudo_elements = ["::before", "::after", "::marker", "::first-line", "::first-letter", "::backdrop"];
+
+ pseudo_elements.forEach((pseudo_element) => {
+ test(() => {
+ assert_equals(getComputedStyle(target, pseudo_element).fontSize, "0px");
+ }, `Initial font-size for ${pseudo_element}`);
+ });
+
+ outer.style.width = "300px";
+
+ pseudo_elements.forEach((pseudo_element) => {
+ test(() => {
+ assert_equals(getComputedStyle(target, pseudo_element).fontSize, "30px");
+ }, `font-size for ${pseudo_element} depending on container`);
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-008.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-008.html
new file mode 100644
index 0000000000..859deb2206
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-008.html
@@ -0,0 +1,66 @@
+<!doctype html>
+<title>@container: originating element container for pseudo elements</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ .container { container-type: inline-size; }
+ #target { display: list-item; }
+ #target::before { content: "PASS"; font-size: 10cqw; }
+ #target::after { font-size: 10cqw; }
+ #target::marker { font-size: 10cqw; }
+ #target::first-line { font-size: 10cqw; }
+ #target::first-letter { font-size: 10cqw; }
+ #target::highlight(foo) {
+ text-decoration-line: underline;
+ text-decoration-thickness: 10cqw;
+ }
+ #outer::first-line { font-size: 10cqw; }
+ #outer::first-letter { font-size: 10cqw; }
+ dialog::backdrop { font-size: 10cqw; }
+</style>
+<div style="width: 400px" class="container">
+ <div style="width: 300px" class="container">
+ <div id="target" class="container" style="width: 200px">First-line</div>
+ <dialog id="dialog" class="container" style="width: 100px"></dialog>
+ </div>
+ <div style="width: 400px" class="container">
+ <div id="outer" style="width: 300px" class="container">
+ <div class="container" style="width: 200px">First-line</div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(target, "::before").fontSize, "20px");
+ }, "Originating element container for ::before");
+ test(() => {
+ assert_equals(getComputedStyle(target, "::after").fontSize, "20px");
+ }, "Originating element container for ::after");
+ test(() => {
+ assert_equals(getComputedStyle(target, "::marker").fontSize, "20px");
+ }, "Originating element container for ::marker");
+ test(() => {
+ assert_equals(getComputedStyle(target, "::first-line").fontSize, "20px");
+ }, "Originating element container for ::first-line");
+ test(() => {
+ assert_equals(getComputedStyle(target, "::first-letter").fontSize, "20px");
+ }, "Originating element container for ::first-letter");
+ test(() => {
+ assert_equals(getComputedStyle(target, "::highlight(foo)").textDecorationThickness, "20px");
+ }, `Originating element container for ::highlight`);
+ test(() => {
+ assert_equals(getComputedStyle(outer, "::first-line").fontSize, "30px");
+ }, "Originating element container for outer ::first-line");
+ test(() => {
+ assert_equals(getComputedStyle(outer, "::first-letter").fontSize, "30px");
+ }, "Originating element container for outer ::first-letter");
+ test((t) => {
+ t.add_cleanup(() => dialog.close());
+ assert_equals(getComputedStyle(dialog, "::backdrop").fontSize, "30px", "::backdrop not rendered");
+ dialog.showModal();
+ assert_equals(getComputedStyle(dialog, "::backdrop").fontSize, "10px", "::backdrop rendered");
+ }, "Originating element container for ::backdrop");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-009-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-009-ref.html
new file mode 100644
index 0000000000..fe6fbb140b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-009-ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<title>CSS Test Reference</title>
+<span style="color: green">Selection</span>
+<span style="color: green">Highlight</span>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-009.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-009.html
new file mode 100644
index 0000000000..769a5962ff
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-009.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>CSS Container Queries Test: Container for highlight pseudo elements</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container">
+<link rel="match" href="pseudo-elements-009-ref.html">
+<style>
+ #container {
+ container-type: inline-size;
+ width: 500px;
+ }
+
+ ::selection { color: red; background: transparent; }
+ ::highlight(hi) { color: red; background: transparent; }
+
+ @container (width >= 400px) {
+ ::selection { color: green }
+ ::highlight(hi) { color: green }
+ }
+</style>
+<div id="container">
+ <span id="sel">Selection</span>
+ <span id="hi">Highlight</span>
+</div>
+<script>
+ getSelection().selectAllChildren(sel);
+ let highlight_range = document.createRange();
+ highlight_range.selectNode(hi);
+ CSS.highlights.set("hi", new Highlight(highlight_range));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-010-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-010-ref.html
new file mode 100644
index 0000000000..a98a402328
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-010-ref.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<title>CSS Test Reference</title>
+<span style="color: green">Highlight</span>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-010.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-010.html
new file mode 100644
index 0000000000..e2e8f8659c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-010.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>CSS Container Queries Test: Container for highlight pseudo elements</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container">
+<link rel="match" href="pseudo-elements-010-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+ .container { container-type: inline-size; }
+ #outer { width: 300px; }
+ #inner { width: 500px; }
+
+ #inner::highlight(hi) {
+ color: red;
+ background: transparent;
+ }
+ @container (width >= 400px) {
+ #inner.green::highlight(hi) {
+ color: green;
+ background: transparent;
+ }
+ }
+</style>
+<div id="outer" class="container">
+ <div id="inner" class="container">
+ <span id="hi">Highlight</span>
+ </div>
+</div>
+<script>
+ let highlight_range = document.createRange();
+ highlight_range.selectNode(hi);
+ CSS.highlights.set("hi", new Highlight(highlight_range));
+
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ inner.classList.add("green");
+ takeScreenshot();
+ });
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-011.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-011.html
new file mode 100644
index 0000000000..26dabbe1df
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-011.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>CSS Container Queries Test: ::highlight pseudo element on size container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container">
+<link rel="match" href="pseudo-elements-010-ref.html">
+<style>
+ #container {
+ width: 500px;
+ container-type: inline-size;
+ }
+ #container::highlight(hi) {
+ color: red;
+ background: transparent;
+ }
+ @container (width >= 400px) {
+ #container::highlight(hi) {
+ color: green;
+ background: transparent;
+ }
+ }
+</style>
+<div id="container">Highlight</div>
+<script>
+ let highlight_range = document.createRange();
+ highlight_range.selectNode(container);
+ CSS.highlights.set("hi", new Highlight(highlight_range));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-012.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-012.html
new file mode 100644
index 0000000000..7c36d9270d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-012.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>CSS Container Queries Test: ::highlight pseudo size container change</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container">
+<link rel="match" href="pseudo-elements-010-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+ #container {
+ width: 300px;
+ container-type: inline-size;
+ }
+ #container::highlight(hi) {
+ color: red;
+ background: transparent;
+ }
+ @container (width >= 400px) {
+ #container::highlight(hi) {
+ color: green;
+ background: transparent;
+ }
+ }
+</style>
+<div id="container">Highlight</div>
+<script>
+ let highlight_range = document.createRange();
+ highlight_range.selectNode(container);
+ CSS.highlights.set("hi", new Highlight(highlight_range));
+
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ container.style.width = "500px";
+ takeScreenshot();
+ });
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-013.html b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-013.html
new file mode 100644
index 0000000000..870b589115
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/pseudo-elements-013.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<title>@container: originating element container for highlight pseudo elements</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #target { container-type: inline-size; }
+ #target::highlight(foo) {
+ text-decoration-line: underline;
+ text-decoration-thickness: 0px;
+ }
+ @container (width >= 300px) {
+ #target::highlight(foo) {
+ text-decoration-line: underline;
+ text-decoration-thickness: 10cqw;
+ }
+ #target::highlight(bar) {
+ text-decoration-line: underline;
+ text-decoration-thickness: 10cqw;
+ }
+ }
+</style>
+<div id="outer" style="width: 200px">
+ <div id="target"></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(target, "::highlight(foo)").textDecorationThickness, "0px");
+ }, `Initial text-decoration-thickness for highlight pseudo`);
+
+ outer.style.width = "300px";
+
+ test(() => {
+ assert_equals(getComputedStyle(target, "::highlight(foo)").textDecorationThickness, "30px");
+ }, `text-decoration-thickness for highlight pseudo depending on container`);
+ test(() => {
+ assert_equals(getComputedStyle(target, "::highlight(bar)").textDecorationThickness, "30px");
+ }, `text-decoration-thickness for highlight pseudo depending on container only defined in a query`);
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/query-content-box.html b/testing/web-platform/tests/css/css-contain/container-queries/query-content-box.html
new file mode 100644
index 0000000000..5f6cc9fdbe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/query-content-box.html
@@ -0,0 +1,80 @@
+<!doctype html>
+<title>CSS Container Queries Test: Size queries match content-box</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ .container {
+ container-type: size;
+ border: 10px solid black;
+ padding: 40px;
+ margin: 20px;
+ }
+
+ #container1 {
+ box-sizing: content-box;
+ width: 100px;
+ height: 100px;
+ }
+
+ #container2 {
+ box-sizing: border-box;
+ width: 200px;
+ height: 200px;
+ }
+
+ #container3 {
+ box-sizing: content-box;
+ width: 100px;
+ height: 100px;
+ overflow: scroll;
+ }
+
+ #container4 {
+ box-sizing: border-box;
+ width: 200px;
+ height: 200px;
+ overflow: scroll;
+ }
+
+ @container ((width = 100px) and (height = 100px)) {
+ .target {
+ background-color: green;
+ height: 100%;
+ }
+ }
+</style>
+<div id="container1" class="container">
+ <div class="target"></div>
+</div>
+<div id="container2" class="container">
+ <div class="target"></div>
+</div>
+<div id="container3" class="container">
+ <div class="target"></div>
+</div>
+<div id="container4" class="container">
+ <div class="target"></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const green = "rgb(0, 128, 0)";
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#container1 > .target")).backgroundColor, green);
+ }, "Size queries with content-box sizing");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#container2 > .target")).backgroundColor, green);
+ }, "Size queries with border-box sizing");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#container3 > .target")).backgroundColor, green);
+ }, "Size queries with content-box sizing and overflow:scroll");
+
+ test(() => {
+ assert_equals(getComputedStyle(document.querySelector("#container4 > .target")).backgroundColor, green);
+ }, "Size queries with border-box sizing and overflow:scroll");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/query-evaluation-style.html b/testing/web-platform/tests/css/css-contain/container-queries/query-evaluation-style.html
new file mode 100644
index 0000000000..bf059f795a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/query-evaluation-style.html
@@ -0,0 +1,80 @@
+<!doctype html>
+<title>Evaluation of style queries</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ --applied: false;
+ --foo: bar;
+ }
+</style>
+<div id=container>
+ <div id=inner></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ function test_query(query, expected) {
+ test((t) => {
+ let style = document.createElement('style');
+ t.add_cleanup(() => { style.remove(); });
+ style.innerText = `@container ${query} { #inner { --applied:true; } }`;
+ let cs = getComputedStyle(inner);
+ assert_equals(cs.getPropertyValue('--applied'), 'false');
+ document.head.append(style);
+ assert_equals(cs.getPropertyValue('--applied'), expected.toString());
+ }, query);
+ };
+
+ // Note that the following assumes that elements are style containers by
+ // default [1], and that:
+ //
+ // - style(--foo: bar) is a query that returns 'true', and
+ // - style(--baz: qux) is a query that returns 'false'.
+ //
+ // [1] https://github.com/w3c/csswg-drafts/issues/7066
+
+ // Nesting in <style-query>:
+ test_query('style((--foo: bar))', true);
+ test_query('style((--baz: qux))', false);
+ test_query('style((unknown))', false);
+ test_query('unknown((--foo: bar))', false);
+
+ // "not" in <style-query>:
+ test_query('style(not (--foo: bar))', false);
+ test_query('style(not (--baz: qux))', true);
+ test_query('style(not (unknown))', false);
+
+ // "and" in <style-query>:
+ test_query('style((--foo: bar) and (--foo: bar))', true);
+ test_query('style((--foo: bar) and (--foo: bar) and (--foo: bar))', true);
+ test_query('style((--baz: qux) and (--baz: qux))', false);
+ test_query('style((--baz: qux) and (--foo: bar) and (--foo: bar))', false);
+ test_query('style((--foo: bar) and (--baz: qux) and (--foo: bar))', false);
+ test_query('style((--foo: bar) and (--foo: bar) and (--baz: qux))', false);
+ test_query('style((unknown) and (--foo: bar) and (--foo: bar))', false);
+ test_query('style((--foo: bar) and (unknown) and (--foo: bar))', false);
+ test_query('style((--foo: bar) and (--foo: bar) and (unknown))', false);
+
+ // "or" in <style-query>:
+ test_query('style((--foo: bar) or (--foo: bar))', true);
+ test_query('style((--foo: bar) or (--foo: bar) or (--foo: bar))', true);
+ test_query('style((--baz: qux) or (--baz: qux))', false);
+ test_query('style((--baz: qux) or (--foo: bar) or (--foo: bar))', true);
+ test_query('style((--foo: bar) or (--baz: qux) or (--foo: bar))', true);
+ test_query('style((--foo: bar) or (--foo: bar) or (--baz: qux))', true);
+ test_query('style((unknown) or (--foo: bar) or (--foo: bar))', false);
+ test_query('style((--foo: bar) or (unknown) or (--foo: bar))', false);
+ test_query('style((--foo: bar) or (--foo: bar) or (unknown))', false);
+ test_query('style((unknown) or (--baz: qux) or (--foo: bar))', false);
+
+ // Combinations, <style-query>:
+ test_query('style(not ((--foo: bar) and (--foo: bar)))', false);
+ test_query('style(not ((--foo: bar) and (--baz: qux)))', true);
+ test_query('style((--foo: bar) and (not ((--baz: qux) or (--foo: bar))))', false);
+ test_query('style((--baz: qux) or (not ((--baz: qux) and (--foo: bar))))', true);
+ test_query('style((--baz: qux) or ((--baz: qux) and (--foo: bar)))', false);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/query-evaluation.html b/testing/web-platform/tests/css/css-contain/container-queries/query-evaluation.html
new file mode 100644
index 0000000000..469b7b0d7a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/query-evaluation.html
@@ -0,0 +1,87 @@
+<!doctype html>
+<title>Evaluation of queries</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ width: 1px;
+ height: 0px;
+ container-type: size;
+ --applied:false;
+ }
+</style>
+<div id=container>
+ <div id=inner></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ function test_query(query, expected) {
+ test((t) => {
+ let style = document.createElement('style');
+ t.add_cleanup(() => { style.remove(); });
+ style.innerText = `@container ${query} { #inner { --applied:true; } }`;
+ let cs = getComputedStyle(inner);
+ assert_equals(cs.getPropertyValue('--applied'), 'false');
+ document.head.append(style);
+ assert_equals(cs.getPropertyValue('--applied'), expected.toString());
+ }, query);
+ };
+
+ // We don't care about specific features in this file, only higher level
+ // evaluation like "and", "or", and so forth. The features "width", "height"
+ // and "unknown" are arbitrarily chosen to represent true, false, and
+ // unknown values, respectively.
+
+ test_query('(width)', true);
+ test_query('(height)', false);
+ test_query('(unknown)', false);
+ test_query('unknown(width)', false);
+
+ // Nesting in <container-query>:
+ test_query('((width))', true);
+ test_query('((height))', false);
+ test_query('((unknown))', false);
+ test_query('((((width))))', true);
+ test_query('((((height))))', false);
+ test_query('((((unknown))))', false);
+
+ // "not" in <container-query>:
+ test_query('(not (width))', false);
+ test_query('(not (height))', true);
+ test_query('(not (unknown))', false);
+ test_query('(not unknown(width))', false);
+
+ // "and" in <container-query>:
+ test_query('((width) and (width))', true);
+ test_query('((width) and (width) and (width))', true);
+ test_query('((height) and (height))', false);
+ test_query('((height) and (width) and (width))', false);
+ test_query('((width) and (height) and (width))', false);
+ test_query('((width) and (width) and (height))', false);
+ test_query('((unknown) and (width) and (width))', false);
+ test_query('((width) and (unknown) and (width))', false);
+ test_query('((width) and (width) and (unknown))', false);
+
+ // "or" in <container-query>:
+ test_query('((width) or (width))', true);
+ test_query('((width) or (width) or (width))', true);
+ test_query('((height) or (height))', false);
+ test_query('((height) or (width) or (width))', true);
+ test_query('((width) or (height) or (width))', true);
+ test_query('((width) or (width) or (height))', true);
+ test_query('((unknown) or (width) or (width))', false);
+ test_query('((width) or (unknown) or (width))', false);
+ test_query('((width) or (width) or (unknown))', false);
+ test_query('((unknown) or (height) or (width))', false);
+
+ // Combinations, <container-query>:
+ test_query('(not ((width) and (width)))', false);
+ test_query('(not ((width) and (height)))', true);
+ test_query('((width) and (not ((height) or (width))))', false);
+ test_query('((height) or (not ((height) and (width))))', true);
+ test_query('((height) or ((height) and (width)))', false);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/reattach-container-with-dirty-child.html b/testing/web-platform/tests/css/css-contain/container-queries/reattach-container-with-dirty-child.html
new file mode 100644
index 0000000000..680d9caa84
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/reattach-container-with-dirty-child.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<title>CSS Container Queries Test: @container changing display type while descendant styles change</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ container-type: inline-size;
+ }
+ @container (min-width: 200px) {
+ div { color: red }
+ }
+ @container (max-width: 150px) {
+ div { color: lime }
+ }
+</style>
+<div id="container">
+ <div id="child"><span id="inner">XXX</span></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ container.offsetTop;
+ assert_equals(getComputedStyle(child).color, "rgb(255, 0, 0)");
+ }, "Initially wider than 200px");
+
+ test(() => {
+ container.style.width = "100px";
+ container.style.display = "inline-block";
+ inner.style.color = "green";
+ container.offsetTop;
+ assert_equals(getComputedStyle(child).color, "rgb(0, 255, 0)");
+ assert_equals(getComputedStyle(inner).color, "rgb(0, 128, 0)");
+ }, "Container query changed and inner.style applied");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/resize-while-content-visibility-hidden-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/resize-while-content-visibility-hidden-ref.html
new file mode 100644
index 0000000000..2a87df85b7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/resize-while-content-visibility-hidden-ref.html
@@ -0,0 +1,3 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<div style="width:200px;height:200px;background:green"></div>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/resize-while-content-visibility-hidden.html b/testing/web-platform/tests/css/css-contain/container-queries/resize-while-content-visibility-hidden.html
new file mode 100644
index 0000000000..a3658f7f34
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/resize-while-content-visibility-hidden.html
@@ -0,0 +1,53 @@
+<!doctype html>
+<html class="reftest-wait">
+<title>CSS Container Queries Test: condition change while content-visibility: hidden</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#content-visibility">
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="match" href="resize-while-content-visibility-hidden-ref.html">
+<link rel="assert" content="Container query applies even if container is content-visibility: hidden">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ container-name: container;
+ container-type: size;
+ width: 300px;
+ height: 300px;
+}
+
+#child {
+ width: 200px;
+ height: 200px;
+ background: red;
+}
+
+#container.wide { width: 500px; }
+.locked { content-visibility: hidden; }
+
+@container container (min-width: 400px) { #child { background: green; } }
+</style>
+
+<div id=container>
+ <div id=child></div>
+</div>
+
+<script>
+async function runTest() {
+ await new Promise(requestAnimationFrame);
+ container.classList.add("locked");
+
+ await new Promise(requestAnimationFrame);
+ container.classList.add("wide");
+
+ await new Promise(requestAnimationFrame);
+ container.classList.remove("locked");
+
+ await new Promise(requestAnimationFrame);
+ takeScreenshot();
+}
+
+requestAnimationFrame(() => { requestAnimationFrame(() => runTest()) });
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/sibling-layout-dependency.html b/testing/web-platform/tests/css/css-contain/container-queries/sibling-layout-dependency.html
new file mode 100644
index 0000000000..5e30a998d2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/sibling-layout-dependency.html
@@ -0,0 +1,134 @@
+<!doctype html>
+<title>@container-dependent styles respond to layout changes</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#containment-size">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<script>
+ setup(() => assert_implements_container_queries());
+</script>
+<style>
+
+ @container (width: 10px) { .affected { --x:10; } }
+ @container (width: 20px) { .affected { --x:20; } }
+
+ .flex {
+ display: flex;
+ height: 30px;
+ width: 30px;
+ }
+
+ .container {
+ container-type: size;
+ flex: 1;
+ background: tomato;
+ }
+
+ .sibling {
+ background-color: skyblue;
+ }
+ .w10 {
+ width: 10px;
+ }
+ .ahem { font: 5px Ahem; }
+
+ /* The following is just to make the results more human-readable. */
+ main {
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+</style>
+
+<main>
+ <!-- A sibling of the container gets a layout-affecting style change -->
+ <div class=flex>
+ <div class=container>
+ <div>
+ <div>
+ <div class=affected id=target1></div>
+ </div>
+ </div>
+ </div>
+ <div class="sibling w10" id=sibling1></div>
+ </div>
+ <script>
+ test(function() {
+ let cs = getComputedStyle(target1);
+ assert_equals(cs.getPropertyValue('--x'), '20');
+
+ sibling1.style.width = '20px';
+ assert_equals(cs.getPropertyValue('--x'), '10');
+ }, 'Sibling style mutation');
+ </script>
+
+ <!-- A sibling of the container gets a layout-affecting style change
+ affecting the parent of the gCS target -->
+ <div class=flex>
+ <div class=container>
+ <div>
+ <div class=affected id=parent2>
+ <div id=target2></div>
+ </div>
+ </div>
+ </div>
+ <div class="sibling w10" id=sibling2></div>
+ </div>
+ <script>
+ test(function() {
+ let cs = getComputedStyle(target2);
+ assert_equals(cs.getPropertyValue('--x'), '20');
+
+ sibling2.style.width = '20px';
+ assert_equals(cs.getPropertyValue('--x'), '10');
+ }, 'Sibling style mutation, parent is affected');
+ </script>
+
+<!-- A sibling of the container gets a layout-affecting style change
+ affecting an ancestor of the gCS target -->
+ <div class=flex>
+ <div class=container>
+ <div class=affected id=ancestor3>
+ <div>
+ <div id=target3></div>
+ </div>
+ </div>
+ </div>
+ <div class="sibling w10" id=sibling3></div>
+ </div>
+ <script>
+ test(function() {
+ let cs = getComputedStyle(target3);
+ assert_equals(cs.getPropertyValue('--x'), '20');
+
+ sibling3.style.width = '20px';
+ assert_equals(cs.getPropertyValue('--x'), '10');
+ }, 'Sibling style mutation, ancestor is affected');
+ </script>
+
+ <!-- A sibling of the container needs layout via text mutation -->
+ <div class=flex>
+ <div class=container>
+ <div>
+ <div>
+ <div class=affected id=target4></div>
+ </div>
+ </div>
+ </div>
+ <div class="sibling ahem" id=sibling4>XX</div>
+ </div>
+ <script>
+ promise_test(async function() {
+ await document.fonts.ready;
+
+ let cs = getComputedStyle(target4);
+ assert_equals(cs.getPropertyValue('--x'), '20');
+
+ sibling4.textContent = 'XXXX';
+ assert_equals(cs.getPropertyValue('--x'), '10');
+ }, 'Sibling text mutation');
+ </script>
+
+</main>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/size-container-no-principal-box.html b/testing/web-platform/tests/css/css-contain/container-queries/size-container-no-principal-box.html
new file mode 100644
index 0000000000..4bff0681ab
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/size-container-no-principal-box.html
@@ -0,0 +1,63 @@
+<!doctype html>
+<title>CSS Container Queries Test: size container types apply to elements without a principal box</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #outer {
+ container-type: inline-size;
+ }
+ #inner_none {
+ display: none;
+ container-type: inline-size;
+ }
+ #inner_contents {
+ display: contents;
+ container-type: inline-size;
+ }
+ @container (min-width: 0) {
+ span { color: red; }
+ }
+ @container (min-width: 0) {
+ #ref { color: green; }
+ }
+ @container not (max-width: 0) {
+ span { background-color: red; }
+ }
+ @container not (max-width: 0) {
+ #ref { background-color: green; }
+ }
+</style>
+<div id="outer">
+ <div id="ref"></div>
+ <div id="inner_none"><span></span></div>
+ <div id="inner_contents"><span></span></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(ref).color, "rgb(0, 128, 0)");
+ }, "(min-width: 0) can match a container with a principal box");
+
+ test(() => {
+ assert_equals(getComputedStyle(inner_none.firstChild).color, "rgb(0, 0, 0)");
+ }, "(min-width: 0) does not match a container without a principal box (display:none)");
+
+ test(() => {
+ assert_equals(getComputedStyle(inner_contents.firstChild).color, "rgb(0, 0, 0)");
+ }, "(min-width: 0) does not match a container without a principal box (display:contents)");
+
+ test(() => {
+ assert_equals(getComputedStyle(ref).backgroundColor, "rgb(0, 128, 0)");
+ }, "not (max-width: 0) can match a container with a principal box");
+
+ test(() => {
+ assert_equals(getComputedStyle(inner_none.firstChild).backgroundColor, "rgba(0, 0, 0, 0)");
+ }, "not (max-width: 0) does not match a container without a principal box (display:none)");
+
+ test(() => {
+ assert_equals(getComputedStyle(inner_contents.firstChild).backgroundColor, "rgba(0, 0, 0, 0)");
+ }, "not (max-width: 0) does not match a container without a principal box (display:contents)");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/size-container-with-quotes-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/size-container-with-quotes-ref.html
new file mode 100644
index 0000000000..e1822fa544
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/size-container-with-quotes-ref.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<title>CSS Test Reference</title>
+<q style="display:block">This text must be quoted.</q>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/size-container-with-quotes.html b/testing/web-platform/tests/css/css-contain/container-queries/size-container-with-quotes.html
new file mode 100644
index 0000000000..b88f882cd0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/size-container-with-quotes.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<title>CSS Container Queries Test: &lt;q&gt; element as a size container must generate quotes</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="match" href="size-container-with-quotes-ref.html">
+<style>
+ q {
+ container-type: inline-size;
+ display: block;
+ }
+</style>
+<q>This text must be quoted.</q>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/size-feature-evaluation.html b/testing/web-platform/tests/css/css-contain/container-queries/size-feature-evaluation.html
new file mode 100644
index 0000000000..600a266fce
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/size-feature-evaluation.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<title>Evaluation of size features</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+
+<div id=container>
+ <div id=target>
+ Test
+ </div>
+</div>
+
+<script>
+setup(() => assert_implements_container_queries());
+
+function test_evaluation(container_class, query, expected) {
+ test(function(t) {
+ let style_node = document.createElement('style');
+ t.add_cleanup(() => {
+ container.classList.remove(container_class);
+ style_node.remove();
+ });
+ style_node.innerText = `@container ${query} { #target { --applied:true; } }`;
+
+ assert_equals(getComputedStyle(target).getPropertyValue('--applied'), '');
+ container.classList.add(container_class);
+ document.head.append(style_node);
+ assert_equals(getComputedStyle(target).getPropertyValue('--applied'), expected ? 'true' : '');
+ }, `${query} (.${container_class})`);
+}
+
+</script>
+
+<style>
+ .horizontal {
+ width: 100px;
+ height: 200px;
+ container-type: size;
+ }
+
+ .vertical {
+ width: 100px;
+ height: 200px;
+ container-type: size;
+ writing-mode: vertical-rl;
+ }
+</style>
+<script>
+
+ for (let cls of ['horizontal', 'vertical']) {
+
+ let logical_width = (cls == 'horizontal') ? 'inline' : 'block';
+ let logical_height = (cls == 'horizontal') ? 'block' : 'inline';
+
+ test_evaluation(cls, '(width < 100px)', false);
+ test_evaluation(cls, '(width >= 100px)', true);
+ test_evaluation(cls, '(min-width: 100px)', true);
+ test_evaluation(cls, '(min-width: 101px)', false);
+ test_evaluation(cls, '(max-width: 100px)', true);
+ test_evaluation(cls, '(max-width: 99px)', false);
+
+ test_evaluation(cls, '(height < 200px)', false);
+ test_evaluation(cls, '(height >= 200px)', true);
+ test_evaluation(cls, '(min-height: 200px)', true);
+ test_evaluation(cls, '(min-height: 201px)', false);
+ test_evaluation(cls, '(max-height: 200px)', true);
+ test_evaluation(cls, '(max-height: 199px)', false);
+
+ test_evaluation(cls, `(${logical_width}-size < 100px)`, false);
+ test_evaluation(cls, `(${logical_width}-size >= 100px)`, true);
+ test_evaluation(cls, `(min-${logical_width}-size: 100px)`, true);
+ test_evaluation(cls, `(min-${logical_width}-size: 101px)`, false);
+ test_evaluation(cls, `(max-${logical_width}-size: 100px)`, true);
+ test_evaluation(cls, `(max-${logical_width}-size: 99px)`, false);
+
+ test_evaluation(cls, `(${logical_height}-size < 200px)`, false);
+ test_evaluation(cls, `(${logical_height}-size >= 200px)`, true);
+ test_evaluation(cls, `(min-${logical_height}-size: 200px)`, true);
+ test_evaluation(cls, `(min-${logical_height}-size: 201px)`, false);
+ test_evaluation(cls, `(max-${logical_height}-size: 200px)`, true);
+ test_evaluation(cls, `(max-${logical_height}-size: 199px)`, false);
+
+ test_evaluation(cls, '(orientation: landscape)', false);
+ test_evaluation(cls, '(orientation: portrait)', true);
+
+ test_evaluation(cls, '(aspect-ratio: 1/2)', true);
+ test_evaluation(cls, '(aspect-ratio: 2/1)', false);
+ }
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/style-change-in-container.html b/testing/web-platform/tests/css/css-contain/container-queries/style-change-in-container.html
new file mode 100644
index 0000000000..ed4baa7e8b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/style-change-in-container.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<title>CSS Container Queries Test: recompute style inside a @container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container { container-type: size; }
+ @container (min-width: 1px) {
+ #content { color: green; }
+ }
+</style>
+<div id="container">
+ <div id="content"></div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ let content = document.getElementById("content");
+
+ test(() => {
+ assert_equals(getComputedStyle(content).color, "rgb(0, 128, 0)");
+
+ // Dirty style of an element inside the container:
+ content.style.backgroundColor = "lime";
+
+ // The container query should still evaluate correctly:
+ assert_equals(getComputedStyle(content).color, 'rgb(0, 128, 0)');
+ }, "Basic test for container query evaluation stability");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/style-container-for-shadow-dom.html b/testing/web-platform/tests/css/css-contain/container-queries/style-container-for-shadow-dom.html
new file mode 100644
index 0000000000..d88bf0bca9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/style-container-for-shadow-dom.html
@@ -0,0 +1,263 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Container Queries Test: style query container for Shadow DOM</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#query-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+
+<div id="inclusive-ancestor-across-root">
+ <div style="--foo: bar">
+ <template shadowrootmode="open">
+ <style>
+ @container style(--foo: bar) {
+ #t1 { color: green; }
+ }
+ </style>
+ <div id="t1"></div>
+ </template>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-skip-slotting">
+ <div style="--foo: bar">
+ <template shadowrootmode="open">
+ <div style="--foo: baz">
+ <slot></slot>
+ </div>
+ </template>
+ <style>
+ @container style(--foo: bar) {
+ #t2 { color: green; }
+ }
+ </style>
+ <div id="t2"></div>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-slotted">
+ <div style="--foo: baz">
+ <template shadowrootmode="open">
+ <style>
+ @container style(--foo: bar) {
+ ::slotted(#t3) { color: green; }
+ }
+ </style>
+ <slot style="--foo: bar"></slot>
+ </template>
+ <div id="t3"></div>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-host" style="--foo: bar">
+ <div id="t4">
+ <template shadowrootmode="open">
+ <style>
+ @container style(--foo: bar) {
+ :host(#t4) { color: green; }
+ }
+ </style>
+ </template>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-part">
+ <div style="--foo: bar">
+ <template shadowrootmode="open">
+ <div style="--foo: baz">
+ <span id="t5" part="part"></span>
+ </div>
+ </template>
+ <style>
+ @container style(--foo: bar) {
+ #inclusive-ancestor-part > div::part(part) { color: green; }
+ }
+ </style>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-slotted-before">
+ <div>
+ <template shadowrootmode="open">
+ <style>
+ @container style(--foo: bar) {
+ ::slotted(#t6)::before {
+ content: "X";
+ color: green;
+ }
+ }
+ </style>
+ <slot style="--foo: bar"></slot>
+ </template>
+ <div id="t6" style="--foo: baz"></div>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-host-before">
+ <div id="t7" style="--foo: bar">
+ <template shadowrootmode="open">
+ <style>
+ @container style(--foo: bar) {
+ :host(#t7)::before {
+ content: "X";
+ color: green;
+ }
+ }
+ </style>
+ </template>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-part-before">
+ <style>
+ @container style(--foo: bar) {
+ #inclusive-ancestor-part-before > div::part(part)::before {
+ content: "X";
+ color: green;
+ }
+ }
+ </style>
+ <div style="--foo: bar">
+ <template shadowrootmode="open">
+ <div style="--foo: baz">
+ <span id="t8" part="part"></span>
+ </div>
+ </template>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-inner-part">
+ <style>
+ @container style(--foo: bar) {
+ #inclusive-ancestor-inner-part > div::part(inner-part) { color: green; }
+ }
+ </style>
+ <div style="--foo: bar">
+ <template shadowrootmode="open">
+ <div exportparts="inner-part" style="-foo: baz">
+ <template shadowrootmode="open">
+ <div style="--foo: baz">
+ <span id="t9" part="inner-part"></span>
+ </div>
+ </template>
+ </div>
+ </template>
+ </div>
+</div>
+
+<div id="inclusive-ancestor-slot-fallback">
+ <div><template shadowrootmode="open">
+ <style>
+ @container style(--foo: bar) {
+ #t10 { color: green; }
+ }
+ </style>
+ <div>
+ <slot style="--foo: bar"><span id="t10"></span></slot>
+ </div>
+ </template></div>
+</div>
+
+<div id="no-container-for-part">
+ <div>
+ <template shadowrootmode="open">
+ <style>
+ #t11 { color: green; }
+ </style>
+ <div style="--foo: bar">
+ <span id="t11" part="part"></span>
+ </div>
+ </template>
+ <style>
+ @container style(--foo: bar) {
+ #no-container-for-part > div::part(part) { color: red; }
+ }
+ </style>
+ </div>
+</div>
+
+<div id="inner-scope-host-part" style="--foo: bar">
+ <div>
+ <template shadowrootmode="open">
+ <style>
+ @container style(--foo: bar) {
+ :host::part(part) { color: green; }
+ }
+ </style>
+ <div style="--foo: baz">
+ <span id="t12" part="part"></span>
+ </div>
+ </template>
+ </div>
+</div>
+
+<script>
+ setup(() => {
+ assert_implements_container_queries();
+ });
+
+ const green = "rgb(0, 128, 0)";
+
+ test(() => {
+ const t1 = document.querySelector("#inclusive-ancestor-across-root > div").shadowRoot.querySelector("#t1");
+ assert_equals(getComputedStyle(t1).color, green);
+ }, "Match container in outer tree");
+
+ test(() => {
+ const t2 = document.querySelector("#t2");
+ assert_equals(getComputedStyle(t2).color, green);
+ }, "Match container in same tree, not walking flat tree ancestors");
+
+ test(() => {
+ const t3 = document.querySelector("#t3");
+ assert_equals(getComputedStyle(t3).color, green);
+ }, "Match container in ::slotted selector's originating element tree");
+
+ test(() => {
+ const t4 = document.querySelector("#t4");
+ assert_equals(getComputedStyle(t4).color, green);
+ }, "Match container in outer tree for :host");
+
+ test(() => {
+ const t5 = document.querySelector("#inclusive-ancestor-part > div").shadowRoot.querySelector("#t5");
+ assert_equals(getComputedStyle(t5).color, green);
+ }, "Match container in ::part selector's originating element tree");
+
+ test(() => {
+ const t6 = document.querySelector("#t6");
+ assert_equals(getComputedStyle(t6, "::before").color, green);
+ }, "Match container for ::before in ::slotted selector's originating element tree");
+
+ test(() => {
+ const t7 = document.querySelector("#t7");
+ assert_equals(getComputedStyle(t7, "::before").color, green);
+ }, "Match container in outer tree for :host::before");
+
+ test(() => {
+ const t8 = document.querySelector("#inclusive-ancestor-part-before > div").shadowRoot.querySelector("#t8");
+ assert_equals(getComputedStyle(t8, "::before").color, green);
+ }, "Match container for ::before in ::part selector's originating element tree");
+
+ test(() => {
+ const outerhost = document.querySelector("#inclusive-ancestor-inner-part > div");
+ const innerhost = outerhost.shadowRoot.querySelector("div");
+ const t9 = innerhost.shadowRoot.querySelector("#t9");
+ assert_equals(getComputedStyle(t9).color, green);
+ }, "Match container for ::part selector's originating element tree for exportparts");
+
+ test(() => {
+ const t10 = document.querySelector("#inclusive-ancestor-slot-fallback > div").shadowRoot.querySelector("#t10");
+ assert_equals(getComputedStyle(t10).color, green);
+ }, "Match container for slot light tree child fallback");
+
+ test(() => {
+ const t11 = document.querySelector("#no-container-for-part > div").shadowRoot.querySelector("#t11");
+ assert_equals(getComputedStyle(t11).color, green);
+ }, "Should not match container inside shadow tree for ::part()");
+
+ test(() => {
+ const t12 = document.querySelector("#inner-scope-host-part > div").shadowRoot.querySelector("#t12");
+ assert_equals(getComputedStyle(t12).color, green);
+ }, "A :host::part rule should match containers in the originating element tree");
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/style-container-invalidation-inheritance.html b/testing/web-platform/tests/css/css-contain/container-queries/style-container-invalidation-inheritance.html
new file mode 100644
index 0000000000..b7aef69d3e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/style-container-invalidation-inheritance.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<title>CSS Container Query Test: named style container query change with inherited custom property</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ container-name: container;
+ }
+ .match {
+ --match: true;
+ }
+ #inner {
+ color: red;
+ }
+ @container container style(--match: true) {
+ #inner {
+ color: green;
+ }
+ }
+</style>
+<div id="container">
+ <div id="outer">
+ <div id="inner"></div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(inner).color, "rgb(255, 0, 0)");
+ assert_equals(getComputedStyle(inner).getPropertyValue("--match"), "");
+ assert_equals(getComputedStyle(outer).getPropertyValue("--match"), "");
+ assert_equals(getComputedStyle(container).getPropertyValue("--match"), "");
+ }, "Pre-conditions");
+
+ test(() => {
+ container.className = "match";
+ assert_equals(getComputedStyle(inner).color, "rgb(0, 128, 0)");
+ assert_equals(getComputedStyle(inner).getPropertyValue("--match"), "true");
+ assert_equals(getComputedStyle(outer).getPropertyValue("--match"), "true");
+ assert_equals(getComputedStyle(container).getPropertyValue("--match"), "true");
+ }, "Changed --match inherits down descendants and affects container query");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/style-not-sharing-float.html b/testing/web-platform/tests/css/css-contain/container-queries/style-not-sharing-float.html
new file mode 100644
index 0000000000..7c76bb32bf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/style-not-sharing-float.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<title>CSS Container Queries Test: Check style is not sharing between cousins in the case of Container Queries</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ .float {
+ float: left;
+ width: 25px;
+ height: 25px;
+ }
+ .item {
+ container-type: inline-size;
+ height: 25px;
+ }
+ @container (width >= 50px) {
+ .item div { color: lime; }
+ }
+ @container (width >= 150px) {
+ .item div { color: green; }
+ }
+</style>
+<div style="width: 150px">
+ <div class="float"></div>
+ <div class="item">
+ <div id="target1"></div>
+ </div>
+ <div class="item">
+ <div id="target2"></div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(target1).color, "rgb(0, 255, 0)", "Second item container should be 100px wide");
+ assert_equals(getComputedStyle(target2).color, "rgb(0, 128, 0)", "First item container should be 200px wide");
+ }, "Check that style is not sharing in the case of Container Queries");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/style-query-with-unknown-width.html b/testing/web-platform/tests/css/css-contain/container-queries/style-query-with-unknown-width.html
new file mode 100644
index 0000000000..8b05d6c112
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/style-query-with-unknown-width.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>CSS Container Queries Test: style and size query against container without a principal box</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ container-type: inline-size;
+ display: contents;
+ --foo: bar;
+ }
+ @container (width >= 0px) or style(--foo: bar) {
+ #target { color: green; }
+ }
+</style>
+<div id="container">
+ <div id="target">Should be green</div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(target).color, "rgb(0, 128, 0)");
+ }, "width query should evaluate to unknown and style query to true");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/support/cq-testcommon.js b/testing/web-platform/tests/css/css-contain/container-queries/support/cq-testcommon.js
new file mode 100644
index 0000000000..2eaca1dd09
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/support/cq-testcommon.js
@@ -0,0 +1,3 @@
+function assert_implements_container_queries() {
+ assert_implements(CSS.supports("container-type:size"), "Basic support for container queries required");
+}
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/support/test.vtt b/testing/web-platform/tests/css/css-contain/container-queries/support/test.vtt
new file mode 100644
index 0000000000..ffd1d4ca44
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/support/test.vtt
@@ -0,0 +1,4 @@
+WEBVTT
+
+00:00:00.000 --> 00:00:10.000
+Sub-<b>title</b>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-child-container.html b/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-child-container.html
new file mode 100644
index 0000000000..898fc22c2b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-child-container.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<title>CSS Container Queries Test: size query container inside foreignObject</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ svg {
+ display: block;
+ width: 200px;
+ height: 200px;
+ container-type: size;
+ }
+ #container {
+ width: 100px;
+ height: 100px;
+ container-type: size;
+ }
+ @container (width = 100px) {
+ #inner { color: green; }
+ }
+</style>
+<svg>
+ <foreignObject>
+ <div id="container">
+ <div id="inner">Green</div>
+ </div>
+ </foreignObject>
+</svg>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const green = "rgb(0, 128, 0)";
+
+ test(() => {
+ assert_equals(getComputedStyle(inner).color, green);
+ }, "#inner querying #container inside foreignObject");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-no-size-container-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-no-size-container-ref.html
new file mode 100644
index 0000000000..abf1af122b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-no-size-container-ref.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<p>You should see the word PASS below and no red.</p>
+<svg><foreignObject style="width:100px;height:100px;"><div>PASS</div><foreignObject></svg>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-no-size-container.html b/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-no-size-container.html
new file mode 100644
index 0000000000..38fc493a16
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/svg-foreignobject-no-size-container.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<title>CSS Container Queries Test: SVG &lt;foreignObject&gt; element not a size query container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="match" href="svg-foreignobject-no-size-container-ref.html">
+<style>
+ foreignObject {
+ display: block;
+ width: 100px;
+ height: 100px;
+ container-type: size;
+ }
+ @supports not (container-type: size) {
+ div { color: red; }
+ }
+ @container (width = 100px) {
+ div { color: red; }
+ }
+</style>
+<p>You should see the word PASS below and no red.</p>
+<svg>
+ <foreignObject>
+ <div id="div">PASS</div>
+ </foreignObject>
+</svg>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/svg-g-no-size-container-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/svg-g-no-size-container-ref.html
new file mode 100644
index 0000000000..4f30c39939
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/svg-g-no-size-container-ref.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<p>You should see the word PASS below and no red.</p>
+<svg><text x="0" y="20" id="text">PASS</text></svg>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/svg-g-no-size-container.html b/testing/web-platform/tests/css/css-contain/container-queries/svg-g-no-size-container.html
new file mode 100644
index 0000000000..ed9e853676
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/svg-g-no-size-container.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>CSS Container Queries Test: SVG &lt;g&gt; element not a size query container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<link rel="match" href="svg-g-no-size-container-ref.html">
+<style>
+ g {
+ display: block;
+ width: 100px;
+ height: 100px;
+ container-type: size;
+ }
+
+ @supports not (container-type: size) {
+ text { fill: red; }
+ }
+ @container (width = 100px) {
+ text { fill: red; }
+ }
+</style>
+<p>You should see the word PASS below and no red.</p>
+<svg>
+ <g><text x="0" y="20" id="text">PASS</text></g>
+</svg>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/svg-root-size-container.html b/testing/web-platform/tests/css/css-contain/container-queries/svg-root-size-container.html
new file mode 100644
index 0000000000..70ce40c0bc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/svg-root-size-container.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<title>CSS Container Queries Test: SVG root as a size query container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ svg {
+ display: block;
+ width: 100px;
+ height: 100px;
+ container-type: size;
+ }
+ @container (width = 100px) {
+ #div, #text { color: green; }
+ }
+</style>
+<svg>
+ <text id="text">Green</text>
+ <foreignObject>
+ <div id="div">Green</div>
+ </foreignObject>
+</svg>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const green = "rgb(0, 128, 0)";
+
+ test(() => {
+ assert_equals(getComputedStyle(text).color, green);
+ }, "SVG text querying SVG root size container");
+
+ test(() => {
+ assert_equals(getComputedStyle(div).color, green);
+ }, "div in foreignObject querying SVG root size container");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/table-inside-container-changing-display-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/table-inside-container-changing-display-ref.html
new file mode 100644
index 0000000000..c0355d2f50
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/table-inside-container-changing-display-ref.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<p>You should see the word PASS below.</p>
+<table><td>PASS</td></table>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/table-inside-container-changing-display.html b/testing/web-platform/tests/css/css-contain/container-queries/table-inside-container-changing-display.html
new file mode 100644
index 0000000000..33a4f4fe72
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/table-inside-container-changing-display.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<title>CSS Container Queries Test: table inside @container changing display type</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<link rel="help" href="https://crbug.com/1284918">
+<link rel="match" href="table-inside-container-changing-display-ref.html">
+<style>
+ @supports not (container-type: inline-size) {
+ #container { display: none !important; }
+ }
+ #container {
+ width: 200px;
+ height: 200px;
+ container-type: inline-size;
+ }
+</style>
+<p>You should see the word PASS below.</p>
+<div id="container">
+ <div>
+ <table><td>PASS</td></table>
+ </div>
+</div>
+<script>
+ document.body.offsetTop;
+ document.querySelector("#container").style.display = "inline-block";
+ document.querySelector("table").style.color = "currentColor";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-backdrop-ref.html b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-backdrop-ref.html
new file mode 100644
index 0000000000..49c46974c9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-backdrop-ref.html
@@ -0,0 +1,3 @@
+<!doctype html>
+<html style="background:green">
+<title>CSS Test Reference</title>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-backdrop.html b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-backdrop.html
new file mode 100644
index 0000000000..25635167a5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-backdrop.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>CSS Container Queries Test: ::backdrop depending on @container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<link rel="match" href="top-layer-dialog-backdrop-ref.html">
+<style>
+ html { background: green; }
+ #container { container-type: inline-size; }
+ @container (max-width: 200px) {
+ ::backdrop { display: none; }
+ #dialog { visibility: hidden; }
+ }
+</style>
+<div id="container">
+ <dialog id="dialog"></dialog>
+</div>
+<script>
+ dialog.showModal();
+ dialog.offsetTop;
+ container.style.width = "100px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-container.html b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-container.html
new file mode 100644
index 0000000000..5627a6cea0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog-container.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<title>CSS Container Queries Test: Top layer element as a @container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #parent { width: 100px; }
+ #dialog {
+ container-type: inline-size;
+ width: auto;
+ border: none;
+ }
+ #child { color: red; }
+ @container (min-width: 200px) {
+ #child { color: green; }
+ }
+</style>
+<div id="parent">
+ <dialog id="dialog"><span id="child"></span></dialog>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(child).color, "rgb(255, 0, 0)");
+ }, "#dialog initially sized by #containing-block");
+
+ test(() => {
+ dialog.showModal();
+ assert_equals(getComputedStyle(child).color, "rgb(0, 128, 0)");
+ }, "#dialog sized by viewport");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog.html b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog.html
new file mode 100644
index 0000000000..9d18b1862d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-dialog.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<title>CSS Container Queries Test: @container with modal dialog child</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #container {
+ container-type: inline-size;
+ }
+ dialog {
+ color: red;
+ }
+ @container (max-width: 200px) {
+ dialog { color: green; }
+ }
+ @container (max-width: 100px) {
+ dialog { color: lime; }
+ }
+</style>
+<div id="container">
+ <dialog id="dialog"></dialog>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(dialog).color, "rgb(255, 0, 0)");
+ }, "#container initially wider than 200px");
+
+ test(() => {
+ container.style.width = "200px";
+ assert_equals(getComputedStyle(dialog).color, "rgb(0, 128, 0)");
+ }, "#container changed to 200px");
+
+ test(() => {
+ dialog.showModal();
+ assert_equals(getComputedStyle(dialog).color, "rgb(0, 128, 0)");
+ }, "Modal dialog still has parent as query container while in top layer");
+
+ test(() => {
+ container.style.width = "100px";
+ assert_equals(getComputedStyle(dialog).color, "rgb(0, 255, 0)");
+ }, "Container changes width while dialog is in top layer");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/top-layer-nested-dialog.html b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-nested-dialog.html
new file mode 100644
index 0000000000..1a6d573f24
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/top-layer-nested-dialog.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<title>CSS Container Queries Test: Nested top layer elements and @container</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ dialog { color: red; }
+ #container { width: 100px; }
+ #container, #outer { container-type: inline-size; }
+ @container (min-width: 200px) {
+ #outer { width: 400px; color: lime; }
+ }
+ @container (min-width: 400px) {
+ #inner { color: green; }
+ }
+</style>
+<div id="container">
+ <dialog id="outer">
+ <dialog id="inner"></dialog>
+ </dialog>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ assert_equals(getComputedStyle(outer).color, "rgb(255, 0, 0)");
+ assert_equals(getComputedStyle(inner).color, "rgb(255, 0, 0)");
+ }, "Dialogs initially not matching for container queries");
+
+ test(() => {
+ container.offsetTop;
+ outer.showModal();
+ inner.showModal();
+ assert_equals(getComputedStyle(outer).color, "rgb(255, 0, 0)");
+ assert_equals(getComputedStyle(inner).color, "rgb(255, 0, 0)");
+ }, "Dialogs still not matching after showModal");
+
+ test(() => {
+ container.offsetTop;
+ container.style.width = "200px";
+ assert_equals(getComputedStyle(outer).color, "rgb(0, 255, 0)");
+ assert_equals(getComputedStyle(inner).color, "rgb(0, 128, 0)");
+ }, "@container queries start matching");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/transition-scrollbars.html b/testing/web-platform/tests/css/css-contain/container-queries/transition-scrollbars.html
new file mode 100644
index 0000000000..60d82d26b4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/transition-scrollbars.html
@@ -0,0 +1,59 @@
+<!doctype html>
+<title>Container Queries - Scrollbars do not cause transitions</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#starting">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #scrollable {
+ overflow: auto;
+ width: 100px;
+ height: 100px;
+ }
+ #container {
+ container-type: inline-size;
+ }
+ #target {
+ background-color: black;
+ }
+
+ /* Matches with or without a scrollbar: */
+ @container (max-width: 100px) {
+ #target {
+ background-color: blue;
+ }
+ }
+
+ /* Matches only when there's a scrollbar: */
+ @container (max-width: 99px) {
+ #target {
+ background-color: green;
+ font-size: 10px;
+ transition: 2s steps(2, start) background-color;
+ }
+ }
+</style>
+<div id=scrollable>
+ <div id=container>
+ <div id=target>
+ Foo bar foo bar foo
+ Foo bar foo bar foo
+ Foo bar foo bar foo
+ Foo bar foo bar foo
+ Foo bar foo bar foo
+ </div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ // Whether or not a scrollbar appeared is out of scope for this test.
+ // The only thing we care about is that no transition was triggered.
+ // Therefore we allow both 'green' and 'blue', but not any other values.
+ let has_scrollbar = target.offsetWidth < 100;
+ let expected = has_scrollbar ? 'rgb(0, 128, 0)' : 'rgb(0, 0, 255)';
+ assert_equals(getComputedStyle(target).backgroundColor, expected);
+ }, 'Scrollbars do not cause a transition of background-color');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/transition-style-change-event-002.html b/testing/web-platform/tests/css/css-contain/container-queries/transition-style-change-event-002.html
new file mode 100644
index 0000000000..dc9297004d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/transition-style-change-event-002.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Container Queries - Style Change Event for transitions</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#starting">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ .container {
+ container-type: inline-size;
+ }
+ #outer {
+ width: 100px;
+ color: green;
+ }
+ #target {
+ transition: color 100s step-end;
+ }
+
+ @container (min-width: 200px) {
+ #inner { color: red; }
+ }
+ @container (min-width: 200px) {
+ #target {
+ /* This rule exists just to have a container query dependency between
+ target and #inner */
+ background-color: orange;
+ }
+ }
+</style>
+<div id="outer" class="container">
+ <div id="inner" class="container">
+ <div id="target">Green</div>
+ </div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ test(() => {
+ outer.offsetTop;
+ outer.style.width = "200px";
+ assert_equals(getComputedStyle(target).color, "rgb(0, 128, 0)");
+ }, "#inner color change to red triggers a step transition starting at green");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/transition-style-change-event.html b/testing/web-platform/tests/css/css-contain/container-queries/transition-style-change-event.html
new file mode 100644
index 0000000000..4cc1772979
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/transition-style-change-event.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Container Queries - Style Change Event for transitions</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#starting">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ .container { container-type: size }
+ #outer {
+ width: 100px;
+ color: green;
+ }
+ @container (min-width: 200px) {
+ #inner { color: red }
+ }
+ @container (min-width: 400px) {
+ #target {
+ color: green;
+ transition: color 1s step-start;
+ }
+ }
+</style>
+<div id="outer" class="container">
+ <div id="inner" class="container">
+ <div id="target">Green</div>
+ </div>
+</div>
+</div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const t = async_test("");
+ const event_handler = t.step_func_done((e) => {
+ assert_unreached("Transition event incorrectly triggered: " + e.type);
+ });
+ for (let event_name of ["transitionrun",
+ "transitionstart",
+ "transitionend",
+ "transitioncancel"]) {
+ target.addEventListener(event_name, event_handler);
+ }
+
+ outer.offsetTop;
+ // #target is green. Making the #outer container 200px will turn #inner and
+ // #target red through inheritance.
+ outer.style.width = "200px";
+ // Making #inner 400px will make #target green.
+ inner.style.width = "400px";
+ // Both changes above should happen in one style change event and should not
+ // trigger any transition events. Run two rAFs to make sure any events have
+ // time to trigger.
+ requestAnimationFrame(() => requestAnimationFrame(t.step_func_done(() => {
+ assert_equals(getComputedStyle(inner).color, "rgb(255, 0, 0)",
+ "@container queries supported");
+ })));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/unsupported-axis.html b/testing/web-platform/tests/css/css-contain/container-queries/unsupported-axis.html
new file mode 100644
index 0000000000..308de2f424
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/unsupported-axis.html
@@ -0,0 +1,228 @@
+<!doctype html>
+<title>Query against unsupported axis</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<script>
+ setup(() => assert_implements_container_queries());
+</script>
+
+<style>
+ #container {
+ width: 200px;
+ height: 100px;
+ container-type: inline-size;
+ }
+</style>
+
+<div id=container>
+ <div id=target>
+ Test
+ </div>
+</div>
+
+
+<style>
+ @container (width > 0px) {
+ #target { --width:true; }
+ }
+</style>
+<script>
+ test(function(t) {
+ assert_equals(getComputedStyle(target).getPropertyValue('--width'), 'true');
+ }, '(width > 0px)');
+</script>
+
+
+<style>
+ @container (height > 0px) {
+ #target { --height:true; }
+ }
+</style>
+<script>
+ test(function(t) {
+ // container-type:inline-size does not support queries along the block
+ // axis.
+ assert_equals(getComputedStyle(target).getPropertyValue('--height'), '');
+ }, '(height > 0px)');
+</script>
+
+
+<style>
+ @container ((height > 0px) or (width > 0px)) {
+ #target { --height-or-width:true; }
+ }
+</style>
+<script>
+ test(function(t) {
+ // (height > 0px) requires container-type:size.
+ assert_equals(getComputedStyle(target).getPropertyValue('--height-or-width'), '');
+ }, '((height > 0px) or (width > 0px))');
+</script>
+
+
+<style>
+ @container ((width > 0px) or (height > 0px)) {
+ #target { --width-or-height:true; }
+ }
+</style>
+<script>
+ test(function(t) {
+ // (height > 0px) requires container-type:size.
+ assert_equals(getComputedStyle(target).getPropertyValue('--width-or-height'), '');
+ }, '((width > 0px) or (height > 0px))');
+</script>
+
+<style>
+ @container ((orientation: landscape) or (width > 0px)) {
+ #target { --orientation-or-width:true; }
+ }
+</style>
+<script>
+ test(function(t) {
+ // (orientation: landscape) requires container-type:size.
+ assert_equals(getComputedStyle(target).getPropertyValue('--orientation-or-width'), '');
+ }, '((orientation: landscape) or (width > 0px))');
+</script>
+
+
+<style>
+ @container ((width > 0px) or (orientation: landscape)) {
+ #target { --width-or-orientation:true; }
+ }
+</style>
+<script>
+ test(function(t) {
+ // (orientation: landscape) requires container-type:size.
+ assert_equals(getComputedStyle(target).getPropertyValue('--width-or-orientation'), '');
+ }, '((width > 0px) or (orientation: landscape))');
+</script>
+
+
+<style>
+ @container ((height > 0px) or (orientation: landscape)) {
+ #target { --height-or-orientation:true; }
+ }
+</style>
+<script>
+ test(function(t) {
+ assert_equals(getComputedStyle(target).getPropertyValue('--height-or-orientation'), '');
+ }, '((height > 0px) or (orientation: landscape))');
+</script>
+
+
+<style>
+ @container ((height > 0px) or (orientation: landscape)) {
+ #target { --height-or-orientation2:true; }
+ }
+</style>
+<script>
+ test(function(t) {
+ // Adding full size containment via the 'contain' property does not
+ // make 'height' queryable. (Limited by container-type:inline-size).
+ t.add_cleanup(() => { target.style = ''; });
+ target.style.contain = 'size';
+ assert_equals(getComputedStyle(target).getPropertyValue('--height-or-orientation2'), '');
+ }, '((height > 0px) or (orientation: landscape)), with contain:size');
+</script>
+
+
+<style>
+ @container (inline-size > 0px) {
+ #target { --inline-size:true; }
+ }
+</style>
+<script>
+ test(function(t) {
+ assert_equals(getComputedStyle(target).getPropertyValue('--inline-size'), 'true');
+ }, '(inline-size > 0px)');
+</script>
+
+
+<style>
+ @container (block-size > 0px) {
+ #target { --block-size:true; }
+ }
+</style>
+<script>
+ test(function(t) {
+ // container-type:inline-size does not support queries along the block
+ // axis.
+ assert_equals(getComputedStyle(target).getPropertyValue('--block-size'), '');
+ }, '(block-size > 0px)');
+</script>
+
+
+<style>
+ @container (block-size > 0px) {
+ #target { --block-size2:true; }
+ }
+</style>
+<script>
+ test(function(t) {
+ // Changing the writing-mode does not affect the evaluation of block-size.
+ t.add_cleanup(() => { target.style = ''; });
+ target.style.writingMode = 'vertical-rl';
+ assert_equals(getComputedStyle(target).getPropertyValue('--block-size2'), '');
+ }, '(block-size > 0px), with writing-mode:vertical-rl');
+</script>
+
+
+<style>
+ @container not (width < 0px) {
+ #target { --not-width:true; }
+ }
+</style>
+<script>
+ test(function(t) {
+ assert_equals(getComputedStyle(target).getPropertyValue('--not-width'), 'true');
+ }, 'not (width < 0px)');
+</script>
+
+
+<style>
+ @container not (height < 0px) {
+ #target { --not-height:true; }
+ }
+</style>
+<script>
+ test(function(t) {
+ assert_equals(getComputedStyle(target).getPropertyValue('--not-height'), '');
+ }, 'not (height < 0px)');
+</script>
+
+
+<style>
+ @container not (inline-size < 0px) {
+ #target { --not-inline-size:true; }
+ }
+</style>
+<script>
+ test(function(t) {
+ assert_equals(getComputedStyle(target).getPropertyValue('--not-inline-size'), 'true');
+ }, 'not (inline-size < 0px)');
+</script>
+
+
+<style>
+ @container not (block-size < 0px) {
+ #target { --not-block-size:true; }
+ }
+</style>
+<script>
+ test(function(t) {
+ assert_equals(getComputedStyle(target).getPropertyValue('--not-block-size'), '');
+ }, 'not (block-size < 0px)');
+</script>
+
+<style>
+ @container not (orientation) {
+ #target { --not-orientation:true; }
+ }
+</style>
+<script>
+ test(function(t) {
+ assert_equals(getComputedStyle(target).getPropertyValue('--not-orientation'), '');
+ }, 'not (orientation)');
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/viewport-units-dynamic.html b/testing/web-platform/tests/css/css-contain/container-queries/viewport-units-dynamic.html
new file mode 100644
index 0000000000..2339533dee
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/viewport-units-dynamic.html
@@ -0,0 +1,59 @@
+<!doctype html>
+<title>CSS Container Queries Test: @container-dependent elements respond to viewport unit changes</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ iframe {
+ width: 100px;
+ height: 100px;
+ }
+</style>
+<iframe id="iframe" srcdoc="
+ <style>
+ #vw, #vh {
+ container-type: inline-size;
+ width: 100px;
+ }
+
+ @container (min-width: 50vw) {
+ #vw span { color: green }
+ }
+ @container (min-width: 100vw) {
+ #vw span { color: red }
+ }
+ @container (min-width: 50vh) {
+ #vh span { color: green }
+ }
+ @container (min-width: 100vh) {
+ #vh span { color: red }
+ }
+ </style>
+ <div id=vw><span>Green</span></div>
+ <div id=vh><span>Green</span></div>
+"></iframe>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ function waitForLoad(w) {
+ return new Promise(resolve => w.addEventListener('load', resolve));
+ }
+
+ promise_test(async () => {
+ await waitForLoad(window);
+ const vw_child = iframe.contentDocument.querySelector("#vw > span");
+ const vh_child = iframe.contentDocument.querySelector("#vh > span");
+
+ assert_equals(getComputedStyle(vw_child).color, "rgb(255, 0, 0)", "vw before resize");
+ assert_equals(getComputedStyle(vh_child).color, "rgb(255, 0, 0)", "vh before resize");
+
+ iframe.style.width = "200px";
+ assert_equals(getComputedStyle(vw_child).color, "rgb(0, 128, 0)", "vw after width resize");
+ assert_equals(getComputedStyle(vh_child).color, "rgb(255, 0, 0)", "vh after width resize");
+
+ iframe.style.height = "200px";
+ assert_equals(getComputedStyle(vw_child).color, "rgb(0, 128, 0)", "vw after height resize");
+ assert_equals(getComputedStyle(vh_child).color, "rgb(0, 128, 0)", "vh after height resize");
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/viewport-units.html b/testing/web-platform/tests/css/css-contain/container-queries/viewport-units.html
new file mode 100644
index 0000000000..9b8bb42c43
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/viewport-units.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<title>CSS Container Queries Test: viewport units</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+ #vw { container-type: inline-size; width: 10vw; }
+ #vh { container-type: inline-size; width: 10vh; }
+
+ @container (min-width: 10vw) {
+ #vw span { color: green }
+ }
+ @container (min-width: 11vw) {
+ #vw span { color: red }
+ }
+ @container (min-width: 10vh) {
+ #vh span { color: green }
+ }
+ @container (min-width: 11vh) {
+ #vh span { color: red }
+ }
+</style>
+<div id="vw"><span>Green</span></div>
+<div id="vh"><span>Green</span></div>
+<script>
+ setup(() => assert_implements_container_queries());
+
+ const green = "rgb(0, 128, 0)";
+
+ test(() => assert_equals(getComputedStyle(vw.firstChild).color, green), "Match width with vw");
+ test(() => assert_equals(getComputedStyle(vh.firstChild).color, green), "Match width with vh");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/container-queries/whitespace-update-after-removal.html b/testing/web-platform/tests/css/css-contain/container-queries/whitespace-update-after-removal.html
new file mode 100644
index 0000000000..a7df55efc6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/container-queries/whitespace-update-after-removal.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<title>CSS Container Queries Test: whitespace changes in container which changes evaluation</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
+<link rel="match" href="change-display-in-container-ref.html">
+<style>
+ #container {
+ container-type: size;
+ width: 400px;
+ height: 200px;
+ }
+
+ @container (min-width: 400px) {
+ span { color: red; }
+ }
+</style>
+<p>You should see the word PASS below.</p>
+<div id="container"><span id="fail">FAIL</span> <span>PASS</span></div>
+<script>
+ if (CSS.supports("container-type:size")) {
+ container.offsetTop;
+ container.style.width = "200px";
+ // The space text node between the two spans no longer takes up space when the
+ // first span is removed.
+ fail.remove();
+ }
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/WEB_FEATURES.yml b/testing/web-platform/tests/css/css-contain/content-visibility/WEB_FEATURES.yml
new file mode 100644
index 0000000000..345619e8b7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: content-visibility
+ files: "**"
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..279ffd002e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/animation-display-lock.html
@@ -0,0 +1,192 @@
+<!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;
+}
+
+function waitForEvent(element, eventName) {
+ return new Promise(resolve => element.addEventListener(eventName, resolve, { once: true }));
+}
+
+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 waitForEvent(target, 'animationiteration');
+ 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..fe48390a7c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-019.sub.https.html
@@ -0,0 +1,36 @@
+<!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>
+
+<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..38dbcd88bc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-020.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-020-ref.html">
+<meta name="assert" content="content-visibility hidden iframe does not paint">
+
+<script src="/common/reftest-wait.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..2c8f59d745
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-024.html
@@ -0,0 +1,47 @@
+<!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">
+<meta name="fuzzy" content="maxDifference=0-5; totalPixels=0-100">
+
+<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..6a8a1e2df0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-028.html
@@ -0,0 +1,63 @@
+<!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>
+
+<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..7cf7828a26
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-029.html
@@ -0,0 +1,26 @@
+<!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>
+
+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..d131c242bc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-031.html
@@ -0,0 +1,72 @@
+<!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;
+
+ function runTest() {
+ let resizeCallback = function (entries) {
+ didCallback = true;
+ }
+ let resizeObserver = new ResizeObserver(resizeCallback);
+
+ resizeObserver.observe(resize);
+
+ requestAnimationFrame(t.step_func(step2));
+ }
+
+ function step2() {
+ assert_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(t.step_func(step3));
+ }
+
+ function step3() {
+ assert_false(didCallback, 'ResizeObsever should not run during while unrendered');
+ requestAnimationFrame(t.step_func(step4));
+ }
+
+ function step4() {
+ assert_false(didCallback, 'ResizeObsever should not run while unrendered');
+ const container = document.getElementById("container");
+ container.classList.remove("hidden");
+ requestAnimationFrame(t.step_func_done(step5));
+ }
+
+ function step5() {
+ assert_true(didCallback, 'ResizeObsevers should now run once becoming visible');
+ }
+
+ window.onload = function() {
+ requestAnimationFrame(() => requestAnimationFrame(t.step_func(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..c2f62ca438
--- /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="button">
+</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..a7add41687
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-040.html
@@ -0,0 +1,44 @@
+<!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>
+
+<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..7a3f138d66
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-049.html
@@ -0,0 +1,42 @@
+<!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>
+
+<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..474d5c087a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-050.html
@@ -0,0 +1,40 @@
+<!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();
+ step_timeout(finish, 0);
+ }
+ function finish() {
+ 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..64ad854692
--- /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();
+ step_timeout(step2, 0);
+ }
+ // 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 keep the last rendered size, see
+ // https://github.com/w3c/csswg-drafts/issues/8407.
+ function step5() {
+ const r = container.getBoundingClientRect();
+ t.step(() => {
+ assert_equals(r.y, 3000, "step5 offset");
+ assert_equals(r.height, 10, "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..f43b603378
--- /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 keep the last rendered size, see
+ // https://github.com/w3c/csswg-drafts/issues/8407.
+ function step6() {
+ const r = container.getBoundingClientRect();
+ t.step(() => {
+ assert_equals(r.y, 3000, "step6 offset");
+ assert_equals(r.height, 10, "step6 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..6d33015466
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-075-ref.html
@@ -0,0 +1,38 @@
+<!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">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.small_child {
+ height: 10000px;
+}
+.large_child {
+ height: 40000px;
+ position: relative;
+}
+#target {
+ position: absolute;
+ bottom: 0;
+ font: 25px/1 Ahem;
+}
+</style>
+
+<div id=e1 class=auto><div class=large_child></div></div>
+<div id=e2 class=auto><div class=large_child></div></div>
+<div id=e3 class=auto><div class=large_child><div id=target>PASS</div></div></div>
+<div id=e4 class=auto><div class=large_child></div></div>
+<div id=e5 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..ade27bdfaa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-075.html
@@ -0,0 +1,45 @@
+<!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">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.auto {
+ content-visibility: auto;
+ contain-intrinsic-size: 1px 10000px;
+}
+.child {
+ height: 40000px;
+ position: relative;
+}
+#target {
+ position: absolute;
+ bottom: 0;
+ font: 25px/1 Ahem;
+}
+.before_target {
+ height: 40000px;
+}
+</style>
+
+<div id=e1 class="auto before_target"></div>
+<div id=e2 class="auto before_target"></div>
+<div id=e3 class=auto><div class=child><div id=target>PASS</div></div></div>
+<div id=e4 class=auto><div class=child></div></div>
+<div id=e5 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..2aadcde0c7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-076.html
@@ -0,0 +1,45 @@
+<!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">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.auto {
+ content-visibility: auto;
+ contain-intrinsic-size: 1px 10000px;
+}
+.child {
+ height: 40000px;
+ position: relative;
+}
+#target {
+ position: absolute;
+ bottom: 0;
+ font: 25px/1 Ahem;
+}
+.before_target {
+ height: 40000px;
+}
+</style>
+
+<div class="auto before_target"></div>
+<div class="auto before_target"></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..9f2c69e9cf
--- /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 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 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, "auto");
+}, "Content-visibility is 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..c4c1bb3beb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-079-ref.html
@@ -0,0 +1,14 @@
+<!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">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ div {
+ font: 25px/1 Ahem;
+ }
+</style>
+<p>Test passes if you see a black rectangle 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..c2cbbfb5a3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-079.html
@@ -0,0 +1,20 @@
+<!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">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.auto {
+ content-visibility: auto;
+ font: 25px/1 Ahem;
+}
+.overflow { overflow: hidden; }
+</style>
+
+<p>Test passes if you see a black rectangle 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-085.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-085.html
new file mode 100644
index 0000000000..b451746bbb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-085.html
@@ -0,0 +1,39 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: auto with content changes</title>
+<link rel="author" title="Cathie Chen" href="mailto:cathiechen@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="content-visibility auto element should be resized when content changes">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.auto {
+ content-visibility: auto;
+ width: fit-content;
+}
+.hidden { height: 0; }
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="auto">
+ <div id ="target" class="hidden">
+ <div style="width: 100px; height: 100px; background-color: green;"></div>
+ </div>
+</div>
+
+<script>
+function changeContent() {
+ requestAnimationFrame(() => {
+ target.classList.toggle("hidden");
+ requestAnimationFrame(takeScreenshot);
+ });
+}
+function runTest() {
+ requestAnimationFrame(changeContent);
+}
+
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-086.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-086.html
new file mode 100644
index 0000000000..b636e29415
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-086.html
@@ -0,0 +1,42 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: innerText</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="innerText is empty for skipped content due to content-visibility auto">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="container">
+This text should be visible.
+<div style="content-visibility: auto">
+ This text should be visible.
+ <div id="inner">This text is also visible.<br/>
+ </div>
+</div>
+<div id=spacer style="height: 300vh"></div>
+<div style="content-visibility: auto">
+ This text should not be visible.
+ <div id="inner2">
+ This text is also not visible.
+ </div>
+</div>
+</div>
+
+<script>
+async_test((t) => {
+ function step1() {
+ t.step(() => {
+ assert_equals(document.getElementById("container").innerText, "This text should be visible.\nThis text should be visible.\nThis text is also visible.\n");
+ assert_equals(document.getElementById("inner").innerText, "This text is also visible.\n");
+ assert_equals(document.getElementById("inner2").innerText, "");
+ });
+ t.done();
+ }
+
+ requestAnimationFrame(() => requestAnimationFrame(step1));
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-087.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-087.html
new file mode 100644
index 0000000000..f2faa45774
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-087.html
@@ -0,0 +1,26 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content visibility: focus does not target nested c-v: hidden/auto subtree"</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="focus does not target nested c-v: hidden/auto subtree">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div style="content-visibility: hidden">
+ <div style="content-visibility: auto">
+ <div id="focusable" tabIndex="0">
+ focusable thing
+ </div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ focusable.focus();
+ assert_not_equals(document.activeElement, focusable);
+}, "Trying to focus on an element in a nested hidden/auto subtree will not work");
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-088.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-088.html
new file mode 100644
index 0000000000..1d1b549594
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-088.html
@@ -0,0 +1,46 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: getClientRects measures correctly</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="getClientRects measures correctly in content-visibility hidden subtree">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body {
+ margin: 0;
+ padding: 0;
+}
+#outer {
+ width: 100px;
+ background: lightblue;
+
+ content-visibility: hidden;
+}
+#inner {
+ margin: 25px;
+ width: 50px;
+ height: 50px;
+ background: lightgreen;
+}
+</style>
+
+<body>
+<div id="outer"><div id="inner"></div></div>
+</body>
+
+<script>
+test(() => {
+ const outer = document.getElementById("outer");
+ assert_equals(outer.getClientRects()[0].height, 0, "outer height");
+
+ const inner = document.getElementById("inner");
+ assert_equals(inner.getClientRects()[0].width, 50, "inner width");
+ assert_equals(inner.getClientRects()[0].height, 50, "inner height");
+});
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-089.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-089.html
new file mode 100644
index 0000000000..b7e4d90299
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-089.html
@@ -0,0 +1,48 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: clientLeft/clientTop/clientWidth/clientHeight measure correctly</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="clientLeft/clientTop/clientWidth/clientHeight measure correctly in content-visibility hidden 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 {
+ border-left: 25px black solid;
+ border-top: 25px black solid;
+ margin: 25px;
+ width: 50px;
+ height: 50px;
+ background: lightgreen;
+}
+</style>
+
+<body>
+<div id="outer"><div id="inner"></div></div>
+</body>
+
+<script>
+test(() => {
+ const inner = document.getElementById("inner");
+ assert_equals(inner.clientLeft, 25, "left");
+ assert_equals(inner.clientTop, 25, "top");
+ assert_equals(inner.clientWidth, 50, "width");
+ assert_equals(inner.clientHeight, 50, "height");
+});
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-090.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-090.html
new file mode 100644
index 0000000000..4d90d0611c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-090.html
@@ -0,0 +1,51 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: scrollLeft/scrollTop/scrollWidth/scrollHeight measure correctly</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="scrollLeft/scrollTop/scrollWidth/scrollHeight measure correctly in content-visibility hidden 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;
+ overflow: scroll;
+
+ content-visibility: hidden;
+}
+#inner {
+ margin: 25px;
+ width: 250px;
+ height: 250px;
+ background: lightgreen;
+}
+</style>
+
+<body>
+<div id="outer"><div id="inner"></div></div>
+</body>
+
+<script>
+test(() => {
+ const outer = document.getElementById("outer");
+
+ outer.scrollLeft = 25;
+ assert_equals(outer.scrollLeft, 25, "left");
+ assert_equals(outer.scrollWidth, 275, "width");
+
+ outer.scrollTop = 25;
+ assert_equals(outer.scrollTop, 25, "top");
+ assert_equals(outer.scrollHeight, 300, "height");
+});
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-091.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-091.html
new file mode 100644
index 0000000000..f6799693eb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-091.html
@@ -0,0 +1,24 @@
+<!doctype HTML>
+<meta charset="utf8">
+<title>CSS Content Visibility: getComputedStyle works in hidden c-v subtree</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="getComputedStyle works in hidden c-v subtree">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+#container { content-visibility: hidden }
+</style>
+
+<div id=container style="width:200px">
+<div id=target style="width:50%"></div>
+</div>
+
+<script>
+test(() => {
+ const computedStyle = getComputedStyle(target);
+ assert_equals(computedStyle.width, "100px");
+}, "getComputedStyle works in hidden c-v subtree");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-092.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-092.html
new file mode 100644
index 0000000000..3d5482d59c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-092.html
@@ -0,0 +1,24 @@
+<!doctype HTML>
+<meta charset="utf8">
+<title>CSS Content Visibility: getComputedStyle works in hidden c-v subtree and an absolutely positioned element</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="getComputedStyle works in hidden c-v subtree and an absolutely positioned element">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+#container { content-visibility: hidden }
+</style>
+
+<div id=container style="width:200px">
+<div id=target style="width:50%;position: absolute"></div>
+</div>
+
+<script>
+test(() => {
+ const computedStyle = getComputedStyle(target);
+ assert_equals(computedStyle.width, "100px");
+}, "getComputedStyle works in hidden c-v subtree and an absolutely positioned element");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-093.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-093.html
new file mode 100644
index 0000000000..a54fa407cb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-093.html
@@ -0,0 +1,24 @@
+<!doctype HTML>
+<meta charset="utf8">
+<title>CSS Content Visibility: getComputedStyle works on a grid container with c-v: hidden and an absolutely positioned child</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="getComputedStyle works on a grid container with c-v: hidden and an absolutely positioned child">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+#container { content-visibility: hidden }
+</style>
+
+<div id=container style="display: grid; width:200px">
+<div id=target style="width:50%;position: absolute"></div>
+</div>
+
+<script>
+test(() => {
+ const computedStyle = getComputedStyle(target);
+ assert_equals(computedStyle.width, "100px");
+}, "getComputedStyle works on a grid container with c-v: hidden and an absolutely positioned child");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-094-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-094-ref.html
new file mode 100644
index 0000000000..a377fc6641
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-094-ref.html
@@ -0,0 +1,23 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hidden effect on table types (reference)</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+
+<style>
+table {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+</style>
+
+<table id=table>
+ <tr id=tr>
+ <td id=td>
+ <div>Test passes if this text is visible.</div>
+ </td>
+ </tr>
+</table>
+
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-094.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-094.html
new file mode 100644
index 0000000000..0434530298
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-094.html
@@ -0,0 +1,44 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: hidden effect on table types</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-094-ref.html">
+<meta name="assert" content="content-visibility: hidden effect on table types">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+table {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<table id=table>
+ <caption id=caption>
+ <div>Test fails if this text is visible.</div>
+ </caption>
+ <tr id=tr>
+ <td id=td>
+ <div>Test passes if this text is visible.</div>
+ </td>
+ </tr>
+</table>
+
+<script>
+function runTest() {
+ document.getElementById("table").classList.add("hidden");
+ document.getElementById("tr").classList.add("hidden");
+ document.getElementById("caption").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-095-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-095-ref.html
new file mode 100644
index 0000000000..3e7d8cd92b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-095-ref.html
@@ -0,0 +1,24 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: hidden table with positioned children (reference)</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+
+<style>
+#table {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+ contain: content;
+}
+#positioned {
+ position: absolute;
+}
+</style>
+
+<table id=table>
+ <td>
+ <div id=positioned>Test passes if this text is visible.</div>
+ </td>
+</table>
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-095.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-095.html
new file mode 100644
index 0000000000..245a8dd827
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-095.html
@@ -0,0 +1,47 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: hidden table with positioned children</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-095-ref.html">
+<meta name="assert" content="content-visibility: hidden table with positioned children">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+table {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+}
+#positioned {
+ position: absolute;
+}
+.hidden {
+ content-visibility: hidden;
+}
+</style>
+
+<table id=table>
+ <caption id=caption>
+ <div id=positioned>Test fails if this text is visible.</div>
+ </caption>
+ <tr id=tr>
+ <td id=td>
+ <div id=positioned>Test passes if this text is visible.</div>
+ </td>
+ </tr>
+</table>
+
+<script>
+function runTest() {
+ document.getElementById("table").classList.add("hidden");
+ document.getElementById("tr").classList.add("hidden");
+ document.getElementById("caption").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-096-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-096-ref.html
new file mode 100644
index 0000000000..5b013f6e1a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-096-ref.html
@@ -0,0 +1,36 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: auto, scroll away and back (Reference)</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ height: 10000px;
+}
+#child {
+ width: 100px;
+ height: 100px;
+ background: green;
+ position: relative
+}
+#target {
+ width: 10px;
+ height: 10px;
+}
+
+</style>
+
+<div>
+ <div id=child></div>
+</div>
+<div class=spacer></div>
+<div id=target></div>
+
+<script>
+ requestAnimationFrame(takeScreenshot);
+</script>
+
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-096.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-096.html
new file mode 100644
index 0000000000..1d1a26c680
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-096.html
@@ -0,0 +1,56 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: auto, scroll away and back</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-096-ref.html">
+<meta name="assert" content="scolling away from c-v: auto container and back renders as expected">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ height: 10000px;
+}
+#child {
+ width: 100px;
+ height: 100px;
+ background: green;
+ position: relative
+}
+#target {
+ width: 10px;
+ height: 10px;
+}
+.auto { content-visibility: auto; }
+
+</style>
+
+<div class="auto">
+ <div id=child></div>
+</div>
+<div class=spacer></div>
+<div id=target></div>
+
+<script>
+
+function runTest() {
+ document.getElementById("target").scrollIntoView(true /* alignToTop */);
+ requestAnimationFrame(finishTest);
+}
+
+function finishTest() {
+ scrollTo(0, 0);
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ runTest();
+ });
+ });
+});
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-097-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-097-ref.html
new file mode 100644
index 0000000000..5b013f6e1a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-097-ref.html
@@ -0,0 +1,36 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: auto, scroll away and back (Reference)</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ height: 10000px;
+}
+#child {
+ width: 100px;
+ height: 100px;
+ background: green;
+ position: relative
+}
+#target {
+ width: 10px;
+ height: 10px;
+}
+
+</style>
+
+<div>
+ <div id=child></div>
+</div>
+<div class=spacer></div>
+<div id=target></div>
+
+<script>
+ requestAnimationFrame(takeScreenshot);
+</script>
+
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-097.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-097.html
new file mode 100644
index 0000000000..5548f480f6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-097.html
@@ -0,0 +1,60 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: auto, scroll away and back while toggling visibility</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-097-ref.html">
+<meta name="assert" content="scolling away from c-v: auto container and back while toggling visibility renders as expected">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ height: 10000px;
+}
+#child {
+ width: 100px;
+ height: 100px;
+ background: green;
+ position: relative
+}
+#target {
+ width: 10px;
+ height: 10px;
+}
+</style>
+
+<div id="container" style="content-visibility: auto">
+ <div id=child></div>
+</div>
+<div class=spacer></div>
+<div id=target></div>
+
+<script>
+
+function step1() {
+ document.getElementById("target").scrollIntoView(true /* alignToTop */);
+ requestAnimationFrame(step2);
+}
+
+function step2() {
+ container.style.visibility = "hidden";
+ requestAnimationFrame(finishTest);
+}
+
+function finishTest() {
+ container.setAttribute("style", "content-visibility: visible; visibility: visible");
+ window.scrollTo(0, 0);
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ step1();
+ });
+ });
+});
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-098.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-098.html
new file mode 100644
index 0000000000..6494ad4a38
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-098.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="Rob Buis" href="mailto:rbuis@igalia.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 (through both c-v and visibility properties) 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;
+}
+#autocontainer { content-visibility: auto; }
+
+</style>
+
+<div id=container>
+ <div id="autocontainer">
+ Test fails if you see this text or a red box.
+ <div id=child></div>
+ </div>
+</div>
+
+<script>
+
+function runTest() {
+ document.getElementById("autocontainer").classList.remove("auto");
+ document.getElementById("autocontainer").classList.add("hidden");
+ document.getElementById("autocontainer").style.visibility = "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-099-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-099-ref.html
new file mode 100644
index 0000000000..7ab3094c31
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-099-ref.html
@@ -0,0 +1,37 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: auto, make unskipped, then skipped while also toggling visibility (Reference)</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ height: 10000px;
+}
+#child {
+ width: 100px;
+ height: 0px;
+ background: green;
+ position: relative
+}
+#target {
+ width: 10px;
+ height: 10px;
+}
+
+</style>
+
+<div>
+ <div id=child></div>
+</div>
+<div class=spacer></div>
+<div id=target></div>
+
+<script>
+ document.getElementById("target").scrollIntoView(true /* alignToTop */);
+ requestAnimationFrame(takeScreenshot);
+</script>
+
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-099.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-099.html
new file mode 100644
index 0000000000..1abff2b9be
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-099.html
@@ -0,0 +1,59 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: auto, make unskipped, then skipped while also toggling visibility</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-099-ref.html">
+<meta name="assert" content="making c-v: auto container unskipped and then skipped while toggling visibility renders as expected">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.spacer {
+ height: 10000px;
+}
+#child {
+ width: 100px;
+ height: 100px;
+ background: green;
+ position: relative
+}
+#target {
+ width: 10px;
+ height: 10px;
+}
+</style>
+
+<div id="container" style="content-visibility: auto">
+ <div id=child></div>
+</div>
+<div class=spacer></div>
+<div id=target></div>
+
+<script>
+
+function step1() {
+ target.focus();
+ requestAnimationFrame(step2);
+}
+
+function step2() {
+ document.getElementById("target").scrollIntoView(true /* alignToTop */);
+ requestAnimationFrame(finishTest);
+}
+
+function finishTest() {
+ container.setAttribute("style", "content-visibility: hidden; visibility: hidden");
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ step1();
+ });
+ });
+});
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-and-scroll-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-and-scroll-ref.html
new file mode 100644
index 0000000000..548970812b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-and-scroll-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<title>Test that scrolling to a content-visibility: auto subtree restarts animations in it</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/">
+
+<style>
+#target {
+ position: relative;
+ background: green;
+ height: 100px;
+ width: 100px;
+ left: 100px;
+}
+</style>
+<body>
+ <div id="container">
+ <div id="target"></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-and-scroll.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-and-scroll.html
new file mode 100644
index 0000000000..3900918819
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-and-scroll.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Test that scrolling to a content-visibility: auto subtree restarts animations in it</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/">
+<link rel="match" href="content-visibility-animation-and-scroll-ref.html">
+<meta name="assert" content="animations in content-visibility: auto subtree should restart when scrolled to">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ content-visibility: auto;
+ contain-intrinsic-size: 100px 100px;
+}
+@keyframes unfade {
+ from { opacity: 0; transform: none; }
+ to { opacity: 1; transform: translate(100px); }
+}
+#target {
+ background: green;
+ height: 100px;
+ width: 100px;
+}
+.animate {
+ animation: unfade 1s linear 1 alternate;
+ animation-fill-mode: forwards;
+}
+#spacer {
+ height: 300vh;
+}
+</style>
+<body>
+ <div id="spacer"></div>
+ <div id="container"></div>
+</body>
+
+<script>
+function createAnimatingElement(name) {
+ const container = document.getElementById('container');
+ const target = document.createElement('div');
+ container.appendChild(target);
+ target.id = 'target';
+ target.className = name;
+ return target;
+}
+
+function runTest() {
+ const container = document.getElementById('container');
+ const target = createAnimatingElement('animate');
+ container.scrollIntoView(true /* alignToTop */);
+ const listener = (e) => {
+ spacer.style.height = "0px";
+ takeScreenshot();
+ };
+
+ target.addEventListener("animationend", listener);
+}
+window.onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-becomes-visible-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-becomes-visible-ref.html
new file mode 100644
index 0000000000..f927a02ca8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-becomes-visible-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<title>Test that making a content-visibility: hidden subtree visible restarts animations in it</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/">
+
+<style>
+#target {
+ position: relative;
+ background: green;
+ height: 100px;
+ width: 100px;
+ left: 100px;
+}
+</style>
+<body>
+ <div id="target"</div>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-becomes-visible.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-becomes-visible.html
new file mode 100644
index 0000000000..53976c651a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-becomes-visible.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Test that making a content-visibility: hidden subtree visible restarts animations in it</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/">
+<link rel="match" href="content-visibility-animation-becomes-visible-ref.html">
+<meta name="assert" content="animations in content-visibility: hidden subtree should restart once visible">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ content-visibility: hidden;
+}
+@keyframes fade {
+ from { opacity: 0; transform: none; }
+ to { opacity: 1; transform: translate(100px); }
+}
+#target {
+ background: green;
+ height: 100px;
+ width: 100px;
+}
+.animate {
+ animation: fade 1s linear 1 alternate;
+ animation-fill-mode: forwards;
+}
+</style>
+<body>
+ <div id="container"></div>
+</body>
+
+<script>
+function createAnimatingElement(name) {
+ const container = document.getElementById('container');
+ const target = document.createElement('div');
+ container.appendChild(target);
+ target.id = 'target';
+ target.className = name;
+ return target;
+}
+
+function runTest() {
+ const container = document.getElementById('container');
+ const target = createAnimatingElement('animate');
+ container.style.contentVisibility = "visible";
+ const listener = (e) => {
+ takeScreenshot();
+ };
+
+ target.addEventListener("animationend", listener);
+}
+window.onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-in-auto-subtree.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-in-auto-subtree.html
new file mode 100644
index 0000000000..690b49255f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-in-auto-subtree.html
@@ -0,0 +1,239 @@
+<!DOCTYPE html>
+<meta charset=utf8>
+<title>Test getComputedStyle on a CSS animation in a content visibility subtree using content-visibility: auto</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: auto;
+}
+@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="spacer"></div>
+ <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;
+ const animation = target.getAnimations()[0];
+ await animation.ready;
+ await waitForAnimationFrames(1);
+ document.getElementById("spacer").style.height = "300vh";
+ await waitForAnimationFrames(1);
+ target.addEventListener('animationiteration', () => {
+ animationIterationEvent = true;
+ });
+ 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 ' +
+ 'content visibility subtree');
+ await waitForAnimationFrames(2);
+ assert_false(animationIterationEvent,
+ 'Animation events do not fire while the animation is ' +
+ 'running in a content visibility subtree');
+ document.getElementById("spacer").style.height = "0vh";
+ await waitForAnimationFrames(2);
+ assert_true(animationIterationEvent,
+ 'The animationiteration event fires once the animation is ' +
+ 'no longer content visibility');
+}, 'Animation events do not fire for a CSS animation running in a content ' +
+ 'visibility 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(target).height == '0px';
+ });
+ await waitForAnimationFrames(1);
+ document.getElementById("spacer").style.height = "300vh";
+ // 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 content visibility subtree');
+ // Advancing frames should not resolve the finished promise.
+ await waitForAnimationFrames(3);
+ document.getElementById("spacer").style.height = "0vh";
+ // 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 content visibility 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(target).height == '0px';
+ });
+ await waitForAnimationFrames(1);
+ document.getElementById("spacer").style.height = "300vh";
+ // 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 content visibility subtree');
+ // Advancing frames should not resolve the finished promise.
+ await waitForAnimationFrames(3);
+ document.getElementById("spacer").style.height = "0vh";
+ // 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 content visibility subtree');
+
+promise_test(async t => {
+ const container = document.getElementById('container');
+ const target = createAnimatingElement(t, 'animate');
+ const animation = target.getAnimations()[0];
+ target.className = '';
+ document.getElementById("spacer").style.height = "300vh";
+ 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 content visibility 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 content visibility subtree if ' +
+ 'no owning element');
+ assert_true(animationFinished,
+ 'Finished promise not blocked on content visibility subtree 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');
+
+promise_test(async t => {
+ // The animation is hidden when it is created.
+ document.getElementById("spacer").style.height = "300vh";
+ const container = document.getElementById('container');
+ const target = createAnimatingElement(t, 'animate');
+ const animation = target.getAnimations()[0];
+ await waitForAnimationFrames(2);
+ // Make this animation no longer associated with its owning element.
+ target.className = '';
+ 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 content visibility 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 content visibility subtree if ' +
+ 'no owning element');
+ assert_true(animationFinished,
+ 'Finished promise not blocked on content visibility subtree if ' +
+ 'no owning element');
+ assert_false(cssAnimationEndEvent,
+ 'CSS animation events should not be dispatched if there is no ' +
+ 'owning element');
+}, 'CSS animations without an owning element should handle events and promises ' +
+ 'normally, even c-v value does change');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-auto-subtree.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-auto-subtree.html
new file mode 100644
index 0000000000..0d9bde7d75
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-auto-subtree.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<meta charset=utf8>
+<title>Test getComputedStyle on a CSS animation with scroll timeline in a content visibility subtree using content-visibility: auto</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: auto;
+}
+
+#scrollContainer {
+ height: 100vh;
+ overflow-y: scroll;
+ scroll-timeline-name: --targetTimeline;
+}
+#innerspacer {
+ height: 300vh;
+}
+@keyframes fade {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+#target {
+ background: green;
+ height: 100px;
+ width: 100px;
+}
+.animate {
+ animation-name: fade;
+ animation-duration: 1ms;
+ animation-direction: alternate;
+ animation-timeline: --targetTimeline;
+}
+
+</style>
+<body>
+ <div id="log"></div>
+ <div id="spacer"></div>
+ <div id="scrollContainer">
+ <div id="container"></div>
+ <div id="innerspacer"></div>
+ </div>
+
+</body>
+<script>
+"use strict";
+
+function createAnimatingElement(test, name) {
+ const container = document.getElementById('container');
+ const target = document.createElement('div');
+ container.appendChild(target);
+ target.id = 'target';
+ target.className = name;
+ return target;
+}
+
+promise_test(async t => {
+ const container = document.getElementById('container');
+ const target = createAnimatingElement(t, 'animate');
+ scrollContainer.scrollTop = 10000;
+ const animation = target.getAnimations()[0];
+ await animation.ready;
+ await waitForAnimationFrames(1);
+ let expectedOpacity = parseFloat(getComputedStyle(target).opacity);
+ assert_approx_equals(expectedOpacity, 0, 0.1, 'scrollContainer scrolls to bottom, so the opacity should be 0');
+ document.getElementById('spacer').style.height = '300vh';
+ await waitForAnimationFrames(1);
+ assert_equals(parseFloat(getComputedStyle(target).opacity), expectedOpacity, 'Opacity does not change when it is hidden by c-v');
+
+ scrollContainer.scrollTop = 0;
+ assert_equals(parseFloat(getComputedStyle(target).opacity), expectedOpacity, 'The animation is hidden by c-v, so opacity does not change even if scrollTop changes');
+
+ await waitForAnimationFrames(2);
+
+ document.getElementById('spacer').style.height = '0vh';
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(target).opacity, '1', 'Now that the animation is visible, opacity should be updated');
+}, 'Animation with scroll-timeline should be affected c-v');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-hidden-subtree.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-hidden-subtree.html
new file mode 100644
index 0000000000..af29a200f1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-hidden-subtree.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<meta charset=utf8>
+<title>Test getComputedStyle on a CSS animation with scroll-timeline in a content-visibility 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;
+}
+
+#scrollContainer {
+ height: 100vh;
+ overflow-y: scroll;
+ scroll-timeline-name: --targetTimeline;
+}
+#innerspacer {
+ height: 300vh;
+}
+@keyframes fade {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+#target {
+ background: green;
+ height: 100px;
+ width: 100px;
+}
+.animate {
+ animation-name: fade;
+ animation-duration: 1ms;
+ animation-direction: alternate;
+ animation-timeline: --targetTimeline;
+}
+
+</style>
+<body>
+ <div id="log"></div>
+ <div id="scrollContainer">
+ <div id="container"></div>
+ <div id="innerspacer"></div>
+ </div>
+
+</body>
+<script>
+"use strict";
+
+function createAnimatingElement(test, name) {
+ const container = document.getElementById('container');
+ const target = document.createElement('div');
+ container.appendChild(target);
+ target.id = 'target';
+ target.className = name;
+ return target;
+}
+
+promise_test(async t => {
+ const container = document.getElementById('container');
+ const target = createAnimatingElement(t, 'animate');
+ scrollContainer.scrollTop = 10000;
+ const animation = target.getAnimations()[0];
+ await animation.ready;
+ await waitForAnimationFrames(1);
+ let expectedOpacity = parseFloat(getComputedStyle(target).opacity);
+ assert_approx_equals(expectedOpacity, 0, 0.1, 'scrollContainer scrolls to bottom, so the opacity should be 0');
+ document.getElementById('container').style.contentVisibility = 'hidden';
+ await waitForAnimationFrames(1);
+ assert_equals(parseFloat(getComputedStyle(target).opacity), expectedOpacity, 'Opacity does not change when it is hidden by c-v');
+
+ scrollContainer.scrollTop = 0;
+ assert_equals(parseFloat(getComputedStyle(target).opacity), expectedOpacity, 'The animation is hidden by c-v, so opacity does not change even if scrollTop changes');
+
+ await waitForAnimationFrames(2);
+
+ document.getElementById('container').style.contentVisibility = 'visible';
+ await waitForAnimationFrames(2);
+ assert_approx_equals(parseFloat(getComputedStyle(target).opacity), 1, 0.1, 'Now that the animation is visible, opacity should be updated');
+}, 'Animation with scroll-timeline should be affected c-v');
+
+</script>
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-first-observation-immediate.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-first-observation-immediate.html
new file mode 100644
index 0000000000..5a177d6ea9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-first-observation-immediate.html
@@ -0,0 +1,53 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: first visibility determination happens before resize observer.</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="first visibility determination happens before resize observer">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+#target {
+ content-visibility: auto;
+ contain-intrinsic-size: 10px;
+}
+#child {
+ height: 100px;
+}
+</style>
+
+<div id=container></div>
+
+<script>
+promise_test(t => new Promise(async (resolve, reject) => {
+ requestAnimationFrame(() => {
+ let target = document.createElement("div");
+ target.id = "target";
+
+ let child = document.createElement("div");
+ child.id = "child";
+ target.appendChild(child);
+
+ const resizeObserver = new ResizeObserver((entries) => {
+ for (const entry of entries) {
+ if (entry.contentBoxSize) {
+ if (entry.contentBoxSize[0].blockSize == 100) {
+ resolve();
+ return;
+ } else {
+ reject(`unexpected size ${entry.contentBoxSize[0].blockSize}`);
+ return;
+ }
+ }
+ }
+ reject("no content boxes or no entries");
+ });
+
+ container.appendChild(target);
+ resizeObserver.observe(target);
+ });
+}), "Target is sized and laid out before resize observer");
+</script>
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-nested-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-nested-ref.html
new file mode 100644
index 0000000000..bc00c86b8b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-nested-ref.html
@@ -0,0 +1,10 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content Visibility: content in nested `content-visibility: auto` elements is considered relevant</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<div style="border:solid">
+ <div>content with content-visibility: auto</div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-nested-scroll-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-nested-scroll-ref.html
new file mode 100644
index 0000000000..aad9b9b73e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-nested-scroll-ref.html
@@ -0,0 +1,33 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: content in nested `content-visibility: auto` element can be scrolled to</title>
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#outer {
+ width: 400px;
+ height: 400px;
+ contain: layout paint size;
+}
+
+#inner {
+ position: relative;
+ top: 100px;
+ width: 100px;
+ height: 100px;
+}
+</style>
+
+<div style="height:100vh"></div>
+<div id="outer" style="border:solid">
+ <div id="inner" >content with content-visibility: auto</div>
+</div>
+
+<script>
+function runTest() {
+ inner.scrollIntoView();
+ requestAnimationFrame(takeScreenshot);
+}
+window.onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-nested-scroll.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-nested-scroll.html
new file mode 100644
index 0000000000..ced9d79ec6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-nested-scroll.html
@@ -0,0 +1,40 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: content in nested `content-visibility: auto` element can be scrolled to</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-auto-nested-scroll-ref.html">
+<meta name="assert" content="content in nested `content-visibility: auto` element can be scrolled to">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ content-visibility: auto;
+}
+#outer {
+ width: 400px;
+ height: 400px;
+}
+
+#inner {
+ position: relative;
+ top: 100px;
+ width: 100px;
+ height: 100px;
+}
+</style>
+
+<script>
+function runTest() {
+ inner.scrollIntoView();
+ requestAnimationFrame(takeScreenshot);
+}
+window.onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
+<div style="height:100vh"></div>
+<div id="outer" style="border:solid">
+ <div id="inner">content with content-visibility: auto</div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-nested.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-nested.html
new file mode 100644
index 0000000000..d9b9db6bb5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-nested.html
@@ -0,0 +1,27 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Content Visibility: content in nested `content-visibility: auto` elements is considered relevant</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-nested-ref.html">
+<meta name="assert" content="content in nested `content-visibility: auto` elements is considered relevant">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+div {
+ content-visibility: auto;
+}
+</style>
+
+<script>
+function runTest() {
+ requestAnimationFrame(takeScreenshot);
+}
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
+
+<div style="border:solid">
+ <div>content with content-visibility: auto</div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-relevancy-updates.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-relevancy-updates.html
new file mode 100644
index 0000000000..2699679994
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-relevancy-updates.html
@@ -0,0 +1,109 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Content Visibility: relevancy updates</title>
+<link rel="author" title="Frédéric Wang" href="mailto:fwang@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#relevant-to-the-user">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#cv-notes">
+<meta name="assert" content="Verify relevancy is properly updated for content-visibility: auto elements.">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+ #spacer {
+ height: 300vh;
+ }
+ #contentVisibilityAuto {
+ content-visibility: auto;
+ border: solid;
+ }
+</style>
+<div>
+ <div id="log"></div>
+ <div tabindex="1" id="spacer"></div>
+ <div tabindex="2" id="contentVisibilityAuto">
+ <span>Hello, World!</span>
+ </div>
+</div>
+
+<script>
+function tick() {
+ return new Promise(r => {
+ requestAnimationFrame(() => requestAnimationFrame(r));
+ });
+}
+
+function contentVisibilityAutoElementIsRelevant() {
+ // A content-visibility: auto element that is not relevant skips its contents,
+ // which do not contribute to the result of innerText.
+ return contentVisibilityAuto.innerText.length > 0;
+}
+
+function clearRelevancyReasons() {
+ window.scrollTo(0, 0);
+ spacer.focus({preventScroll: true});
+ window.getSelection().empty();
+}
+
+promise_test(async function(t) {
+ // Wait for page load.
+ await new Promise(resolve => { window.addEventListener("load", resolve); });
+
+ // Register cleanup method to reset relevancy.
+ t.add_cleanup(clearRelevancyReasons);
+
+ // Element should initially not be relevant.
+ await tick();
+ assert_false(contentVisibilityAutoElementIsRelevant(), "initial relevancy");
+
+ // Make element close to the viewport.
+ contentVisibilityAuto.firstElementChild.scrollIntoView();
+ await tick();
+ assert_true(contentVisibilityAutoElementIsRelevant(), "close to viewport");
+
+ // Scroll away from the element again.
+ window.scrollTo(0, 0);
+ await tick();
+ assert_false(contentVisibilityAutoElementIsRelevant(), "far from viewport");
+}, "Relevancy updated after changing proximity to the viewport.");
+
+promise_test(async function(t) {
+ // Register cleanup method to reset relevancy.
+ t.add_cleanup(clearRelevancyReasons);
+
+ // Element should initially not be relevant.
+ await tick();
+ assert_false(contentVisibilityAutoElementIsRelevant(), "initial relevancy");
+
+ // Focus the element.
+ contentVisibilityAuto.focus({preventScroll: true});
+ await tick();
+ assert_true(contentVisibilityAutoElementIsRelevant(), "focused");
+
+ // Unfocus the element again.
+ spacer.focus({preventScroll: true});
+ await tick();
+ assert_false(contentVisibilityAutoElementIsRelevant(), "unfocused");
+}, "Relevancy updated after being focused/unfocused.");
+
+promise_test(async function(t) {
+ // Register cleanup method to reset relevancy.
+ t.add_cleanup(clearRelevancyReasons);
+
+ // Element should initially not be relevant.
+ await tick();
+ assert_false(contentVisibilityAutoElementIsRelevant(), "initial relevancy");
+
+ // Select the contents of the element.
+ window.getSelection().selectAllChildren(contentVisibilityAuto);
+ await tick();
+ assert_true(contentVisibilityAutoElementIsRelevant(), "selected");
+
+ // Unselect the contents of the element.
+ window.getSelection().empty();
+ await tick();
+ assert_false(contentVisibilityAutoElementIsRelevant(), "unselected");
+}, "Relevancy updated after being selected/unselected.");
+
+</script>
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-removed.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-state-changed-removed.html
new file mode 100644
index 0000000000..5724aa1649
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-state-changed-removed.html
@@ -0,0 +1,41 @@
+<!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 does not fire on disconnected element">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/rendering-utils.js"></script>
+
+<style>
+.spacer {
+ height: 10000px;
+}
+#bottomdiv {
+ content-visibility: auto;
+}
+</style>
+
+<div class=spacer></div>
+<div id=bottomdiv></div>
+
+<script>
+promise_test(t => new Promise(async (resolve, reject) => {
+ // Make sure the first "contentvisibilityautostatechange" event has fired before the test.
+ await new Promise(resolve => bottomdiv.addEventListener("contentvisibilityautostatechange", resolve, { once: true }));
+
+ let observed = false;
+ bottomdiv.addEventListener("contentvisibilityautostatechange", () => {
+ reject("unexpected signal")
+ });
+
+ bottomdiv.remove()
+ waitForAtLeastOneFrame().then(resolve);
+
+}), "ContentVisibilityAutoStateChange does not fire on disconnected element");
+
+</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-auto-text-fragment.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-text-fragment.html
new file mode 100644
index 0000000000..d5184d72a4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-text-fragment.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://github.com/WICG/display-locking">
+<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-matchable.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-matchable.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-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-interpolation.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-interpolation.html
new file mode 100644
index 0000000000..55f8c7e5af
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-interpolation.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/w3c/csswg-drafts/issues/6429">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+const alwaysVisible = [
+ {at: -1, expect: 'visible'},
+ {at: 0, expect: 'visible'},
+ {at: 0.1, expect: 'visible'},
+ {at: 0.9, expect: 'visible'},
+ {at: 1, expect: 'visible'},
+ {at: 1.5, expect: 'visible'},
+];
+const alwaysHidden = [
+ {at: -1, expect: 'hidden'},
+ {at: 0, expect: 'hidden'},
+ {at: 0.1, expect: 'hidden'},
+ {at: 0.9, expect: 'hidden'},
+ {at: 1, expect: 'hidden'},
+ {at: 1.5, expect: 'hidden'},
+];
+
+test_interpolation({
+ property: 'content-visibility',
+ behavior: 'allow-discrete',
+ from: 'visible',
+ to: 'hidden',
+}, [
+ {at: -1, expect: 'visible'},
+ {at: 0, expect: 'visible'},
+ {at: 0.1, expect: 'visible'},
+ {at: 0.9, expect: 'visible'},
+ {at: 1, expect: 'hidden'},
+ {at: 1.5, expect: 'hidden'},
+]);
+
+test_interpolation({
+ property: 'content-visibility',
+ behavior: 'allow-discrete',
+ from: 'hidden',
+ to: 'visible',
+}, [
+ {at: -1, expect: 'hidden'},
+ {at: 0, expect: 'hidden'},
+ {at: 0.1, expect: 'visible'},
+ {at: 0.9, expect: 'visible'},
+ {at: 1, expect: 'visible'},
+ {at: 1.5, expect: 'visible'},
+]);
+
+test_no_interpolation({
+ property: 'content-visibility',
+ from: 'auto',
+ to: 'visible'
+});
+
+test_interpolation({
+ property: 'content-visibility',
+ from: 'visible',
+ to: 'visible'
+}, [
+ {at: -1, expect: 'visible'},
+ {at: 0, expect: 'visible'},
+ {at: 0.5, expect: 'visible'},
+ {at: 1, expect: 'visible'},
+ {at: 1.5, expect: 'visible'},
+]);
+
+test_interpolation({
+ property: 'content-visibility',
+ from: 'hidden',
+ to: 'hidden'
+}, [
+ {at: -1, expect: 'hidden'},
+ {at: 0, expect: 'hidden'},
+ {at: 0.5, expect: 'hidden'},
+ {at: 1, expect: 'hidden'},
+ {at: 1.5, expect: 'hidden'},
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-layout-containment-001.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-layout-containment-001.html
new file mode 100644
index 0000000000..852e064a5e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-layout-containment-001.html
@@ -0,0 +1,185 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>content-visibility and layout containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1765615">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/rendering-utils.js"></script>
+<meta name="assert" content="content-visibility: auto and elements skipping their content change the used value of the contain property to turn on layout containment.">
+<style>
+ /* Selectors for content-visibility */
+ #spacer_for_far_to_viewport {
+ height: 300vh;
+ }
+ .content_visibility {
+ /* Dynamic modification of content-visibility may change whether style
+ containment is applied, which in turn may cause drastic invalidations
+ (e.g. rebuilding counters). Make the test more robust by forcing
+ style containment to always apply. */
+ contain: style;
+ }
+ #visible .content_visibility {
+ content-visibility: visible;
+ }
+ #hidden .content_visibility {
+ content-visibility: hidden;
+ }
+ #auto_far .content_visibility {
+ content-visibility: auto;
+ }
+ #auto_close .content_visibility {
+ content-visibility: auto;
+ }
+ #visible_to_hidden .content_visibility {
+ content-visibility: visible;
+ }
+ #hidden_to_visible .content_visibility {
+ content-visibility: hidden;
+ }
+ #visible_to_auto .content_visibility {
+ content-visibility: visible;
+ }
+ #auto_to_visible .content_visibility {
+ content-visibility: auto;
+ }
+
+ /* Selectors for testing baseline */
+ .flex {
+ display: inline-flex;
+ align-items: baseline;
+ }
+ .rect {
+ background: black;
+ width: 50px;
+ height: 100px;
+ }
+</style>
+<body>
+ <div id="log"></div>
+
+ <div id="visible">
+ <div class="flex">
+ <div class="rect"></div>
+ <div class="content_visibility rect">X</div>
+ </div>
+ </div>
+
+ <div id="hidden">
+ <div class="flex">
+ <div class="rect"></div>
+ <div class="content_visibility rect">X</div>
+ </div>
+ </div>
+
+ <div id="auto_close">
+ <div class="flex">
+ <div class="rect"></div>
+ <div class="content_visibility rect">X</div>
+ </div>
+ </div>
+
+ <div id="visible_to_hidden">
+ <div class="flex">
+ <div class="rect"></div>
+ <div class="content_visibility rect">X</div>
+ </div>
+ </div>
+
+ <div id="hidden_to_visible">
+ <div class="flex">
+ <div class="rect"></div>
+ <div class="content_visibility rect">X</div>
+ </div>
+ </div>
+
+ <div id="visible_to_auto">
+ <div class="flex">
+ <div class="rect"></div>
+ <div class="content_visibility rect">X</div>
+ </div>
+ </div>
+
+ <div id="auto_to_visible">
+ <div class="flex">
+ <div class="rect"></div>
+ <div class="content_visibility rect">X</div>
+ </div>
+ </div>
+
+ <div id="spacer_for_far_to_viewport"></div>
+
+ <div id="auto_far">
+ <div class="flex">
+ <div class="rect"></div>
+ <div class="content_visibility rect">X</div>
+ </div>
+ </div>
+
+ <script>
+ function layoutContainmentApplied(id) {
+ let container = document.getElementById(id);
+ let content_visibility = container.getElementsByClassName("content_visibility")[0];
+
+ // To verify layout containment, we test baseline suppression.
+ // See contain-layout-dynamic-001.html for more details.
+ let item1 = content_visibility;
+ let item2 = item1.previousElementSibling;
+ return Math.abs(item1.getBoundingClientRect().top - item2.getBoundingClientRect().top) <= 1;
+ }
+
+ function setContentVisibility(id, value) {
+ let container = document.getElementById(id);
+ let content_visibility = container.getElementsByClassName("content_visibility")[0];
+ content_visibility.style.contentVisibility = value;
+ }
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ assert_false(layoutContainmentApplied("visible"));
+ }, "content-visibility: visible");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ assert_true(layoutContainmentApplied("hidden"));
+ }, "content-visibility: hidden");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ await waitForAtLeastOneFrame();
+ assert_true(layoutContainmentApplied("auto_far"));
+ }, "content-visibility: auto (far from viewport)");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ await waitForAtLeastOneFrame();
+ assert_true(layoutContainmentApplied("auto_close"));
+ }, "content-visibility: auto (close from viewport)");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ setContentVisibility("visible_to_hidden", "hidden");
+ assert_true(layoutContainmentApplied("visible_to_hidden"));
+ }, "switching content-visibility from visible to hidden");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ setContentVisibility("hidden_to_visible", "visible");
+ assert_false(layoutContainmentApplied("hidden_to_visible"));
+ }, "switching content-visibility from hidden to visible");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ setContentVisibility("visible_to_auto", "auto");
+ await waitForAtLeastOneFrame();
+ assert_true(layoutContainmentApplied("visible_to_auto"));
+ }, "switching content-visibility from visible to auto");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ setContentVisibility("auto_to_visible", "visible");
+ assert_false(layoutContainmentApplied("auto_to_visible"));
+ }, "switching content-visibility from auto to visible");
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-layout-paint-containment-001.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-layout-paint-containment-001.html
new file mode 100644
index 0000000000..788139e17e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-layout-paint-containment-001.html
@@ -0,0 +1,179 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>content-visibility and layout/paint containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1765615">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/rendering-utils.js"></script>
+<meta name="assert" content="content-visibility: auto and elements skipping their content change the used value of the contain property to turn on layout/paint containment, affecting absolute/fixed positioned descendants.">
+<style>
+ /* Selectors for content-visibility */
+ #spacer_for_far_to_viewport {
+ height: 300vh;
+ }
+ .content_visibility {
+ /* Dynamic modification of content-visibility may change whether style
+ containment is applied, which in turn may cause drastic invalidations
+ (e.g. rebuilding counters). Make the test more robust by forcing
+ style containment to always apply. */
+ contain: style;
+ }
+ #visible {
+ content-visibility: visible;
+ }
+ #hidden {
+ content-visibility: hidden;
+ }
+ #auto_far {
+ content-visibility: auto;
+ }
+ #auto_close {
+ content-visibility: auto;
+ }
+ #visible_to_hidden {
+ content-visibility: visible;
+ }
+ #hidden_to_visible {
+ content-visibility: hidden;
+ }
+ #visible_to_auto {
+ content-visibility: visible;
+ }
+ #auto_to_visible {
+ content-visibility: auto;
+ }
+
+ /* Selectors for testing absolute/fixed positioning container blocks */
+ #top_spacer {
+ height: 100px;
+ background: lightgray;
+ }
+ .absolute_pos {
+ position: absolute;
+ top: 42px;
+ }
+ .fixed_pos {
+ position: fixed;
+ top: 42px;
+ }
+</style>
+<body>
+ <div id="log"></div>
+
+ <div id="top_spacer"></div>
+
+ <div id="visible" class="content_visibility">
+ <div class="absolute_pos"></div>
+ <div class="fixed_pos"></div>
+ </div>
+
+ <div id="hidden" class="content_visibility">
+ <div class="absolute_pos"></div>
+ <div class="fixed_pos"></div>
+ </div>
+
+ <div id="auto_close" class="content_visibility">
+ <div class="absolute_pos"></div>
+ <div class="fixed_pos"></div>
+ </div>
+
+ <div id="visible_to_hidden" class="content_visibility">
+ <div class="absolute_pos"></div>
+ <div class="fixed_pos"></div>
+ </div>
+
+ <div id="hidden_to_visible" class="content_visibility">
+ <div class="absolute_pos"></div>
+ <div class="fixed_pos"></div>
+ </div>
+
+ <div id="visible_to_auto" class="content_visibility">
+ <div class="absolute_pos"></div>
+ <div class="fixed_pos"></div>
+ </div>
+
+ <div id="auto_to_visible" class="content_visibility">
+ <div class="absolute_pos"></div>
+ <div class="fixed_pos"></div>
+ </div>
+
+ <div id="spacer_for_far_to_viewport"></div>
+
+ <div id="auto_far" class="content_visibility">
+ <div class="absolute_pos"></div>
+ <div class="fixed_pos"></div>
+ </div>
+
+ <script>
+ function verifyContainmentFromAbsoluteFixedPositioning(id, applied) {
+ // content-visibility: auto and elements skipping their content change
+ // apply paint/layout containment, making them an absolute/fixed
+ // positioning container blocks.
+ // See contain-paint-dynamic-001.html / contain-layout-dynamic-001.html.
+
+ let container = document.getElementById(id);
+ let containerTop = container.getBoundingClientRect().top;
+
+ let abs_top = container.getElementsByClassName("absolute_pos")[0]
+ .getBoundingClientRect().top;
+ assert_equals(abs_top > containerTop, applied, "absolute positioning containing block");
+
+ let fixed_top = container.getElementsByClassName("fixed_pos")[0]
+ .getBoundingClientRect().top;
+ assert_equals(fixed_top > containerTop, applied, "fixed positioning containing block");
+ }
+
+ function setContentVisibility(id, value) {
+ let container = document.getElementById(id);
+ container.style.contentVisibility = value;
+ }
+
+ promise_test(async () => {
+ verifyContainmentFromAbsoluteFixedPositioning("visible",
+ /*applied=*/false);
+ }, "content-visibility: visible");
+
+ promise_test(async () => {
+ verifyContainmentFromAbsoluteFixedPositioning("hidden",
+ /*applied=*/true);
+ }, "content-visibility: hidden");
+
+ promise_test(async () => {
+ await waitForAtLeastOneFrame();
+ verifyContainmentFromAbsoluteFixedPositioning("auto_far",
+ /*applied=*/true);
+ }, "content-visibility: auto (far from viewport)");
+
+ promise_test(async () => {
+ await waitForAtLeastOneFrame();
+ verifyContainmentFromAbsoluteFixedPositioning("auto_close",
+ /*applied=*/true);
+ }, "content-visibility: auto (close from viewport)");
+
+ promise_test(async () => {
+ setContentVisibility("visible_to_hidden", "hidden");
+ verifyContainmentFromAbsoluteFixedPositioning("visible_to_hidden",
+ /*applied=*/true);
+ }, "switching content-visibility from visible to hidden");
+
+ promise_test(async () => {
+ setContentVisibility("hidden_to_visible", "visible");
+ verifyContainmentFromAbsoluteFixedPositioning("hidden_to_visible",
+ /*applied=*/false);
+ }, "switching content-visibility from hidden to visible");
+
+ promise_test(async () => {
+ setContentVisibility("visible_to_auto", "auto");
+ await waitForAtLeastOneFrame();
+ verifyContainmentFromAbsoluteFixedPositioning("visible_to_auto",
+ /*applied=*/true);
+ }, "switching content-visibility from visible to auto");
+
+ promise_test(async () => {
+ setContentVisibility("auto_to_visible", "visible");
+ verifyContainmentFromAbsoluteFixedPositioning("auto_to_visible",
+ /*applied=*/false);
+ }, "switching content-visibility from auto to visible");
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-on-g-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-on-g-ref.html
new file mode 100644
index 0000000000..e93425d5ff
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-on-g-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title>CSS Content Visibility: effect on <g> element (reference)</title>
+<link rel="author" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<div>
+ <svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
+ <g>
+ <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>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-on-g.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-on-g.html
new file mode 100644
index 0000000000..4ff0789268
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-on-g.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>CSS Content Visibility: effect on <g> element</title>
+<link rel="author" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-on-g-ref.html">
+<meta name="assert" content="content-visibility hidden has no effect on g element">
+
+<div>
+ <svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
+ <g style="content-visibility:hidden">
+ <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>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-on-root-svg-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-on-root-svg-ref.html
new file mode 100644
index 0000000000..258cdfacab
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-on-root-svg-ref.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<title>CSS Content Visibility: effect on root <svg> element (reference)</title>
+<link rel="author" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-on-root-svg.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-on-root-svg.html
new file mode 100644
index 0000000000..440d1ad94b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-on-root-svg.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>CSS Content Visibility: effect on root <svg> element</title>
+<link rel="author" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-on-root-svg-ref.html">
+<meta name="assert" content="content-visibility hidden has an effect on root svg element">
+
+<div>
+ <svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" style="content-visibility:hidden">
+ <g>
+ <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>
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-paint-containment-001-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-001-ref.html
new file mode 100644
index 0000000000..1e8e96df13
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-001-ref.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<title>content-visibility and paint containment (reference)</title>
+
+<style>
+ .container {
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ .hidden {
+ contain: layout paint style;
+ }
+ .visible {
+ contain: none;
+ }
+ #overflowing {
+ width: 400px;
+ height: 100px;
+ }
+ .square {
+ display: inline-block;
+ width: 50px;
+ height: 50px;
+ margin: 5px;
+ }
+ .red {
+ background: red;
+ }
+ .green {
+ background: green;
+ }
+</style>
+
+<body>
+ <p>PASS if you see a green square and no red.</p>
+ <div class="hidden container">
+ <div id="overflowing"><div class="square"></div><div class="square"></div><div class="red square"></div></div>
+ </div>
+ <p>PASS if you see <em>two</em> green squares.</p>
+ <div class="visible container">
+ <div id="overflowing"><div class="square"></div><div class="square"></div><div class="green square"></div></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-001.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-001.html
new file mode 100644
index 0000000000..b18a9cb1e9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-001.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<title>content-visibility and paint containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1765615">
+<meta name="assert" content="Verify paint containment is implied by content-visibility.">
+<link rel="match" href="content-visibility-paint-containment-001-ref.html">
+
+<style>
+ .container {
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ .hidden {
+ content-visibility: hidden;
+ }
+ .visible {
+ content-visibility: visible;
+ }
+ #overflowing {
+ width: 400px;
+ height: 100px;
+ }
+ .square {
+ display: inline-block;
+ width: 50px;
+ height: 50px;
+ margin: 5px;
+ }
+ .red {
+ background: red;
+ }
+ .green {
+ background: green;
+ }
+</style>
+
+<body>
+ <p>PASS if you see a green square and no red.</p>
+ <div class="hidden container">
+ <div id="overflowing"><div class="square"></div><div class="square"></div><div class="red square"></div></div>
+ </div>
+ <p>PASS if you see <em>two</em> green squares.</p>
+ <div class="visible container">
+ <div id="overflowing"><div class="square"></div><div class="square"></div><div class="green square"></div></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-002-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-002-ref.html
new file mode 100644
index 0000000000..e71e9c0c9f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-002-ref.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<title>content-visibility and paint containment (reference)</title>
+
+<style>
+ #container {
+ width: 100px;
+ height: 100px;
+ background: green;
+ content-visibility: hidden;
+ contain: style;
+ }
+ #overflowing {
+ width: 400px;
+ height: 100px;
+ }
+ .square {
+ display: inline-block;
+ width: 50px;
+ height: 50px;
+ margin: 5px;
+ }
+ .red {
+ background: red;
+ }
+</style>
+
+<body>
+ <p>PASS if you see a green square and no red.</p>
+ <div id="container">
+ <div id="overflowing"><div class="square"></div><div class="square"></div><div class="red square"></div></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-002.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-002.html
new file mode 100644
index 0000000000..bfe6d13b39
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-002.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>content-visibility and paint containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1765615">
+<meta name="assert" content="Verify paint containment is properly updated after dynamic change to the content-visibility property.">
+<link rel="match" href="content-visibility-paint-containment-002-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+
+<style>
+ #container {
+ width: 100px;
+ height: 100px;
+ background: green;
+ content-visibility: visible;
+ /* Dynamic modification of content-visibility may change whether style
+ containment is applied, which in turn may cause drastic invalidations
+ (e.g. rebuilding counters). Make the test more robust by forcing
+ style containment to always apply. */
+ contain: style;
+ }
+ #overflowing {
+ width: 400px;
+ height: 100px;
+ }
+ .square {
+ display: inline-block;
+ width: 50px;
+ height: 50px;
+ margin: 5px;
+ }
+ .red {
+ background: red;
+ }
+</style>
+
+<body>
+ <p>PASS if you see a green square and no red.</p>
+ <div id="container">
+ <div id="overflowing"><div class="square"></div><div class="square"></div><div class="red square"></div></div>
+ </div>
+ <script>
+ window.addEventListener("TestRendered", async () => {
+ container.style.contentVisibility = "hidden";
+ await waitForAtLeastOneFrame();
+ takeScreenshot();
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-003-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-003-ref.html
new file mode 100644
index 0000000000..43f3a2ed48
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-003-ref.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<title>Dynamic change to paint containment (reference)</title>
+
+<style>
+ #container {
+ width: 100px;
+ height: 100px;
+ background: green;
+ content-visibility: visible;
+ contain: style;
+ }
+ #overflowing {
+ width: 400px;
+ height: 100px;
+ }
+ .square {
+ display: inline-block;
+ width: 50px;
+ height: 50px;
+ margin: 5px;
+ }
+ .green {
+ background: green;
+ }
+</style>
+
+<body>
+ <p>PASS if you see <em>two</em> green squares.</p>
+ <div id="container">
+ <div id="overflowing"><div class="square"></div><div class="square"></div><div class="green square"></div></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-003.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-003.html
new file mode 100644
index 0000000000..0a4de9c4e5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-paint-containment-003.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>content-visibility and paint containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1765615">
+<meta name="assert" content="Verify paint containment is properly updated after dynamic change to the content-visibility property.">
+<link rel="match" href="content-visibility-paint-containment-003-ref.html">
+
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+
+<style>
+ #container {
+ width: 100px;
+ height: 100px;
+ background: green;
+ content-visibility: hidden;
+ /* Dynamic modification of content-visibility may change whether style
+ containment is applied, which in turn may cause drastic invalidations
+ (e.g. rebuilding counters). Make the test more robust by forcing
+ style containment to always apply. */
+ contain: style;
+ }
+ #overflowing {
+ width: 400px;
+ height: 100px;
+ }
+ .square {
+ display: inline-block;
+ width: 50px;
+ height: 50px;
+ margin: 5px;
+ }
+ .green {
+ background: green;
+ }
+</style>
+
+<body>
+ <p>PASS if you see <em>two</em> green squares.</p>
+ <div id="container">
+ <div id="overflowing"><div class="square"></div><div class="square"></div><div class="green square"></div></div>
+ </div>
+ <script>
+ window.addEventListener("TestRendered", async () => {
+ container.style.contentVisibility = "visible";
+ await waitForAtLeastOneFrame();
+ takeScreenshot();
+ });
+ </script>
+</body>
+</html>
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-selection-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-selection-crash.html
new file mode 100644
index 0000000000..78b610b72e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-selection-crash.html
@@ -0,0 +1,20 @@
+<style>
+* { content-visibility: auto; }
+</style>
+<script>
+document.addEventListener('DOMContentLoaded', () => {
+ document.documentElement.setAttribute('contenteditable', true)
+ let a = document.createElement('map')
+ let b = document.createElement('h1')
+ let c = document.createElement('kbd')
+ b.appendChild(c)
+ a.appendChild(b)
+ document.documentElement.appendChild(a)
+ let d = new Range()
+ let f = document.getSelection()
+ f.addRange(d)
+ d.setStart(c, 0)
+ f.addRange(d)
+ f.removeRange(d)
+})
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-size-containment-001.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-size-containment-001.html
new file mode 100644
index 0000000000..3b4a7c55a4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-size-containment-001.html
@@ -0,0 +1,264 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>content-visibility and size containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1765615">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/rendering-utils.js"></script>
+<meta name="assert" content="elements skipping their content change the used value of the contain property to turn on size containment.">
+<style>
+ /* Selectors for content-visibility */
+ #spacer_for_far_to_viewport {
+ height: 300vh;
+ }
+ .content_visibility {
+ /* Dynamic modification of content-visibility may change whether style
+ containment is applied, which in turn may cause drastic invalidations
+ (e.g. rebuilding counters). Make the test more robust by forcing
+ style containment to always apply. */
+ contain: style;
+ }
+ #visible .content_visibility {
+ content-visibility: visible;
+ }
+ #hidden .content_visibility {
+ content-visibility: hidden;
+ }
+ #auto_far .content_visibility {
+ content-visibility: auto;
+ }
+ #auto_close .content_visibility {
+ content-visibility: auto;
+ }
+ #visible_to_hidden .content_visibility {
+ content-visibility: visible;
+ }
+ #hidden_to_visible .content_visibility {
+ content-visibility: hidden;
+ }
+ #visible_to_auto_far .content_visibility {
+ content-visibility: visible;
+ }
+ #auto_far_to_visible .content_visibility {
+ content-visibility: auto;
+ }
+ #hidden_to_auto_close .content_visibility {
+ content-visibility: hidden;
+ }
+ #auto_close_to_hidden .content_visibility {
+ content-visibility: auto;
+ }
+ #auto_dynamic_relevancy .content_visibility {
+ content-visibility: auto;
+ }
+
+ /* Selectors for testing sizing as empty */
+ .content_visibility {
+ display: inline-block;
+ }
+ .box {
+ display: inline-block;
+ width: 50px;
+ height: 5px;
+ background: black;
+ }
+</style>
+<body>
+ <div id="log"></div>
+
+ <div id="visible">
+ <div class="content_visibility"><div class="box"></div></div>
+ </div>
+
+ <div id="hidden">
+ <div class="content_visibility"><div class="box"></div></div>
+ </div>
+
+ <div id="auto_close">
+ <div class="content_visibility"><div class="box"></div></div>
+ </div>
+
+ <div id="visible_to_hidden">
+ <div class="content_visibility"><div class="box"></div></div>
+ </div>
+
+ <div id="hidden_to_visible">
+ <div class="content_visibility"><div class="box"></div></div>
+ </div>
+
+ <div id="hidden_to_auto">
+ <div class="content_visibility"><div class="box"></div></div>
+ </div>
+
+ <div id="auto_to_hidden">
+ <div class="content_visibility"><div class="box"></div></div>
+ </div>
+
+ <div id="hidden_to_auto_close">
+ <div class="content_visibility"><div class="box"></div></div>
+ </div>
+
+ <div id="auto_close_to_hidden">
+ <div class="content_visibility"><div class="box"></div></div>
+ </div>
+
+ <div id="spacer_for_far_to_viewport"></div>
+
+ <div id="auto_far">
+ <div class="content_visibility"><div class="box"></div></div>
+ </div>
+
+ <div id="visible_to_auto_far">
+ <div class="content_visibility"><div class="box"></div></div>
+ </div>
+
+ <div id="auto_far_to_visible">
+ <div class="content_visibility"><div class="box"></div></div>
+ </div>
+
+
+ <div id="auto_dynamic_relevancy">
+ <div tabindex="1"></div>
+ <div class="content_visibility" tabindex="2"><div class="box"></div></div>
+ </div>
+
+ <script>
+ function sizeContainmentApplied(id) {
+ // To verify size containment, we test the width is zero.
+ // See contain-size-dynamic-001.html for more details.
+ let container = document.getElementById(id);
+ let content_visibility = container.getElementsByClassName("content_visibility")[0];
+ return content_visibility.getBoundingClientRect().width == 0;
+ }
+
+ function setContentVisibility(id, value) {
+ let container = document.getElementById(id);
+ let content_visibility = container.getElementsByClassName("content_visibility")[0];
+ content_visibility.style.contentVisibility = value;
+ }
+
+ promise_test(async () => {
+ assert_false(sizeContainmentApplied("visible"));
+ }, "content-visibility: visible");
+
+ promise_test(async () => {
+ assert_true(sizeContainmentApplied("hidden"));
+ }, "content-visibility: hidden");
+
+ promise_test(async () => {
+ await waitForAtLeastOneFrame();
+ assert_true(sizeContainmentApplied("auto_far"));
+ }, "content-visibility: auto (far from viewport)");
+
+ promise_test(async () => {
+ await waitForAtLeastOneFrame();
+ assert_false(sizeContainmentApplied("auto_close"));
+ }, "content-visibility: auto (close from viewport)");
+
+ promise_test(async () => {
+ setContentVisibility("visible_to_hidden", "hidden");
+ assert_true(sizeContainmentApplied("visible_to_hidden"));
+ }, "switching content-visibility from visible to hidden");
+
+ promise_test(async () => {
+ setContentVisibility("hidden_to_visible", "visible");
+ assert_false(sizeContainmentApplied("hidden_to_visible"));
+ }, "switching content-visibility from hidden to visible");
+
+ promise_test(async () => {
+ setContentVisibility("auto_far_to_visible", "visible");
+ assert_false(sizeContainmentApplied("auto_far_to_visible"));
+ }, "switching content-visibility from auto (far from viewport) to visible");
+
+ promise_test(async () => {
+ setContentVisibility("visible_to_auto_far", "auto");
+ await waitForAtLeastOneFrame();
+ assert_true(sizeContainmentApplied("visible_to_auto_far"));
+ }, "switching content-visibility from visible to auto (far from viewport)");
+
+ promise_test(async () => {
+ setContentVisibility("auto_close_to_hidden", "hidden");
+ assert_true(sizeContainmentApplied("auto_close_to_hidden"));
+ }, "switching content-visibility from auto (close from viewport) to hidden");
+
+ promise_test(async () => {
+ setContentVisibility("hidden_to_auto_close", "auto");
+ await waitForAtLeastOneFrame();
+ assert_false(sizeContainmentApplied("hidden_to_auto_close"));
+ }, "switching content-visibility from hidden to auto (close from viewport)");
+
+
+ let contentVisibilityAuto =
+ document.getElementById("auto_dynamic_relevancy").
+ getElementsByClassName("content_visibility")[0];
+
+ function clearRelevancyReasons() {
+ // Scrolling auto_dynamic_relevancy far from the viewport, unfocus it
+ // and unselect it. Also temporarily set its content-visibility to
+ // 'hidden' before scrolling to give more chance for browsers to
+ // re-apply size containment, especially if they fail the corresponding
+ // tests "going back to initial state" below.
+ setContentVisibility("auto_dynamic_relevancy", "hidden");
+ window.scrollTo(0, 0);
+ document.getElementById("auto_dynamic_relevancy")
+ .firstElementChild.focus({preventScroll: true});
+ window.getSelection().empty();
+ setContentVisibility("auto_dynamic_relevancy", "auto");
+ }
+
+ promise_test(async (t) => {
+ t.add_cleanup(clearRelevancyReasons);
+
+ await waitForAtLeastOneFrame();
+ assert_true(sizeContainmentApplied("auto_dynamic_relevancy"),
+ "size containment applied when initially far to the viewport");
+
+ contentVisibilityAuto.scrollIntoView();
+ await waitForAtLeastOneFrame();
+ assert_false(sizeContainmentApplied("auto_dynamic_relevancy"),
+ "size containment applied when changing from far to close to the viewport");
+
+ window.scrollTo(0, 0);
+ assert_true(sizeContainmentApplied("auto_dynamic_relevancy"),
+ "size containment applied when changing back from close to far to the viewport");
+ }, "content-visibility: auto, changing proximity to the viewport");
+
+ promise_test(async (t) => {
+ t.add_cleanup(clearRelevancyReasons);
+
+ await waitForAtLeastOneFrame();
+ assert_true(sizeContainmentApplied("auto_dynamic_relevancy"),
+ "size containment applied when initially unfocused");
+
+ contentVisibilityAuto.focus({preventScroll: true});
+ await waitForAtLeastOneFrame();
+ assert_false(sizeContainmentApplied("auto_dynamic_relevancy"),
+ "size containment applied after focusing");
+
+ document.getElementById("auto_dynamic_relevancy")
+ .firstElementChild.focus({preventScroll: true});
+ assert_true(sizeContainmentApplied("auto_dynamic_relevancy"),
+ "size containment applied after unfocusing back");
+ }, "content-visibility: auto, after being focused/unfocused");
+
+ promise_test(async (t) => {
+ t.add_cleanup(clearRelevancyReasons);
+
+ await waitForAtLeastOneFrame();
+ assert_true(sizeContainmentApplied("auto_dynamic_relevancy"),
+ "size containment applied when initially unselected");
+
+ window.getSelection().selectAllChildren(contentVisibilityAuto);
+ await waitForAtLeastOneFrame();
+ assert_false(sizeContainmentApplied("auto_dynamic_relevancy"),
+ "size containment applied when after selecting");
+
+ window.getSelection().empty();
+ await waitForAtLeastOneFrame();
+ assert_true(sizeContainmentApplied("auto_dynamic_relevancy"),
+ "size containment applied when unselecting back");
+ }, "content-visibility: auto, after being selected/unselected");
+
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-style-containment-001.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-style-containment-001.html
new file mode 100644
index 0000000000..d976d89b73
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-style-containment-001.html
@@ -0,0 +1,202 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>content-visibility and style containment</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1765615">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/rendering-utils.js"></script>
+<meta name="assert" content="content-visibility: auto and elements skipping their content change the used value of the contain property to turn on style containment.">
+<style>
+ /* Selectors for content-visibility */
+ #spacer_for_far_to_viewport {
+ height: 300vh;
+ }
+ #visible .content_visibility {
+ content-visibility: visible;
+ }
+ #hidden .content_visibility {
+ content-visibility: hidden;
+ }
+ #auto_far .content_visibility {
+ content-visibility: auto;
+ }
+ #auto_close .content_visibility {
+ content-visibility: auto;
+ }
+ #visible_to_hidden .content_visibility {
+ content-visibility: visible;
+ }
+ #hidden_to_visible .content_visibility {
+ content-visibility: hidden;
+ }
+ #visible_to_auto .content_visibility {
+ content-visibility: visible;
+ }
+ #auto_to_visible .content_visibility {
+ content-visibility: auto;
+ }
+
+ /* Selectors for testing counters */
+ .set_counter_to_9 {
+ counter-set: testcounter 9;
+ }
+ .increment_counter {
+ counter-increment: testcounter;
+ }
+ span.print_counter::after {
+ font: 25px/1 Ahem;
+ content: counters(testcounter, ".");
+ }
+
+</style>
+<body>
+ <div id="log"></div>
+
+ <div id="visible">
+ <div class="set_counter_to_9"></div>
+ <span><span class="print_counter"></span></span>
+ <div class="content_visibility">
+ <span class="increment_counter"></span>
+ </div>
+ <span><span class="print_counter"></span></span>
+ </div>
+
+ <div id="hidden">
+ <div class="set_counter_to_9"></div>
+ <span><span class="print_counter"></span></span>
+ <div class="content_visibility">
+ <span class="increment_counter"></span>
+ </div>
+ <span><span class="print_counter"></span></span>
+ </div>
+
+ <div id="auto_close">
+ <div class="set_counter_to_9"></div>
+ <span><span class="print_counter"></span></span>
+ <div class="content_visibility">
+ <span class="increment_counter"></span>
+ </div>
+ <span><span class="print_counter"></span></span>
+ </div>
+
+ <div id="visible_to_hidden">
+ <div class="set_counter_to_9"></div>
+ <span><span class="print_counter"></span></span>
+ <div class="content_visibility">
+ <span class="increment_counter"></span>
+ </div>
+ <span><span class="print_counter"></span></span>
+ </div>
+
+ <div id="hidden_to_visible">
+ <div class="set_counter_to_9"></div>
+ <span><span class="print_counter"></span></span>
+ <div class="content_visibility">
+ <span class="increment_counter"></span>
+ </div>
+ <span><span class="print_counter"></span></span>
+ </div>
+
+ <div id="visible_to_auto">
+ <div class="set_counter_to_9"></div>
+ <span><span class="print_counter"></span></span>
+ <div class="content_visibility">
+ <span class="increment_counter"></span>
+ </div>
+ <span><span class="print_counter"></span></span>
+ </div>
+
+ <div id="auto_to_visible">
+ <div class="set_counter_to_9"></div>
+ <span><span class="print_counter"></span></span>
+ <div class="content_visibility">
+ <span class="increment_counter"></span>
+ </div>
+ <span><span class="print_counter"></span></span>
+ </div>
+
+ <div id="spacer_for_far_to_viewport"></div>
+
+ <div id="auto_far">
+ <div class="set_counter_to_9"></div>
+ <span><span class="print_counter"></span></span>
+ <div class="content_visibility">
+ <span class="increment_counter"></span>
+ </div>
+ <span><span class="print_counter"></span></span>
+ </div>
+
+ <script>
+ function styleContainmentApplied(id) {
+ let container = document.getElementById(id);
+
+ let printed_counters = container.getElementsByClassName("print_counter");
+
+ // To verify style containment, we test the string length of generated
+ // content for counters.
+ // See contain-style-dynamic-001.html for more details.
+ function haveSameStringLength(box1, box2) {
+ const ahemFontSizePx = 25;
+ return Math.abs(box2.width - box1.width) < ahemFontSizePx / 2;
+ }
+ let beforeBox = printed_counters[0].parentNode.getBoundingClientRect();
+ let afterBox = printed_counters[1].parentNode.getBoundingClientRect();
+ return haveSameStringLength(beforeBox, afterBox);
+ }
+
+ function setContentVisibility(id, value) {
+ let container = document.getElementById(id);
+ let content_visibility = container.getElementsByClassName("content_visibility")[0];
+ content_visibility.style.contentVisibility = value;
+ }
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ assert_false(styleContainmentApplied("visible"));
+ }, "content-visibility: visible");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ assert_true(styleContainmentApplied("hidden"));
+ }, "content-visibility: hidden");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ await waitForAtLeastOneFrame();
+ assert_true(styleContainmentApplied("auto_far"));
+ }, "content-visibility: auto (far from viewport)");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ await waitForAtLeastOneFrame();
+ assert_true(styleContainmentApplied("auto_close"));
+ }, "content-visibility: auto (close from viewport)");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ setContentVisibility("visible_to_hidden", "hidden");
+ assert_true(styleContainmentApplied("visible_to_hidden"));
+ }, "switching content-visibility from visible to hidden");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ setContentVisibility("hidden_to_visible", "visible");
+ assert_false(styleContainmentApplied("hidden_to_visible"));
+ }, "switching content-visibility from hidden to visible");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ setContentVisibility("visible_to_auto", "auto");
+ await waitForAtLeastOneFrame();
+ assert_true(styleContainmentApplied("visible_to_auto"));
+ }, "switching content-visibility from visible to auto");
+
+ promise_test(async () => {
+ await document.fonts.ready;
+ setContentVisibility("auto_to_visible", "visible");
+ assert_false(styleContainmentApplied("auto_to_visible"));
+ }, "switching content-visibility from auto to visible");
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-svg-path.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-svg-path.html
new file mode 100644
index 0000000000..a91f5817fd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-svg-path.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<link rel="author" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body {
+ margin: 0;
+ padding: 0;
+}
+div {
+ content-visibility:hidden;
+}
+path {
+ stroke-width: 5px;
+ stroke:green;
+}
+</style>
+
+<div>
+ <svg xmlns="http://www.w3.org/2000/svg">
+ <path id="path" d="M5 5 L 10 5 L 10 10 L 5 10 Z"/>
+ </svg>
+</div>
+
+<script>
+ test(() => {
+ const pathElement = document.getElementById('path');
+ const length = pathElement.getTotalLength();
+ assert_greater_than(length, 0, 'length');
+ }, `getTotalLength() should return nonzero value in a c-v:hidden subtree.`);
+
+ test(() => {
+ const pathElement = document.getElementById('path');
+ const point = pathElement.getPointAtLength(0);
+ assert_greater_than(point.x, 0, 'point.x');
+ assert_greater_than(point.y, 0, 'point.y');
+ }, `getPointAtLength() should return nonzero values in a c-v:hidden subtree.`);
+
+ test(() => {
+ const pathElement = document.getElementById('path');
+ const inFill = pathElement.isPointInFill({ x: 7, y: 7});
+ assert_true(inFill, 'fill');
+ }, `isPointInFill() should return true in a c-v:hidden subtree.`);
+
+ test(() => {
+ const pathElement = document.getElementById('path');
+ const inStroke = pathElement.isPointInStroke({ x: 7, y: 7});
+ assert_true(inStroke, 'stroke');
+ }, `isPointInStroke() should return true in a c-v:hidden subtree.`);
+
+ test(() => {
+ const pathElement = document.getElementById('path');
+ var rect = pathElement.ownerSVGElement.createSVGRect();
+ rect.x = 10;
+ rect.y = 10;
+ rect.width = 50;
+ rect.height = 50;
+ const intersection = pathElement.ownerSVGElement.checkIntersection(pathElement, rect);
+ assert_true(intersection, 'intersection');
+ }, `checkIntersection() should return true in a c-v:hidden subtree.`);
+
+ test(() => {
+ const pathElement = document.getElementById('path');
+ var rect = pathElement.ownerSVGElement.createSVGRect();
+ rect.width = 50;
+ rect.height = 50;
+ const enclosed = pathElement.ownerSVGElement.checkEnclosure(pathElement, rect);
+ assert_true(enclosed, 'enclosure');
+ }, `checkEnclosure() should return true in a c-v:hidden subtree.`);
+
+ test(() => {
+ const pathElement = document.getElementById('path');
+ var rect = pathElement.ownerSVGElement.createSVGRect();
+ rect.x = 10;
+ rect.y = 10;
+ rect.width = 50;
+ rect.height = 50;
+ const intersectionList = pathElement.ownerSVGElement.getIntersectionList(rect, null);
+ assert_greater_than(intersectionList.length, 0, 'intersection');
+ }, `getIntersectionList() should return items in a c-v:hidden subtree.`);
+
+ test(() => {
+ const pathElement = document.getElementById('path');
+ var rect = pathElement.ownerSVGElement.createSVGRect();
+ rect.width = 50;
+ rect.height = 50;
+ const enclusureList = pathElement.ownerSVGElement.getEnclosureList(rect, null);
+ assert_greater_than(enclusureList.length, 0, 'intersection');
+ }, `getEnclosureList() should return items in a c-v:hidden subtree.`);
+
+ test(() => {
+ const pathElement = document.getElementById('path');
+ const bbox = pathElement.getBBox();
+ assert_not_equals(bbox.x, 0, 'x');
+ assert_not_equals(bbox.y, 0, 'y');
+ assert_not_equals(bbox.width, 0, 'width');
+ assert_not_equals(bbox.height, 0, 'height');
+ }, `path 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-svg-rect.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-svg-rect.html
new file mode 100644
index 0000000000..be0abe5767
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-svg-rect.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<link rel="author" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body {
+ margin: 0;
+ padding: 0;
+}
+div {
+ content-visibility:hidden;
+}
+rect {
+ stroke-width: 5px;
+ stroke:green;
+}
+</style>
+
+<div>
+ <svg xmlns="http://www.w3.org/2000/svg">
+ <rect id="rect" x="5" y="5" width="10" height="10"/>
+ </svg>
+</div>
+
+<script>
+ test(() => {
+ const rectElement = document.getElementById('rect');
+ const length = rectElement.getTotalLength();
+ assert_greater_than(length, 0, 'length');
+ }, `getTotalLength() should return nonzero value in a c-v:hidden subtree.`);
+
+ test(() => {
+ const rectElement = document.getElementById('rect');
+ const point = rectElement.getPointAtLength(0);
+ assert_greater_than(point.x, 0, 'point.x');
+ assert_greater_than(point.y, 0, 'point.y');
+ }, `getPointAtLength() should return nonzero values in a c-v:hidden subtree.`);
+
+ test(() => {
+ const rectElement = document.getElementById('rect');
+ const inFill = rectElement.isPointInFill({ x: 7, y: 7});
+ assert_true(inFill, 'fill');
+ }, `isPointInFill() should return true in a c-v:hidden subtree.`);
+
+ test(() => {
+ const rectElement = document.getElementById('rect');
+ const inStroke = rectElement.isPointInStroke({ x: 7, y: 7});
+ assert_true(inStroke, 'stroke');
+ }, `isPointInStroke() should return true in a c-v:hidden subtree.`);
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-svg-text.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-svg-text.html
new file mode 100644
index 0000000000..fd3e44386c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-svg-text.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<link rel="author" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body {
+ margin: 0;
+ padding: 0;
+}
+#container {
+ content-visibility:hidden;
+}
+</style>
+
+<div id="container">
+ <svg xmlns="http://www.w3.org/2000/svg">
+ <text transform="scale(2, 2)"><tspan id="tspan1" x="50 150 100" y="100">abc</tspan></text>
+ </svg>
+</div>
+
+<script>
+ test(() => {
+ const element = document.querySelector('#tspan1');
+ assert_greater_than(element.getComputedTextLength(), 0);
+ }, `getComputedTextLength() should return nonzero values in a c-v:hidden subtree.`);
+
+ test(() => {
+ const element = document.querySelector('#tspan1');
+ assert_greater_than(element.getCharNumAtPosition(new DOMPoint(51, 101), 0), -1, "position");
+ }, `getCharNumAtPosition() should return nonzero values in a c-v:hidden subtree.`);
+
+ test(() => {
+ const element = document.querySelector('#tspan1');
+ assert_equals(element.getNumberOfChars(), 3);
+ }, `getNumberOfChars() should return nonzero values in a c-v:hidden subtree.`);
+
+ test(() => {
+ const element = document.querySelector('#tspan1');
+ const ctm = element.getCTM();
+ assert_equals(ctm.a, 2, 'a');
+ assert_equals(ctm.b, 0, 'b');
+ assert_equals(ctm.c, 0, 'c');
+ assert_equals(ctm.d, 2, 'd');
+ assert_equals(ctm.e, 0, 'e');
+ assert_equals(ctm.f, 0, 'f');
+ }, `getCTM() should return nonzero values in a c-v:hidden subtree.`);
+
+ test(() => {
+ const element = document.querySelector('#tspan1');
+ const ctm = element.getScreenCTM();
+ assert_equals(ctm.a, 2, 'a');
+ assert_equals(ctm.b, 0, 'b');
+ assert_equals(ctm.c, 0, 'c');
+ assert_equals(ctm.d, 2, 'd');
+ assert_equals(ctm.e, 0, 'e');
+ assert_equals(ctm.f, 0, 'f');
+ }, `getScreenCTM() 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-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-vs-scrollIntoView-001-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-001-ref.html
new file mode 100644
index 0000000000..746d770f85
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-001-ref.html
@@ -0,0 +1,42 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Nested CSS Content Visibility: auto + scrollIntoView</title>
+<link rel="author" title="Cathie Chen" href="mailto:cathiechen@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="Test if target scrollIntoView is visible when it is inside a nested content-visibility: auto">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+
+ .child {
+ height: 40000px;
+ position: relative;
+ }
+
+ #target {
+ position: absolute;
+ bottom: 0;
+ font: 25px/1 Ahem;
+ }
+
+ .before_target {
+ height: 40000px;
+ }
+</style>
+
+<div id=e1 class="before_target"></div>
+<div id=e2 class="before_target"></div>
+<div id=e3 class="before_target"></div>
+<div id=e4 class="before_target"></div>
+<div id=e5 class=child>
+ <div id=target>PASS</div>
+</div>
+
+<script>
+ window.onload = () => {
+ target.scrollIntoView();
+ requestAnimationFrame(takeScreenshot);
+ }
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-001.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-001.html
new file mode 100644
index 0000000000..b7af346257
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-001.html
@@ -0,0 +1,59 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Nested CSS Content Visibility: auto + scrollIntoView</title>
+<link rel="author" title="Cathie Chen" href="mailto:cathiechen@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-vs-scrollIntoView-001-ref.html">
+<meta name="assert"
+ content="Test if target scrollIntoView is visible when it is inside a nested content-visibility: auto">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+ .auto {
+ content-visibility: auto;
+ contain-intrinsic-size: auto 1px auto 10000px;
+ }
+
+ .child {
+ height: 40000px;
+ position: relative;
+ }
+
+ #target {
+ position: absolute;
+ bottom: 0;
+ font: 25px/1 Ahem;
+ }
+
+ .before_target {
+ height: 40000px;
+ }
+</style>
+
+<div id=e1 class="auto before_target"></div>
+<div id=e2 class="auto before_target"></div>
+<div id=e3 class=auto>
+ <div class=auto>
+ <div class=child></div>
+ <div class=auto>
+ <div class=child></div>
+ <div class=auto>
+ <div class=child>
+ <div id=target>PASS</div>
+ </div>
+ </div>
+ </div>
+ </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-vs-scrollIntoView-002-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-002-ref.html
new file mode 100644
index 0000000000..417549e919
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-002-ref.html
@@ -0,0 +1,59 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: auto + overflow clip + scrollIntoView</title>
+<link rel="author" title="Cathie Chen" href="mailto:cathiechen@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert"
+ content="Test if target scrollIntoView is hidden when it is inside the overflow area of a content-visibility: auto which is not relevent content">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+ .auto {
+ content-visibility: auto;
+ contain-intrinsic-size: auto 1px auto 10000px;
+ }
+
+ .child {
+ height: 40000px;
+ position: relative;
+ }
+
+ #target {
+ position: absolute;
+ bottom: 0;
+ }
+
+ .before_target {
+ height: 40000px;
+ }
+
+ #overflow_clip {
+ overflow: clip;
+ height: 20000px;
+ }
+</style>
+
+<div id=e1 class="auto before_target"></div>
+<div id=e2 class="auto before_target"></div>
+<div id=e3 class="auto">
+ <div id="overflow_clip">
+ <div class=child>
+ <div id=target>PASS</div>
+ </div>
+ </div>
+</div>
+<div id=e4 class=auto>
+ <div class=child></div>
+</div>
+
+
+<script>
+ function runTest() {
+ target.scrollIntoView();
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ }
+
+ window.onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-002.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-002.html
new file mode 100644
index 0000000000..5358fc6db8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-002.html
@@ -0,0 +1,63 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: auto + overflow clip + scrollIntoView</title>
+<link rel="author" title="Cathie Chen" href="mailto:cathiechen@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-vs-scrollIntoView-002-ref.html">
+<meta name="assert"
+ content="content-visibility: auto element not relevent to user should be hidden even after calling scrollIntoView of its descendant">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+ .auto {
+ content-visibility: auto;
+ contain-intrinsic-size: auto 1px auto 10000px;
+ }
+
+ .child {
+ height: 40000px;
+ position: relative;
+ }
+
+ #target {
+ position: absolute;
+ bottom: 0;
+ }
+
+ .before_target {
+ height: 40000px;
+ }
+
+ #overflow_clip {
+ overflow: clip;
+ height: 20000px;
+ }
+</style>
+
+<div id=e1 class="auto before_target"></div>
+<div id=e2 class="auto before_target"></div>
+<div id=e3 class="auto">
+ <div id="overflow_clip">
+ <div class=child>
+ <div id=target>PASS</div>
+ </div>
+ </div>
+</div>
+<div id=e4 class=auto>
+ <div class=child></div>
+</div>
+
+<script>
+ function runTest() {
+ target.scrollIntoView();
+ requestAnimationFrame(() => requestAnimationFrame(() => {
+ // Remove the fixed value of height, so that the computed height would be 40000px.
+ // e3 should be hidden now, "PASS" should not show up.
+ overflow_clip.style.height = "auto";
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+ }));
+ }
+ window.onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-003.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-003.html
new file mode 100644
index 0000000000..9fc9c5ff32
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-vs-scrollIntoView-003.html
@@ -0,0 +1,80 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: auto + overflow clip + scrollIntoView, ContentVisibilityAutoStateChange fires trece</title>
+<link rel="author" title="Cathie Chen" href="mailto:cathiechen@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert"
+ content="If content-visibility: auto element is not relevent to user after calling scrollIntoView of its descendant, contentvisibilityautostatechange trece">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/rendering-utils.js"></script>
+
+<style>
+ .auto {
+ content-visibility: auto;
+ contain-intrinsic-size: auto 1px auto 10000px;
+ }
+
+ .child {
+ height: 40000px;
+ position: relative;
+ }
+
+ #target {
+ position: absolute;
+ bottom: 0;
+ }
+
+ .before_target {
+ height: 40000px;
+ }
+
+ #overflow_clip {
+ overflow: clip;
+ height: 20000px;
+ }
+</style>
+
+<div id=e1 class="auto before_target"></div>
+<div id=e2 class="auto before_target"></div>
+<div id=e3 class="auto">
+ <div id="overflow_clip">
+ <div class=child>
+ <div id=target>PASS</div>
+ </div>
+ </div>
+</div>
+<div id=e4 class=auto>
+ <div class=child></div>
+</div>
+
+<script>
+function waitForEvent() {
+ return new Promise(resolve => e3.addEventListener('contentvisibilityautostatechange', resolve, { once: true }));
+}
+
+promise_test(async (t) => {
+ var eventCounter = 0;
+ function eventHandler(e) {
+ eventCounter++;
+ if (eventCounter == 1) {
+ assert_equals(e.skipped, true, "the first event is the initial one");
+ } else if (eventCounter == 2) {
+ assert_equals(e.skipped, false, "the second event should be generated by visible");
+ } else if (eventCounter == 3) {
+ assert_equals(e.skipped, true, "the third event should be generated by hidden");
+ }
+ }
+
+ e3.addEventListener("contentvisibilityautostatechange", eventHandler);
+ // Make sure the first event has fired.
+ await waitForEvent();
+ target.scrollIntoView();
+ await waitForEvent();
+ await waitForEvent();
+ await waitForAtLeastOneFrame();
+ assert_equals(eventCounter, 3, "There should be three contentvisibilityautostatechange events.");
+}, "ContentVisibilityAutoStateChange fires trece when `scrollIntoView` a descendant of `content-visibility:auto` which is hidden after scrolling");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-web-animation-in-auto-subtree.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-web-animation-in-auto-subtree.html
new file mode 100644
index 0000000000..a663e58fe0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-web-animation-in-auto-subtree.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<meta charset=utf8>
+<title>Web Animation does not stop even if target is hidden by c-v</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: auto;
+}
+@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="spacer"></div>
+ <div id="container"></div>
+</body>
+<script>
+"use strict";
+
+function createElementWithWebAnimation(test) {
+ const container = document.getElementById('container');
+ const target = document.createElement('div');
+ container.appendChild(target);
+ target.id = 'target';
+ const keyframes = [
+ { opacity: 1 },
+ { opacity: 0 },
+ ];
+ const options = {
+ duration: 2000,
+ iterations: 1,
+ easing: 'linear',
+ direction: 'alternate',
+ };
+ target.animate(keyframes, options);
+
+ return target;
+}
+
+promise_test(async t => {
+ // Make sure the target is hidden from the beginning.
+ document.getElementById("spacer").style.height = "300vh";
+ const target = createElementWithWebAnimation(t);
+ const animation = target.getAnimations()[0];
+
+ let animationFinishEvent = false;
+ animation.addEventListener('finish', () => {
+ animationFinishEvent = true;
+ });
+
+ animation.currentTime = 1999;
+ await animation.ready;
+ await waitForAnimationFrames(2);
+
+ assert_true(animationFinishEvent,
+ 'Web Animation event should keep going even if target is hidden by c-v');
+}, 'Web Animation does not stop even if target is hidden by c-v');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-float-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-float-crash.html
new file mode 100644
index 0000000000..22f86775a3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-float-crash.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <style>
+ * {
+ content-visibility: hidden;
+ float: inline-start;
+ }
+ </style>
+</head>
+
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-000.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-000.html
new file mode 100644
index 0000000000..fef4f5e540
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-000.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: popover doesn't show when hidden</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@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 popovers 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
+<div popover id=popover>Fail<div id=inner></div></div>
+</div>
+
+<script>
+function runTest() {
+ popover.showPopover();
+ takeScreenshot();
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-001.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-001.html
new file mode 100644
index 0000000000..fb3c9096da
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-001.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: popover doesn't show when hidden after render</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@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 popovers 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
+<div popover id=popover>Fail<div id=inner></div></div>
+</div>
+
+<script>
+function runTest() {
+ container.classList.add("hidden");
+ popover.showPopover();
+ takeScreenshot();
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-002.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-002.html
new file mode 100644
index 0000000000..48b436f4de
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-002.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: popover doesn't show when hidden after render</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@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 popovers 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
+<div popover id=popover>popover<div id=inner></div></div>
+</div>
+
+<script>
+function runTest() {
+ container.classList.add("hidden");
+ popover.showPopover();
+ inner.getBoundingClientRect();
+
+ takeScreenshot();
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-003.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-003.html
new file mode 100644
index 0000000000..df3cf07a01
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-003.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: popover shows when rendered</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-with-popover-top-layer-ref.html">
+<meta name="assert" content="top layer popovers 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 }
+#popover { outline: none; }
+</style>
+
+<div id=container class=box>
+This test passes if you can see “PASS” in a white box.
+<div popover id=popover>PASS<div id=inner></div></div>
+</div>
+text
+
+<script>
+function unhide() {
+ container.classList.remove("hidden");
+ takeScreenshot();
+}
+
+function runTest() {
+ container.classList.add("hidden");
+ popover.showPopover();
+ requestAnimationFrame(unhide);
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-004.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-004.html
new file mode 100644
index 0000000000..bbf4567e37
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-004.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: popover shows under c-v auto</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="spacer-with-popover-top-layer-ref.html">
+<meta name="assert" content="top layer popovers 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
+<div popover id=popover>PASS<div id=inner></div></div>
+</div>
+
+<script>
+function runTest() {
+ popover.showPopover();
+ takeScreenshot();
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-005.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-005.html
new file mode 100644
index 0000000000..264d7b317e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-005.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: popover shows under c-v auto</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="spacer-with-popover-top-layer-ref.html">
+<meta name="assert" content="top layer popovers 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
+<div popover id=popover><div id=inner class="auto">PASS</div></div>
+</div>
+
+<script>
+function runTest() {
+ popover.showPopover();
+ takeScreenshot();
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-006.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-006.html
new file mode 100644
index 0000000000..36989f79d1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-006.html
@@ -0,0 +1,38 @@
+<!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="Rob Buis" href="mailto:rbuis@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>
+<script src="/common/rendering-utils.js"></script>
+
+<style>
+#inner {
+ content-visibility: auto;
+ contain-intrinsic-size: 100px 100px;
+}
+</style>
+
+<div popover id="popover">
+ <div id="spacer" style="height: 100000px;"></div>
+ <div id="inner">
+ <div style="height: 200px; width: 200px;">content</div>
+ </div>
+</div>
+
+<script>
+promise_test(async () => {
+ popover.showPopover();
+ // It takes at least one frame to determine the proximity to the viewport.
+ await waitForAtLeastOneFrame();
+
+ // Even though the element with `content-visibility: auto` has an ancestor
+ // in the top layer, this element is not in the top layer list (although
+ // it's in the top layer stacking context). This means it should not be
+ // relevant to the user, because it is not onscreen.
+ assert_equals(inner.getBoundingClientRect().height, 100);
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-and-auto-descendant-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-and-auto-descendant-ref.html
new file mode 100644
index 0000000000..211bb89a33
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-and-auto-descendant-ref.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<meta charset="utf8">
+<title>CSS Content Visibility: content-visibility: auto descendant in popover is shown on showPopover"</title>
+<meta name="assert" content="content-visibility: auto descendant in popover is shown on showPopover">
+
+<div id="spacer" style="height: 100vh"></div>
+<div popover="manual" style="display: block; position: static;" id="popover">
+ <span>Test passes if this is visible</span>
+</div>
+
+<script>
+ popover.showPopover();
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-and-auto-descendant.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-and-auto-descendant.html
new file mode 100644
index 0000000000..aed0227ef1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-and-auto-descendant.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: content-visibility: auto descendant in popover is shown on showPopover</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-with-popover-top-layer-and-auto-descendant-ref.html">
+<meta name="assert" content="content-visibility: auto descendant in popover is shown on showPopover">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#inner {
+ content-visibility: auto;
+ contain-intrinsic-size: 100px 100px;
+}
+</style>
+
+<div id="spacer" style="height: 100vh"></div>
+<div popover="manual" style="display: block; position: static;" id="popover">
+ <span id="inner">Test passes if this is visible</span>
+</div>
+
+<script>
+function runTest() {
+ popover.showPopover();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = runTest;
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-hide-after-addition.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-hide-after-addition.html
new file mode 100644
index 0000000000..e3934bf46f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-hide-after-addition.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: popover doesn't show when hidden after showModal()</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@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 popovers 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
+<div popover id=popovers>FAIL<div id=inner></div></div>
+</div>
+
+<script>
+function runTest() {
+ popovers.showPopover();
+ 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-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..7fb1f20b7e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-003.html
@@ -0,0 +1,37 @@
+<!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 }
+#dialog { outline: none; }
+</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..79a7993e26
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-006.html
@@ -0,0 +1,45 @@
+<!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>
+<script src="/common/rendering-utils.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>
+promise_test(async () => {
+ dialog.show();
+ // It takes at least one frame to determine the proximity to the viewport.
+ await waitForAtLeastOneFrame();
+ assert_equals(inner.getBoundingClientRect().height, 100);
+
+ dialog.close();
+ dialog.showModal();
+
+ // Even though the element with `content-visibility: auto` has an ancestor
+ // in the top layer, this element is not in the top layer list (although
+ // it's in the top layer stacking context). This means it should not be
+ // relevant to the user, because it is nevertheless not onscreen.
+ // It takes at least one frame to determine the proximity to the viewport.
+ await waitForAtLeastOneFrame();
+ assert_equals(inner.getBoundingClientRect().height, 100);
+ dialog.close();
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-007.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-007.html
new file mode 100644
index 0000000000..028f818133
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-007.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<meta charset="utf8">
+<title>CSS Content Visibility: onscreen c-v auto content is relevant when in top layer</title>
+<link rel="author" title="Cathie Chen" href="mailto:cathiechen@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="onscreen c-v auto content is relevant when in top layer">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/rendering-utils.js"></script>
+
+<style>
+#inner {
+ content-visibility: auto;
+ contain-intrinsic-size: 100px 100px;
+}
+</style>
+
+<dialog id="dialog">
+ <div id="inner">
+ <div style="height: 200px; width: 200px;">content</div>
+ </div>
+ <div id="spacer" style="height: 100000px;"></div>
+</dialog>
+
+<script>
+promise_test(async () => {
+ dialog.show();
+ // It takes at least one frame to determine the proximity to the viewport.
+ await waitForAtLeastOneFrame();
+ assert_equals(inner.getBoundingClientRect().height, 200);
+
+ dialog.close();
+ dialog.showModal();
+
+ // It takes at least one frame to determine the proximity to the viewport.
+ await waitForAtLeastOneFrame();
+ assert_equals(inner.getBoundingClientRect().height, 200);
+ dialog.close();
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-008.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-008.html
new file mode 100644
index 0000000000..2911ef7783
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-008.html
@@ -0,0 +1,46 @@
+<!doctype html>
+<meta charset="utf8">
+<title>CSS Content Visibility: Contentvisibilityautostatechange fires once when c-v auto's dialog ancestor show</title>
+<link rel="author" title="Cathie Chen" href="mailto:cathiechen@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="Contentvisibilityautostatechange fires once when c-v auto's dialog ancestor show">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/rendering-utils.js"></script>
+
+<style>
+#inner {
+ content-visibility: auto;
+ contain-intrinsic-size: 100px 100px;
+}
+</style>
+
+<dialog id="dialog">
+ <div id="inner">
+ <div style="height: 200px; width: 200px;">content</div>
+ </div>
+ <div id="spacer" style="height: 100000px;"></div>
+</dialog>
+
+<script>
+promise_test(async () => {
+ let count = 0;
+ inner.addEventListener("contentvisibilityautostatechange", (e) => {
+ count++;
+ });
+
+ dialog.show();
+ // getBoundingClientRect shouldn't trigger "contentvisibilityautostatechange", because the proximity to the viewport is not determined now.
+ inner.getBoundingClientRect().height;
+
+ // It takes at least one frame to determine the proximity to the viewport.
+ await waitForAtLeastOneFrame();
+ // getBoundingClientRect should trigger "contentvisibilityautostatechange" now.
+ inner.getBoundingClientRect().height;
+
+ await waitForAtLeastOneFrame();
+ assert_equals(count, 1);
+ dialog.close();
+}, "Contentvisibilityautostatechange fires once when c-v auto's dialog ancestor show()");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-and-auto-descendant-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-and-auto-descendant-ref.html
new file mode 100644
index 0000000000..40a2d9acd3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-and-auto-descendant-ref.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<meta charset="utf8">
+<title>CSS Content Visibility: content-visibility: auto descendant in dialog is shown on showModal"</title>
+<meta name="assert" content="content-visibility: auto descendant in dialog is shown on showModal">
+
+<div id="spacer" style="height: 100vh"></div>
+<dialog id="dialog" style="display: block; position: static;">
+ <span>Test passes if this is visible</span>
+</dialog>
+
+<script>
+ dialog.showModal();
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-and-auto-descendant.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-and-auto-descendant.html
new file mode 100644
index 0000000000..a55337bf44
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-and-auto-descendant.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: content-visibility: auto descendant in dialog is shown on showModal</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-with-top-layer-and-auto-descendant-ref.html">
+<meta name="assert" content="content-visibility: auto descendant in dialog is shown on showModal">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#inner {
+ content-visibility: auto;
+ contain-intrinsic-size: 100px 100px;
+}
+</style>
+
+<div id="spacer" style="height: 100vh"></div>
+<dialog id="dialog" style="display: block; position: static;">
+ <span id="inner">Test passes if this is visible</span>
+</dialog>
+
+<script>
+function runTest() {
+ dialog.showModal();
+ requestAnimationFrame(takeScreenshot);
+}
+
+window.onload = runTest;
+</script>
+</html>
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-visibility-with-top-layer-in-auto-subtree-removal.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-in-auto-subtree-removal.html
new file mode 100644
index 0000000000..af7be86152
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-with-top-layer-in-auto-subtree-removal.html
@@ -0,0 +1,43 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: test top layer dialog removal in on-screen c-v:auto subtree</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<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="test top layer dialog removal in on-screen c-v:auto subtree">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#container {
+ width: 150px;
+ height: 150px;
+ background: lightblue;
+ content-visibility: auto;
+}
+#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>
+<dialog id=dialog >FAIL<div id=inner></div></dialog>
+</div>
+
+<script>
+function runTest() {
+ dialog.showModal();
+ inner.getBoundingClientRect();
+
+ dialog.close();
+
+ takeScreenshot();
+}
+
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-with-popover-top-layer-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-with-popover-top-layer-ref.html
new file mode 100644
index 0000000000..59b2304d9e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-with-popover-top-layer-ref.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf8">
+<title>CSS Content Visibility: popover shows when rendered (ref)</title>
+
+<style>
+.box { width: 100px; height: 100px; border: 1px solid black; }
+#popover { outline: none; }
+</style>
+
+<div id=container class=box>
+This test passes if you can see “PASS” in a white box.
+<div popover id=popover>PASS<div id=inner></div></div>
+</div>
+text
+
+<script>
+popover.showPopover();
+</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..eadc5f65d1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-with-top-layer-ref.html
@@ -0,0 +1,18 @@
+<!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; }
+dialog { outline: none; }
+</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..fe6d79a694
--- /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 shadowrootmode=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/content-visibility-transition-finished-001.html b/testing/web-platform/tests/css/css-contain/content-visibility/crashtests/content-visibility-transition-finished-001.html
new file mode 100644
index 0000000000..ef7fb001ed
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/crashtests/content-visibility-transition-finished-001.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html class="test-wait">
+<meta charset="utf-8">
+<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1822907">
+<style>
+ #inner {
+ /* Extremely short so that we can just do a double-rAF and
+ * expect that this transition will have completed: */
+ transition: opacity 0.01s;
+ }
+</style>
+<script>
+ function setup() {
+ // Flush style, in case the document hasn't been styled yet:
+ let origOpacity = getComputedStyle(inner).opacity;
+
+ // Trigger the (extremely short) transition, and proceed to next step
+ // when it finishes.
+ inner.addEventListener("transitionend", handleTransitionEnd);
+ inner.style.opacity = "0.8";
+ }
+ function handleTransitionEnd(e) {
+ // Hide & unhide the subtree that contained the transition:
+ foo.style.contentVisibility = "hidden";
+ document.documentElement.offsetHeight; // flush layout
+ foo.style.contentVisibility = "";
+
+ // Double-rAF to see if we crash when animations are resampled.
+ requestAnimationFrame(() => { requestAnimationFrame(finish) });
+ }
+ function finish() {
+ // If we get here, we've succeeded; hooray!
+ document.documentElement.removeAttribute("class");
+ }
+</script>
+<body onload="setup()">
+ <div id="foo">
+ Hello
+ <div id="inner">Inner</div>
+ </div>
+</body>
+</html>
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/crashtests/grid-dynamic.html b/testing/web-platform/tests/css/css-contain/content-visibility/crashtests/grid-dynamic.html
new file mode 100644
index 0000000000..efc6585961
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/crashtests/grid-dynamic.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<div id="target" style="display:grid;">
+ text
+</div>
+<script>
+const target = document.getElementById('target');
+document.body.offsetTop;
+target.style.contentVisibility = 'hidden';
+document.body.offsetTop;
+target.style.contentVisibility = '';
+</script>
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/display-ruby-text-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/display-ruby-text-crash.html
new file mode 100644
index 0000000000..85ccd459af
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/display-ruby-text-crash.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:vmpstr@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1515531">
+
+<style>
+body,table,tbody{
+ content-visibility: hidden;
+ display: ruby-text;
+}
+</style>
+
+<marquee></marquee>
+<u style="height: 100px; width: 100px; overflow: scroll; display: block;" dir="ltr"></u>
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/locked-frame-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/locked-frame-crash.html
new file mode 100644
index 0000000000..dce0baa62e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/locked-frame-crash.html
@@ -0,0 +1,8 @@
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="help" href="https://crbug.com/1309693">
+
+<iframe id="target" width=320 height=320></iframe>
+<style>
+:first-child { content-visibility: hidden; }
+html,body,ol { -webkit-column-count: 2; }
+</style>
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..f41c337965
--- /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 shadowrootmode=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/resources/text-fragment-target-matchable.html b/testing/web-platform/tests/css/css-contain/content-visibility/resources/text-fragment-target-matchable.html
new file mode 100644
index 0000000000..6d57a2ebbd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/resources/text-fragment-target-matchable.html
@@ -0,0 +1,61 @@
+<!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;
+}
+</style>
+
+<body onload="doubleRafCheckScroll()">
+<div class=spacer></div>
+<div hidden=until-found>
+ <div id=text>hiddentext</div>
+</div>
+<div class=spacer></div>
+<div id=text2and3ancestor>
+ <div hidden=until-found>
+ <div id=text2>start</div>
+ </div>
+ <div class=spacer></div>
+ <div hidden=until-found>
+ <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..da5e51c6d2
--- /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 shadowrootmode=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..a8d86a3e7a
--- /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 shadowrootmode=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..bf64ac5c5b
--- /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 shadowrootmode=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..51bdfd3f62
--- /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 shadowrootmode=open>
+ <slot style="content-visibility: hidden; display: block"></slot>
+ </template>
+ a
+</div>
+<iframe src="resources/slot-content-visibility.html"></iframe>
+<div>
+ <template shadowrootmode=open>
+ <slot style="content-visibility: hidden; display: block"></slot>
+ </template>
+ a
+</div>
+<iframe src="resources/slot-content-visibility.html"></iframe>
+<div>
+ <template shadowrootmode=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..8e2937312c
--- /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 shadowrootmode=open>
+ <slot style="content-visibility:hidden; display:block"></slot>
+ </template>
+ <div id='id6'>
+ <template shadowrootmode=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..d9b950a00c
--- /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 shadowrootmode=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..74fdff2bf2
--- /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 shadowrootmode=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..c4d0c804a8
--- /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 shadowrootmode=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..8ae5872862
--- /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 shadowrootmode=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..d3816a5e94
--- /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 shadowrootmode=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..2d3a9865af
--- /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 shadowrootmode=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..077a47d3f3
--- /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 shadowrootmode=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..e206bdf43b
--- /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 shadowrootmode=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..eb6acc8526
--- /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 shadowrootmode=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..74e214dc1b
--- /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 shadowrootmode=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-popover-top-layer-ref.html b/testing/web-platform/tests/css/css-contain/content-visibility/spacer-with-popover-top-layer-ref.html
new file mode 100644
index 0000000000..6c4c65f58c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/spacer-with-popover-top-layer-ref.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf8">
+<title>CSS Content Visibility: popover 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
+<div popover id=popover>PASS<div id=inner></div></div>
+</div>
+
+<script>
+popover.showPopover();
+</script>
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..b5cb1f108e
--- /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>
diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/touch-action-beside-display-locked-fixedpos-iframe-crash.html b/testing/web-platform/tests/css/css-contain/content-visibility/touch-action-beside-display-locked-fixedpos-iframe-crash.html
new file mode 100644
index 0000000000..920305c14d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/content-visibility/touch-action-beside-display-locked-fixedpos-iframe-crash.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+ <link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1434550">
+ <button id="boo"></button>
+ <div>
+ <iframe style="position:fixed; content-visibility:hidden;"></iframe>
+ </div>
+ <script>
+ requestAnimationFrame(()=> {
+ requestAnimationFrame(()=> {
+ boo.style.touchAction = "pan-x";
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ });
+ </script>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/counter-scoping-001.html b/testing/web-platform/tests/css/css-contain/counter-scoping-001.html
new file mode 100644
index 0000000000..ab948e1908
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/counter-scoping-001.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment and counter-increment</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="counter-increment is scoped to the subtree and creates a new counter at the root of the subtree">
+ <link rel="match" href="reference/counter-scoping-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<style>
+div {
+ contain: style;
+ counter-increment: n;
+}
+div::before, div::after {
+ content: counters(n, '.') " ";
+}
+div::after {
+ counter-increment: n 2;
+}
+</style>
+
+<p>Test passes if the text below is "1 1.2" (not including the quotation marks).<p>
+<div></div>
+
diff --git a/testing/web-platform/tests/css/css-contain/counter-scoping-002.html b/testing/web-platform/tests/css/css-contain/counter-scoping-002.html
new file mode 100644
index 0000000000..077dca5b7a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/counter-scoping-002.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment and counter-set</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="counter-set is scoped to the subtree and creates a new counter at the root of the subtree">
+ <link rel="match" href="reference/counter-scoping-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
+ <link rel=help href="https://drafts.csswg.org/css-lists-3/#propdef-counter-set">
+
+<style>
+div {
+ contain: style;
+ counter-set: n 1;
+}
+div::before, div::after {
+ content: counters(n, '.') " ";
+}
+div::after {
+ counter-set: n 2;
+}
+</style>
+
+<p>Test passes if the text below is "1 1.2" (not including the quotation marks).<p>
+<div></div>
+
diff --git a/testing/web-platform/tests/css/css-contain/counter-scoping-003.html b/testing/web-platform/tests/css/css-contain/counter-scoping-003.html
new file mode 100644
index 0000000000..a12dbfa700
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/counter-scoping-003.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment and subtree root</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="When considering the effects of the scoped property on elements inside the subtree, the element at the base of the subtree is treated as if it was the root of the document">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
+ <link rel="match" href="reference/counter-scoping-003-ref.html">
+
+<style>
+div {
+ contain: style;
+ counter-increment: c 123;
+}
+span {
+ counter-increment: c 1;
+}
+span::before {
+ content: counter(c);
+}
+</style>
+
+<p>Test passes if the text below is "1 2" (not including the quotation marks).<p>
+<div>
+ <span></span>
+ <span></span>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-contain/counter-scoping-004.html b/testing/web-platform/tests/css/css-contain/counter-scoping-004.html
new file mode 100644
index 0000000000..3aad43f853
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/counter-scoping-004.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="UTF-8">
+<title>CSS-contain test: style containment and subtree root</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain-2/#property-scoped-to-a-sub-tree">
+<link rel="match" href="reference/counter-scoping-004-ref.html">
+<style>
+ .list-item {
+ contain: style;
+ counter-increment: my-list-counter;
+ margin-left: 40px;
+ }
+ .list-item::before {
+ content: '[' counter(my-list-counter, decimal) '] ';
+ }
+</style>
+<div class="list-item">
+ A1
+ <div class="list-item">B1</div>
+ <div class="list-item">B2</div>
+</div>
+<div class="list-item">A2</div>
+<div class="list-item">A3</div>
diff --git a/testing/web-platform/tests/css/css-contain/crashtests/contain-nested-crash-001.html b/testing/web-platform/tests/css/css-contain/crashtests/contain-nested-crash-001.html
new file mode 100644
index 0000000000..063563c260
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/crashtests/contain-nested-crash-001.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<link rel="help" href="https://crbug.com/1214198">
+<link rel="author" title="Koji Ishii" href="mailto:kojii@chromium.org">
+<style>
+.contain {
+ contain: strict;
+ display: block;
+ width: 100px;
+ height: 100px;
+}
+</style>
+<body>
+ <div id="outer" class="contain">
+ <div>
+ <div id="inner" class="contain"></div>
+ </div>
+ </div>
+<script>
+ document.body.offsetTop;
+ inner.appendChild(document.createTextNode('inner-child'));
+ outer.appendChild(document.createTextNode('outer-child'));
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/crashtests/contain-nested-crash-002.html b/testing/web-platform/tests/css/css-contain/crashtests/contain-nested-crash-002.html
new file mode 100644
index 0000000000..42dc06b993
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/crashtests/contain-nested-crash-002.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1340168">
+<div style="contain:size layout;">
+ <div id="klabb" style="display:inline-block; contain:size layout;">t</div>
+ <br>
+ <div id="babb" style="display:inline-block; width:10px; height:10px;"></div>
+</div>
+<script>
+ document.body.offsetTop;
+ klabb.innerHTML = ":-)";
+ klabb.style.height = "100px";
+ document.body.offsetTop;
+ babb.style.width = "20px";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/crashtests/contain-nested-crash-003.html b/testing/web-platform/tests/css/css-contain/crashtests/contain-nested-crash-003.html
new file mode 100644
index 0000000000..a7dbe7dcc3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/crashtests/contain-nested-crash-003.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1386673">
+<div style="contain:layout size;">
+ <div style="display:inline-block;">
+ <div style="contain:layout size;">
+ <div id="firstVictim"></div>
+ </div>
+ </div>
+ <div style="position:absolute;">
+ <div id="secondVictim"></div>
+ </div>
+</div>
+<script>
+ document.body.offsetTop;
+ firstVictim.style.display = "none";
+ secondVictim.style.display = "none";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/crashtests/contain-nested-crash-004.html b/testing/web-platform/tests/css/css-contain/crashtests/contain-nested-crash-004.html
new file mode 100644
index 0000000000..db29e1424d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/crashtests/contain-nested-crash-004.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1439692">
+<style>
+body, fieldset { contain: strict; }
+</style>
+<script>
+function crash() {
+ document.body.offsetTop;
+ document.body.appendChild(document.createElement("fieldset"));
+}
+</script>
+<body onload="crash()">
diff --git a/testing/web-platform/tests/css/css-contain/crashtests/contain-nested-relayout-boundary.html b/testing/web-platform/tests/css/css-contain/crashtests/contain-nested-relayout-boundary.html
new file mode 100644
index 0000000000..ce915728f4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/crashtests/contain-nested-relayout-boundary.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<div style="position: relative; width: 100px; height: 100px; overflow: hidden;">
+ <div id="target" style="contain: size layout;">
+ <canvas id="inner" width="0"></canvas>
+ </div>
+</div>
+<script>
+document.body.offsetTop;
+document.getElementById('inner').width = '100';
+document.getElementById('target').style.contain = 'initial';
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/inheritance.html b/testing/web-platform/tests/css/css-contain/inheritance.html
new file mode 100644
index 0000000000..07378a29f3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/inheritance.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Inheritance of CSS contain property</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<meta name="assert" content="Property 'contain' does not inherit.">
+<meta name="assert" content="Property 'contain' has initial value 'none'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/inheritance-testcommon.js"></script>
+</head>
+<body>
+<div id="container">
+<div id="target"></div>
+</div>
+<script>
+assert_not_inherited('contain', 'none', 'paint');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/parsing/contain-computed-children.html b/testing/web-platform/tests/css/css-contain/parsing/contain-computed-children.html
new file mode 100644
index 0000000000..b955bed76c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/parsing/contain-computed-children.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<title>CSS Containment Module Level 1: getComputedStyle().contain</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
+<meta name="assert" content="computed contain value for children should ignore container contain value.">
+<div id="container"><div id="target"></div></div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(() => {
+ ['none', 'style', 'layout', 'paint', 'size', 'strict', 'content'].forEach(value => {
+ container.style.contain = value;
+ assert_equals(getComputedStyle(target).contain, "none");
+ });
+}, "computed contain value for children should ignore container contain value");
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/parsing/contain-computed.html b/testing/web-platform/tests/css/css-contain/parsing/contain-computed.html
new file mode 100644
index 0000000000..02633953c5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/parsing/contain-computed.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Containment Module Level 3: getComputedStyle().contain</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#contain-property">
+<meta name="assert" content="contain computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("contain", "none");
+test_computed_value("contain", "strict");
+test_computed_value("contain", "content");
+
+test_computed_value("contain", "size");
+test_computed_value("contain", "layout");
+test_computed_value("contain", "style");
+test_computed_value("contain", "paint");
+test_computed_value("contain", "size layout");
+test_computed_value("contain", "style paint");
+test_computed_value("contain", "style layout paint", "content");
+test_computed_value("contain", "size style layout paint", "strict");
+test_computed_value("contain", "size layout paint", "size layout paint");
+test_computed_value("contain", "layout paint");
+test_computed_value("contain", "inline-size");
+test_computed_value("contain", "inline-size layout style paint");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/parsing/contain-invalid.html b/testing/web-platform/tests/css/css-contain/parsing/contain-invalid.html
new file mode 100644
index 0000000000..9f96bbc2fe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/parsing/contain-invalid.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Containment Module Level 3: parsing contain with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#contain-property">
+<meta name="assert" content="contain supports only the grammar 'none | strict | content | [ [ size | inline-size ] || layout || style || paint ]'.">
+<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("contain", "auto");
+test_invalid_value("contain", "layout layout");
+test_invalid_value("contain", "strict layout");
+test_invalid_value("contain", "paint strict");
+test_invalid_value("contain", "paint layout style paint");
+test_invalid_value("contain", "none none");
+test_invalid_value("contain", "none strict");
+test_invalid_value("contain", "strict strict");
+test_invalid_value("contain", "strict none");
+test_invalid_value("contain", "strict content");
+test_invalid_value("contain", "size layout size");
+test_invalid_value("contain", "paint content");
+test_invalid_value("contain", "size inline-size");
+test_invalid_value("contain", "inline-size inline-size");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/parsing/contain-valid.html b/testing/web-platform/tests/css/css-contain/parsing/contain-valid.html
new file mode 100644
index 0000000000..f7e18411da
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/parsing/contain-valid.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Containment Module Level 3: parsing contain with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#contain-property">
+<meta name="assert" content="contain supports the full grammar 'none | strict | content | [ [ size | inline-size ] || layout || style || paint ]'.">
+<meta name="assert" content="contain serializes in canonical order.">
+<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("contain", "none");
+test_valid_value("contain", "strict");
+test_valid_value("contain", "content");
+
+// [ [ size | inline-size ] || layout || style || paint ]
+test_valid_value("contain", "size");
+test_valid_value("contain", "layout");
+test_valid_value("contain", "style");
+test_valid_value("contain", "paint");
+test_valid_value("contain", "layout size", "size layout");
+test_valid_value("contain", "paint style", "style paint");
+test_valid_value("contain", "layout style paint");
+test_valid_value("contain", "layout paint style size", "size layout style paint");
+test_valid_value("contain", "inline-size");
+test_valid_value("contain", "layout inline-size", "inline-size layout");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/quote-scoping-001.html b/testing/web-platform/tests/css/css-contain/quote-scoping-001.html
new file mode 100644
index 0000000000..8c38e45b1a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/quote-scoping-001.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment and open-quote</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment cause the open-quote value of the content property are scoped to the element's subtree">
+ <link rel="match" href="reference/quote-scoping-001-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<style>
+
+div {
+ quotes: "A" "Z" "1" "9";
+}
+div::before, span::before {
+ content: open-quote;
+}
+div::after {
+ content: close-quote;
+}
+span {
+ contain: style;
+}
+</style>
+
+<p>Test passes if the text below is "A1Z" (not including the quotation marks).<p>
+<div><span></span></div>
diff --git a/testing/web-platform/tests/css/css-contain/quote-scoping-002.html b/testing/web-platform/tests/css/css-contain/quote-scoping-002.html
new file mode 100644
index 0000000000..9477afdfb1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/quote-scoping-002.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment and close-quote</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment cause the close-quote value of the content property are scoped to the element's subtree">
+ <link rel="match" href="reference/quote-scoping-002-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<style>
+
+div {
+ quotes: "A" "Z" "1" "9";
+}
+div::before {
+ content: open-quote;
+}
+div::after, span::after {
+ content: close-quote;
+}
+span {
+ contain: style;
+}
+</style>
+
+<p>Test passes if the text below is "AZZ" (not including the quotation marks).<p>
+<div><span></span></div>
diff --git a/testing/web-platform/tests/css/css-contain/quote-scoping-003.html b/testing/web-platform/tests/css/css-contain/quote-scoping-003.html
new file mode 100644
index 0000000000..2a909511c3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/quote-scoping-003.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment and no-open-quote</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment cause the no-open-quote value of the content property are scoped to the element's subtree">
+ <link rel="match" href="reference/quote-scoping-003-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<style>
+
+div {
+ quotes: "A" "Z" "1" "9";
+}
+div::before{
+ content: open-quote;
+}
+
+span::before {
+ content: no-open-quote;
+}
+div::after {
+ content: close-quote;
+}
+span {
+ contain: style;
+}
+</style>
+
+<p>Test passes if the text below is "AZ" (not including the quotation marks).<p>
+<div><span></span></div>
diff --git a/testing/web-platform/tests/css/css-contain/quote-scoping-004.html b/testing/web-platform/tests/css/css-contain/quote-scoping-004.html
new file mode 100644
index 0000000000..d86382be08
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/quote-scoping-004.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: style containment and no-close-quote</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="">
+ <meta name=assert content="style containment cause the no-close-quote value of the content property are scoped to the element's subtree">
+ <link rel="match" href="reference/quote-scoping-003-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<style>
+
+div {
+ quotes: "A" "Z" "1" "9";
+}
+div::before{
+ content: open-quote;
+}
+
+span::after {
+ content: no-close-quote;
+}
+div::after {
+ content: close-quote;
+}
+span {
+ contain: style;
+}
+</style>
+
+<p>Test passes if the text below is "AZ" (not including the quotation marks).<p>
+<div><span></span></div>
diff --git a/testing/web-platform/tests/css/css-contain/quote-scoping-empty-style-boundaries.html b/testing/web-platform/tests/css/css-contain/quote-scoping-empty-style-boundaries.html
new file mode 100644
index 0000000000..89614565ba
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/quote-scoping-empty-style-boundaries.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: nested style containment and the quote element following a style boundary without any quotes</title>
+ <link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+ <link rel="match" href="reference/quote-scoping-empty-style-boundaries-ref.html">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<div style="contain: style;">
+ <div style="contain: style;">
+ <q></q>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/quote-scoping-invalidation-001.html b/testing/web-platform/tests/css/css-contain/quote-scoping-invalidation-001.html
new file mode 100644
index 0000000000..61ec4a481f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/quote-scoping-invalidation-001.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSS-contain test: style containment dynamic containment set invalidation</title>
+<link rel="author" title="Daniil Sakhapov" href="sakhapov@google.com">
+<link rel="match" href="reference/quote-scoping-invalidation-001-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<style>
+ #root {
+ quotes: "A" "Z" "1" "9" "(" ")" "+" "-";
+ }
+ #root::before, #root span::before {
+ content: open-quote;
+ }
+ #root::after {
+ content: close-quote;
+ }
+ .contain-style {
+ contain: style;
+ }
+</style>
+
+<p>Test passes if the text below is "A1(19" (not including the quotation marks).<p>
+<div id="root">
+ <div id="scope">
+ <span id="span1"></span>
+ <span id="span2"></span>
+ </div>
+ <span></span>
+</div>
+
+<script>
+ document.body.offsetTop;
+ scope.style.contain = "style";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/quote-scoping-invalidation-002.html b/testing/web-platform/tests/css/css-contain/quote-scoping-invalidation-002.html
new file mode 100644
index 0000000000..727ee9a581
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/quote-scoping-invalidation-002.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSS-contain test: style containment dynamic containment set unset invalidation</title>
+<link rel="author" title="Daniil Sakhapov" href="sakhapov@google.com">
+<link rel="match" href="reference/quote-scoping-invalidation-002-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<style>
+ #root {
+ quotes: "A" "Z" "1" "9" "(" ")" "+" "-";
+ }
+ #root::before, #root span::before {
+ content: open-quote;
+ }
+ #root::after {
+ content: close-quote;
+ }
+ .contain-style {
+ contain: style;
+ }
+</style>
+
+<p>Test passes if the text below is "A1(+-" (not including the quotation marks).<p>
+<div id="root">
+ <div id="scope">
+ <span id="span1"></span>
+ <span id="span2"></span>
+ </div>
+ <span></span>
+</div>
+
+<script>
+ document.body.offsetTop;
+ scope.style.contain = "style";
+ document.body.offsetTop;
+ scope.style.contain = "";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/quote-scoping-invalidation-003.html b/testing/web-platform/tests/css/css-contain/quote-scoping-invalidation-003.html
new file mode 100644
index 0000000000..24e69eb38f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/quote-scoping-invalidation-003.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSS-contain test: style containment dynamic containment set unset set invalidation</title>
+<link rel="author" title="Daniil Sakhapov" href="sakhapov@google.com">
+<link rel="match" href="reference/quote-scoping-invalidation-003-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<style>
+ #root {
+ quotes: "A" "Z" "1" "9" "(" ")" "+" "-";
+ }
+ #root::before, #root span::before {
+ content: open-quote;
+ }
+ #root::after {
+ content: close-quote;
+ }
+ .contain-style {
+ contain: style;
+ }
+</style>
+
+<p>Test passes if the text below is "A119" (not including the quotation marks).<p>
+<div id="root">
+ <div id="scope">
+ <span id="span1"></span>
+ <span id="span2"></span>
+ </div>
+ <span></span>
+</div>
+
+<script>
+ document.body.offsetTop;
+ scope.style.contain = "style";
+ document.body.offsetTop;
+ scope.style.contain = "";
+ document.body.offsetTop;
+ scope.style.contain = "style";
+ document.body.offsetTop;
+ span1.remove();
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/quote-scoping-invalidation-004.html b/testing/web-platform/tests/css/css-contain/quote-scoping-invalidation-004.html
new file mode 100644
index 0000000000..11b0d24f66
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/quote-scoping-invalidation-004.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSS-contain test: style containment invalidation with elements in different subtrees</title>
+<link rel="author" title="Daniil Sakhapov" href="sakhapov@google.com">
+<link rel="match" href="reference/quote-scoping-invalidation-004-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<style>
+ #root {
+ quotes: "A" "Z" "1" "9" "(" ")" "+" "-";
+ }
+ #root::before, #root span::before {
+ content: open-quote;
+ }
+ #root::after {
+ content: close-quote;
+ }
+ .contain-style {
+ contain: style;
+ }
+</style>
+
+<p>Test passes if the text below is "A111119" (not including the quotation marks).<p>
+<div id="root">
+ <div class="contain-style">
+ <span id="span1"></span>
+ <span id="span2"></span>
+ </div>
+ <div class="contain-style">
+ <span id="span3"></span>
+ <span id="span4"></span>
+ </div>
+ <span></span>
+</div>
+
+<script>
+ document.body.offsetTop;
+ span1.className = "contain-style";
+ span3.className = "contain-style";
+</script>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-baseline-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-baseline-ref.html
new file mode 100644
index 0000000000..1fdecb1c33
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-baseline-ref.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<html lang=en>
+<meta charset=utf-8>
+<title>CSS test reference</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<style>
+div {
+ display: inline-block;
+ height: 5px;
+ background: blue;
+ width: 50px;
+ color: transparent;
+ font-size: 100px;
+}
+</style>
+
+<p>Test passes if there are two, not one, blue lines below.</p>
+<div></div><div>a</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-body-bg-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-body-bg-001-ref.html
new file mode 100644
index 0000000000..1d6357e173
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-body-bg-001-ref.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test reference</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+
+<style>
+html, body, p {
+ margin: 0;
+ width: 300px;
+ height: 200px;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-body-overflow-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-body-overflow-001-ref.html
new file mode 100644
index 0000000000..32bc8b0eaf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-body-overflow-001-ref.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test referemce</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+
+<style>
+html, body, p, div {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+}
+</style>
+
+<p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-body-t-o-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-body-t-o-001-ref.html
new file mode 100644
index 0000000000..ecf9d031a3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-body-t-o-001-ref.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test reference</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+
+<style>
+html {
+ writing-mode: vertical-lr;
+ direction: rtl;
+ width: 100vw;
+ height: 100vh;
+ overflow: hidden;
+}
+body {
+ margin: 0;
+ border-top: 100px solid red;
+ border-bottom: 100px solid green;
+ width: 100vw;
+ height: 100vh;
+}
+div {
+ text-orientation: upright;
+}
+p {
+ margin: auto;
+ padding: 150px 0;
+ writing-mode: horizontal-tb;
+ direction: ltr;
+}
+</style>
+
+<div>
+ <p>Test passes if there is no red.
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-body-w-m-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-body-w-m-001-ref.html
new file mode 100644
index 0000000000..3341816e2b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-body-w-m-001-ref.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test reference</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+
+<style>
+html::before {
+ content: "";
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: block;
+}
+body { margin: 0; }
+p {
+ margin: 0;
+ width: 200px;
+ height: 200px;
+}
+</style>
+
+<p>Test passes if the orange square is in the upper-left corner.
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-content-011-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-content-011-ref.html
new file mode 100644
index 0000000000..00ad302ca4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-content-011-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div#green-square
+ {
+ background-color: green;
+ height: 100px;
+ width: 100px;
+ }
+
+ div#result
+ {
+ font-size: 3em;
+ }
+ </style>
+
+ <p>Test passes if there is a filled green square, no red and the number 17.
+
+ <div id="green-square"></div>
+
+ <div id="result">17</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-layout-020-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-layout-020-ref.html
new file mode 100644
index 0000000000..9a0eab3afe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-layout-020-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>CSS Containment Test: Removing layout containment and contained positioned elements</title>
+
+<style>
+.container {
+ width: 300px;
+ height: 300px;
+}
+.box {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+}
+.fixed {
+ position: fixed;
+ top: 0;
+ left: 0;
+}
+.abspos {
+ position: absolute;
+ top: 0;
+ right: 0;
+}
+</style>
+
+<div class="container">
+ <div class="fixed box"></div>
+ <div class="abspos box"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-layout-021-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-layout-021-ref.html
new file mode 100644
index 0000000000..c29b12e137
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-layout-021-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment fixed positioned descendants</title>
+<style>
+#green {
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+body {
+ height: 3000px;
+ margin: 0px;
+}
+#spacer {
+ height: 200px;
+}
+</style>
+<script>
+function runTest() {
+ document.documentElement.scrollTop += 200;
+}
+</script>
+<body onload="runTest()">
+<div id="spacer"></div>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="green"></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-layout-baseline-004-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-layout-baseline-004-ref.html
new file mode 100644
index 0000000000..69658a7004
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-layout-baseline-004-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+ display: inline-block;
+ font: 100px/1 Ahem;
+ width: 100px;
+ height: 100px;
+}
+#first {
+ color: blue;
+ position: relative;
+ top: 20px;
+}
+#second {
+ color: green;
+}
+</style>
+<p>Test passes if there is not a rectangle as the two boxes ("blue" and "green") are not baseline aligned.</p>
+<div id="first">X</div><div id="second">X</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-layout-baseline-005-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-layout-baseline-005-ref.html
new file mode 100644
index 0000000000..360652c939
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-layout-baseline-005-ref.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+.wrapper {
+ height: 110px;
+}
+.wrapper > * {
+ vertical-align: bottom;
+ background: cyan;
+ font-size: 20px;
+}
+.wrapper > :nth-child(1) {
+ background: magenta;
+}
+.inline-block {
+ display: inline-block;
+}
+canvas {
+ width: 100px;
+ height: 100px;
+}
+fieldset, details {
+ display: inline-block;
+ width: max-content;
+}
+</style>
+<p>Test passes if it has the same output than the reference (all elements are aligned on the bottom edge).</p>
+<div class="wrapper">
+ <div class="inline-block" style="font-size: 80px;">foo</div>
+ <div class="inline-block">foo</div>
+ <div class="inline-block" style="border: solid thick; padding: 2px;">foo</div>
+ <div style="display: inline-flex;">foo</div>
+ <div style="display: inline-flex; border: solid thick; padding: 2px;">foo</div>
+ <div style="display: inline-grid;">foo</div>
+ <div style="display: inline-grid; border: solid thick; padding: 2px;">foo</div>
+</div>
+<div class="wrapper">
+ <canvas></canvas>
+ <div class="inline-block">foo</div>
+ <button>foo</button>
+ <select><option>foo</option></select>
+ <select multiple style="height: 40px;"><option>foo</option></select>
+ <textarea style="height: 40px;"></textarea>
+</div>
+<div class="wrapper">
+ <canvas></canvas>
+ <input value="foo" size="3"></input>
+ <input type="file"></input>
+</div>
+<div class="wrapper">
+ <canvas></canvas>
+ <table style="display: inline-table;"><tr><td>foo</td></tr></table>
+ <canvas></canvas>
+ <fieldset></fieldset>
+ <fieldset><legend>foo</legend></fieldset>
+ <fieldset><legend>foo</legend>foo</fieldset>
+ <details></details>
+ <details><summary>foo</summary>foo</details> <details open="true"><summary>foo</summary>foo</details>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-layout-breaks-002-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-layout-breaks-002-ref.html
new file mode 100644
index 0000000000..72a3beff84
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-layout-breaks-002-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div
+ {
+ float: left;
+ }
+
+ img
+ {
+ vertical-align: top;
+ }
+ </style>
+
+ <p>Test passes if there is a) a blue square below a yellow square and b) an orange square below a blue square.
+
+ <div>
+ <img src="../support/swatch-yellow.png" width="100" height="100" alt="Image download support must be enabled">
+ <br>
+ <img src="../support/swatch-blue.png" width="100" height="100" alt="Image download support must be enabled">
+ <br>
+ <img src="../support/swatch-orange.png" width="100" height="100" alt="Image download support must be enabled">
+ </div>
+
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-layout-button-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-layout-button-001-ref.html
new file mode 100644
index 0000000000..da83204dce
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-layout-button-001-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+div.fakeButton {
+ display: inline-block;
+ border: 5px solid green;
+ padding: 0;
+ margin-bottom: 2px;
+ color: transparent;
+ width: 0;
+ height: 0px;
+ /* Layout containment creates a stacking context, the following lines simuluate the same in the reference file. */
+ position: relative;
+ z-index: 1;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square aligned 2px above the text's baseline, and then the word "after".</p>
+before<div class="fakeButton"></div>after
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-layout-cell-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-layout-cell-001-ref.html
new file mode 100644
index 0000000000..9ff7f45e39
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-layout-cell-001-ref.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ table
+ {
+ background-color: blue;
+ border-spacing: 2px;
+ height: 206px;
+ table-layout: fixed;
+ width: 206px;
+ }
+
+ td
+ {
+ background-color: white;
+ padding: 0px;
+ vertical-align: baseline;
+ }
+
+ span
+ {
+ background-color: green;
+ color: white;
+ font-family: monospace;
+ vertical-align: top;
+ }
+ </style>
+
+ <p>Test passes if there is the word PASS and if there is <strong>no red</strong>.
+
+ <table>
+
+ <tr><td>&nbsp;<td>&nbsp;
+
+ <tr><td>&nbsp;<td><span>PASS</span>
+
+ </table>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-layout-flexbox-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-layout-flexbox-001-ref.html
new file mode 100644
index 0000000000..832e4c72c2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-layout-flexbox-001-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+div {
+ display: inline-flex;
+ border: 5px solid green;
+ /* Layout containment creates a stacking context, the following lines simuluate the same in the reference file. */
+ position: relative;
+ z-index: 1;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the bottom, and then the word "after".</p>
+before<div></div>after
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-layout-grid-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-layout-grid-001-ref.html
new file mode 100644
index 0000000000..b5ff8e0e0d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-layout-grid-001-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+div {
+ display: inline-grid;
+ border: 5px solid green;
+ /* Layout containment creates a stacking context, the following lines simuluate the same in the reference file. */
+ position: relative;
+ z-index: 1;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the bottom, and then the word "after".</p>
+before<div></div>after
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-layout-ifc-022-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-layout-ifc-022-ref.html
new file mode 100644
index 0000000000..682af7d4f4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-layout-ifc-022-ref.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div
+ {
+ color: transparent;
+ float: left;
+ font-size: 16px;
+ padding: 8px;
+ }
+
+ div#blue-rectangle
+ {
+ background-color: blue;
+ margin: 8px;
+ width: 6em;
+ }
+
+ div#orange-rectangle
+ {
+ background-color: orange;
+ width: 12em;
+ }
+ </style>
+
+ <p>Test passes if the orange rectangle and blue rectangle do not overlap.
+
+ <div id="blue-rectangle">Some text in a blue rectangle.</div>
+
+ <div id="orange-rectangle">Some text in an orange rectangle. Some text in an orange rectangle. Some text in an orange rectangle.</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-013-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-013-ref.html
new file mode 100644
index 0000000000..27041414e4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-013-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div
+ {
+ font-family: monospace;
+ font-size: 100px;
+ height: 3em;
+ overflow: scroll;
+ width: 4ch;
+ }
+ </style>
+
+ <body>
+
+ <p>Test passes if there is no red.
+
+ <div></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-014-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-014-ref.html
new file mode 100644
index 0000000000..a2b75db314
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-014-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div
+ {
+ font-family: monospace;
+ font-size: 100px;
+ height: 2.8ch;
+ overflow: scroll;
+ width: 4ch;
+ }
+ </style>
+
+ <body>
+
+ <p>Test passes if there is no red.
+
+ <div></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-015-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-015-ref.html
new file mode 100644
index 0000000000..8dbbbbd3ec
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-015-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <body>
+
+ <p>Test passes if there is no red.
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-019-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-019-ref.html
new file mode 100644
index 0000000000..7ec1d1bf8e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-019-ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div#parent
+ {
+ height: 100px;
+ width: 100px;
+ overflow: scroll;
+ }
+
+ div#child
+ {
+ background-color: green;
+ height: 100px;
+ width: 100px;
+ }
+ </style>
+
+ <body onload="document.getElementById('parent').scrollLeft = 100; document.getElementById('parent').scrollTop = 125;">
+
+ <p>Test passes if there is a filled green square <strong>with 2 scroll bars</strong> and if there is <strong>no red</strong>.
+
+ <div id="parent">
+ <div id="child"></div>
+ </div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-020-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-020-ref.html
new file mode 100644
index 0000000000..57a4e9c361
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-layout-ink-overflow-020-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div
+ {
+ background-color: green;
+ height: 100px;
+ width: 100px;
+ }
+ </style>
+
+ <p>Test passes if there is a filled green square, <strong>no scrollbar around it</strong> and <strong>no red</strong>.
+
+ <div></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-layout-size-003-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-layout-size-003-ref.html
new file mode 100644
index 0000000000..e3932a9b05
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-layout-size-003-ref.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div
+ {
+ color: transparent;
+ float: left;
+ font-size: 16px;
+ padding: 8px;
+ }
+
+ div#blue-rectangle
+ {
+ background-color: blue;
+ margin: 8px;
+ width: 6em;
+ }
+
+ div#orange-rectangle
+ {
+ background-color: orange;
+ height: 0px;
+ width: 12em;
+ }
+ </style>
+
+ <p>Test passes if the orange rectangle and blue rectangle do not overlap.
+
+ <div id="blue-rectangle">Some text in a blue rectangle.</div>
+
+ <div id="orange-rectangle">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore.</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-paint-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-paint-001-ref.html
new file mode 100644
index 0000000000..639fbb2248
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-paint-001-ref.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment use the padding edge</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: blue;
+ padding: 50px;
+ border-radius: 100px;
+ overflow: hidden
+}
+div::before {
+ content:"";
+ display: block;
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+</style>
+
+<p>Test passes if there is a green square in a rounded blue box, and no red.
+<div></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-paint-007-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-paint-007-ref.html
new file mode 100644
index 0000000000..ae3c424f72
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-paint-007-ref.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test reference</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+
+<style>
+rtc {
+ display: ruby-text-container;
+ font-size: 1rem;
+}
+rtc::after {
+ content: "PASS";
+ position: absolute;
+}
+</style>
+
+<p>This test passes if you can see the word PASS below.
+<div><ruby><rtc></rtc></ruby></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-paint-008-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-paint-008-ref.html
new file mode 100644
index 0000000000..b94055eb1b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-paint-008-ref.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: paint containment on ruby-text</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+
+<style>
+rt {
+ display: ruby-text;
+ font-size: 1rem;
+ font-family: monospace;
+}
+</style>
+
+<p>This test passes if you can see the word PASS below.
+<div><ruby><rt><span style="margin-left: 4ch;"></span>PASS</rt></ruby></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-paint-022-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-paint-022-ref.html
new file mode 100644
index 0000000000..b3bb7576f2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-paint-022-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div
+ {
+ background-color: green;
+ height: 100px;
+ left: 100px;
+ position: relative;
+ top: 100px;
+ width: 100px;
+ }
+
+ </style>
+
+ <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+ <div></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-paint-047-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-paint-047-ref.html
new file mode 100644
index 0000000000..f13649977f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-paint-047-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div
+ {
+ color: green;
+ font-family: monospace;
+ font-size: 100px;
+ }
+ </style>
+
+ <p>Test passes if there is <strong>no red</strong>.
+
+ <div>PASS</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-paint-clip-015-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-paint-clip-015-ref.html
new file mode 100644
index 0000000000..781a6d2f2f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-paint-clip-015-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div
+ {
+ background-color: green;
+ border-radius: 50%;
+ height: 100px;
+ width: 100px;
+ }
+ </style>
+
+ <p>Test passes if there is a filled green circle and <strong>no red</strong>.
+
+ <div></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-paint-clip-019-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-paint-clip-019-ref.html
new file mode 100644
index 0000000000..2a529c12c4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-paint-clip-019-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+
+<meta charset="UTF-8">
+
+<title>CSS Reference Test</title>
+
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+
+<style>
+ #green {
+ background-color: green;
+ width: 100px;
+ height: 100px;
+ }
+</style>
+
+<p>Test passes if there there is a green square. No red and no scrollbars should be visible.</p>
+
+<div id="green"></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-paint-ifc-011-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-paint-ifc-011-ref.html
new file mode 100644
index 0000000000..229c8c2d74
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-paint-ifc-011-ref.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ p
+ {
+ margin-bottom: 30px;
+ }
+
+ div
+ {
+ height: 30px;
+ }
+
+ div.orange
+ {
+ background-color: orange;
+ }
+
+ div.blue
+ {
+ background-color: blue;
+ }
+
+ div#lime
+ {
+ background-color: lime;
+ }
+ </style>
+
+ <p>Test passes if there are 5 horizontal stripes across the page in this order (from top to bottom): an orange stripe, a blue stripe, a bright green stripe, a blue stripe and then an orange stripe.
+
+ <div class="orange"></div>
+
+ <div class="blue"></div>
+
+ <div id="lime"></div>
+
+ <div class="blue"></div>
+
+ <div class="orange"></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-paint-independent-formatting-context-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-paint-independent-formatting-context-001-ref.html
new file mode 100644
index 0000000000..08900b201b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-paint-independent-formatting-context-001-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+.wrapper {
+ border: solid thick;
+ margin: 1em;
+}
+</style>
+<p>Test passes if it has the same output than the reference.</p>
+<div class="wrapper">
+ <div style="margin: 2em 0;">This text should have 2em top and bottom margins (margins do not collapse).</div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-paint-independent-formatting-context-003-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-paint-independent-formatting-context-003-ref.html
new file mode 100644
index 0000000000..0cef592ba5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-paint-independent-formatting-context-003-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+.wrapper {
+ border: solid thick;
+ margin: 1em;
+}
+</style>
+<p>Test passes if it has the same output than the reference.</p>
+<div class="wrapper">
+ <div style="margin: 1em 0;">This text should have 1em top and bottom margins.</div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-paint-size-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-paint-size-001-ref.html
new file mode 100644
index 0000000000..9aad8a490b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-paint-size-001-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div
+ {
+ background-color: green;
+ height: 40px;
+ width: 206px;
+ }
+ </style>
+
+ <p>Test passes if there is a short horizontal green stripe and <strong>no red</strong>.
+
+ <div></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-paint-size-003-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-paint-size-003-ref.html
new file mode 100644
index 0000000000..27820fae76
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-paint-size-003-ref.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div
+ {
+ color: transparent;
+ float: left;
+ font-size: 16px;
+ padding: 8px;
+ }
+
+ div#blue-rectangle
+ {
+ background-color: blue;
+ margin: 8px;
+ width: 6em;
+ }
+
+ div#orange-rectangle
+ {
+ background-color: orange;
+ height: 0px;
+ overflow: hidden;
+ width: 12em;
+ }
+ </style>
+
+ <p>Test passes if the orange rectangle and blue rectangle do not overlap.
+
+ <div id="blue-rectangle">Some text in a blue rectangle.</div>
+
+ <div id="orange-rectangle">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore.</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-004-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-004-ref.html
new file mode 100644
index 0000000000..75ae2bcc2b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-004-ref.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test reference</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+
+<style>
+rtc {
+ display: ruby-text-container;
+ font-size: 1rem;
+}
+div {
+ overflow: hidden;
+}
+</style>
+
+<p>This test passes if you can see the word PASS below.
+<div><ruby><rtc>PASS</rtc></ruby></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-005-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-005-ref.html
new file mode 100644
index 0000000000..001fc90061
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-005-ref.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test reference</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+
+<style>
+div { overflow: hidden; }
+rt {
+ display: ruby-text;
+ font-size: 1rem;
+}
+</style>
+
+<p>This test passes if you can see the word PASS below.
+<div><ruby><rt>PASS</rt></ruby></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-021-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-021-ref.html
new file mode 100644
index 0000000000..639daa8437
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-021-ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+ div.inline-block {
+ display: inline-block;
+ height: 100px;
+ width: 100px;
+ }
+
+ div#blue-test {
+ background-color: blue;
+ padding: 50px;
+ box-sizing: border-box;
+ }
+
+ div#orange-reference {
+ background-color: orange;
+ }
+</style>
+
+<p>This test passes if the painted blue area is <strong>exactly as wide as</strong> the orange square.
+
+<div>
+ <div id="blue-test" class="inline-block"><img src="../support/blue50wBy46h.png" alt="Image download support must be enabled"></div>
+</div>
+
+<div>
+ <div id="orange-reference" class="inline-block"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-022-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-022-ref.html
new file mode 100644
index 0000000000..3ca9ac9ee4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-022-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <p>This test passes if the painted blue area is <strong>exactly as tall as</strong> the orange square.
+
+ <div><img src="../support/swatch-blue.png" width="100" height="100" alt="Image download support must be enabled"> <img src="../support/swatch-orange.png" width="100" height="100" alt="Image download support must be enabled"></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-023-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-023-ref.html
new file mode 100644
index 0000000000..1073100b0c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-023-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+ div.inline-block {
+ display: inline-block;
+ height: 100px;
+ width: 100px;
+ }
+
+ div#blue-test {
+ background-color: blue;
+ color: transparent;
+ font-size: 100px;
+ padding: 50px;
+ box-sizing: border-box;
+ }
+
+ div#orange-reference {
+ background-color: orange;
+ }
+</style>
+
+<p>This test passes if the painted blue area is <strong>exactly as wide as</strong> the orange square.
+
+<div>
+ <div id="blue-test" class="inline-block">B</div>
+</div>
+
+<div>
+ <div id="orange-reference" class="inline-block"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-025-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-025-ref.html
new file mode 100644
index 0000000000..de9cea1050
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-025-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <p>This test passes if the painted blue area is <strong>exactly as wide as</strong> the orange square.
+
+ <div><img src="../support/swatch-blue.png" width="100" height="100" alt="Image download support must be enabled"></div>
+
+ <div><img src="../support/swatch-orange.png" width="100" height="100" alt="Image download support must be enabled"></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-027-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-027-ref.html
new file mode 100644
index 0000000000..ce4c699dc1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-027-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+ div.inline-block {
+ display: inline-block;
+ height: 100px;
+ width: 100px;
+ }
+
+ div#blue-test {
+ background-color: blue;
+ color: transparent;
+ font-size: 50px;
+ line-height: 1;
+ padding: 50px;
+ box-sizing: border-box;
+ }
+
+ div#orange-reference {
+ background-color: orange;
+ }
+
+ span {
+ display: block;
+ }
+</style>
+
+<p>This test passes if the painted blue area is <strong>exactly as wide as</strong> the orange square.
+
+<div>
+ <div id="blue-test" class="inline-block">
+ <span>B</span>
+ <span>L</span>
+ </div>
+</div>
+
+<div>
+ <div id="orange-reference" class="inline-block"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-051-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-051-ref.html
new file mode 100644
index 0000000000..07455aaed2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-051-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ td
+ {
+ font-size: 50px;
+ }
+ </style>
+
+ <p>Test passes if "5678" (without quotes) is readable and if the digits do not overlap each other.
+
+ <table>
+ <tr>
+ <td>5<td>6<td>7<td>8
+ </table>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-056-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-056-ref.html
new file mode 100644
index 0000000000..2e73f0e42b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-056-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ table
+ {
+ width: 400px;
+ }
+
+ caption
+ {
+ border-top: orange solid 6px;
+ color: blue;
+ font-size: 32px;
+ }
+
+ span
+ {
+ bottom: 3px;
+ position: relative;
+ }
+ </style>
+
+ <p>Test passes if the words "Table caption" are below a thick orange line. Test fails if, instead of a thick orange line, there is an orange rectangle with the words "Table caption" in it.
+
+ <table>
+ <caption><span>Table caption</span></caption>
+ </table>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-061-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-061-ref.html
new file mode 100644
index 0000000000..756c20d40e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-061-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <p>Test passes if the word FAIL is absent.
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-062-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-062-ref.html
new file mode 100644
index 0000000000..dbfa77f6ac
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-062-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div
+ {
+ border: orange solid 3px;
+ color: blue;
+ font-size: 32px;
+ height: 0px;
+ width: 400px;
+ }
+ </style>
+
+ <p>Test passes if the words "Text sample" are below a thick orange line. Test fails if, instead of a thick orange line, there is an orange rectangle with the words "Text sample" in it.
+
+ <div>Text sample</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-063-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-063-ref.html
new file mode 100644
index 0000000000..9544ebcac2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-063-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>Test reference</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+
+<p>Test passes if there is no red below.
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-064-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-064-ref.html
new file mode 100644
index 0000000000..6d2876ae9b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-064-ref.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>test reference</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<style>
+div { font-size: 50px; }
+.green { background: green; }
+.grid {
+ display: grid;
+ grid-template-columns: min-content max-content;
+}
+</style>
+
+<p>This test passes if there are two green rectangles and no red.
+
+<div class=grid>
+ <div style="grid-area: 1/1">&nbsp;</div>
+ <div style="grid-area: 2/2"id=test class="grid">
+ <div>&nbsp;</div>
+ <div class=green></div>
+ <div class=green></div>
+ <div>&nbsp;</div>
+ </div>
+</div>
+
+
+
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-breaks-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-breaks-001-ref.html
new file mode 100644
index 0000000000..b807ea5a11
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-breaks-001-ref.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test reference</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+ <meta name=flags content="ahem">
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+article {
+ height: 2.5em;
+ column-gap: 0;
+ columns: 3 1em;
+ width: 3em;
+ column-fill: auto;
+
+ font-size: 40px;
+ font-family: ahem;
+ line-height: 1;
+}
+div {
+ background: orange;
+ padding-top: 5em;
+}
+</style>
+
+<p>This test passes if there is an orange rectangle below. If the shape is not a rectangle, the test fails.
+
+<article>
+<div></div>
+</article>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-button-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-button-001-ref.html
new file mode 100644
index 0000000000..eff64aa8e2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-button-001-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+button {
+ border: 5px solid green;
+ padding: 0;
+ color: transparent;
+ width: 0;
+ height: 0;
+ font-size: 2em;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the top, and then the word "after".</p>
+before<button>b</button>after
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-fieldset-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-fieldset-001-ref.html
new file mode 100644
index 0000000000..85f5c73c2e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-fieldset-001-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+fieldset {
+ display: inline-block;
+ color: transparent;
+ border: none;
+ padding: 0;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a small space, and then the word "after".</p>
+before<fieldset></fieldset>after
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-fieldset-002-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-fieldset-002-ref.html
new file mode 100644
index 0000000000..51ff6998b6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-fieldset-002-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<style>
+#border {
+ border: 1px solid black;
+ width: min-content;
+}
+fieldset {
+ visibility: hidden;
+ height: 1px;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You should see a black border box below.</p>
+<div id="border">
+ <fieldset></fieldset>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-flexbox-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-flexbox-001-ref.html
new file mode 100644
index 0000000000..70f4086430
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-flexbox-001-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+div {
+ display: inline-flex;
+ border: 5px solid green;
+ color: transparent;
+ width: 0;
+ height: 0;
+ font-size: 2em;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the top, and then the word "after".</p>
+before<div>f</div>after
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-flexbox-002-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-flexbox-002-ref.html
new file mode 100644
index 0000000000..a75fa26c9f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-flexbox-002-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>Tests that scrollbars are handled correctly in a flex item with contains:size</title>
+<link rel="author" title="Google LLC" href="https://www.google.com">
+
+<style>
+div > div {
+ vertical-align: top;
+ display: inline-block;
+ contain: size;
+ overflow: scroll;
+ border: 1px solid;
+}
+</style>
+
+<p>Test passes if the two lines below look the same.</p>
+
+<div style="line-height: 1.0;">
+ <div></div>
+</div>
+
+<div style="line-height: 1.0;">
+ <div></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-grid-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-grid-001-ref.html
new file mode 100644
index 0000000000..cf4f807665
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-grid-001-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+div {
+ display: inline-grid;
+ border: 5px solid green;
+ color: transparent;
+ width: 0;
+ height: 0;
+ font-size: 2em;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a 10px green square at the top, and then the word "after".</p>
+before<div>g</div>after
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-grid-005-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-grid-005-ref.html
new file mode 100644
index 0000000000..b2fdf4b887
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-grid-005-ref.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Gerald Squelart" href="mailto:gsquelart@mozilla.com">
+ <style>
+ .basic {
+ display: grid;
+ border: 1em solid green;
+ }
+ .height-ref {
+ height: 40px;
+ background: lightblue;
+ }
+ .width-ref {
+ width: 40px;
+ }
+ .floatLBasic-ref {
+ float: left;
+ }
+ .floatLWidth-ref {
+ float: left;
+ width: 40px;
+ }
+ </style>
+</head>
+<body>
+ <div class="basic"></div>
+ <br>
+
+ <div class="basic height-ref"></div>
+ <br>
+
+ <div class="basic height-ref"></div>
+ <br>
+
+ <div class="basic width-ref"></div>
+ <br>
+
+ <div class="basic width-ref"></div>
+ <br>
+
+ <div class="basic floatLBasic-ref"></div>
+ <br>
+
+ <div class="basic floatLWidth-ref"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-monolithic-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-monolithic-001-ref.html
new file mode 100644
index 0000000000..2e8f1ba70a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-monolithic-001-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div
+ {
+ font-family: monospace;
+ font-size: 20px;
+ width: 8ch;
+ }
+ </style>
+
+ <p>Test passes if "AB", "CD", "EF" and "GH" are vertically aligned into 1 single column and if there is <strong>no red</strong>.
+
+
+ <div>AB<br>CD<br>EF<br>GH</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-scrollbars-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-scrollbars-001-ref.html
new file mode 100644
index 0000000000..402ff6c95e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-scrollbars-001-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+div {
+ display: inline-block;
+ border: solid thick;
+ overflow: scroll;
+}
+</style>
+<p>This test passes if it has the same output as the reference.</p>
+<div></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-scrollbars-004-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-scrollbars-004-ref.html
new file mode 100644
index 0000000000..91d9e51709
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-scrollbars-004-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<style>
+#scroller {
+ background: lightgreen;
+ overflow: scroll;
+ padding-bottom: 50px;
+ width: 100px;
+ height: 100px;
+}
+#content {
+ background: lightblue;
+ width: 50px;
+ height: 130px;
+}
+</style>
+
+<div id=scroller>
+ <div id=content>
+ </div>
+</div>
+
+<p>This test passes if it has the same output as the reference.</p>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-size-select-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-size-select-001-ref.html
new file mode 100644
index 0000000000..1944e49375
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-size-select-001-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+select {
+ color: transparent;
+ background: white;
+}
+</style>
+<p>Test passes if it has the same output than the reference.</p>
+<select></select>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-strict-011-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-strict-011-ref.html
new file mode 100644
index 0000000000..401275b552
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-strict-011-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ p
+ {
+ margin-top: 1.5em;
+ }
+
+ div
+ {
+ font-size: 3em;
+ }
+ </style>
+
+ <p>Test passes if there is the number 17.
+
+ <div>17</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-style-breaks-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-style-breaks-001-ref.html
new file mode 100644
index 0000000000..2c0b758e6b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-style-breaks-001-ref.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test reference</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<style>
+article {
+ columns: 2 1ch;
+ column-gap: 0;
+ float: left;
+ font-family: monospace;
+ margin-right: 3em;
+}
+div {
+ page-break-inside: avoid;
+ break-inside: avoid;
+}
+</style>
+
+<p>Test passes if there are two identical blocks “A” letters below.
+<article>
+ <div>
+ A<br>
+ A<br>
+ A<br>
+ A
+ <div>
+</article>
+<article>
+ <div>
+ A<br>
+ A<br>
+ A<br>
+ A
+ <div>
+</article>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-style-breaks-004-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-style-breaks-004-ref.html
new file mode 100644
index 0000000000..eaf4d566a2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-style-breaks-004-ref.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test reference</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<style>
+article {
+ columns: 2 1ch;
+ column-gap: 0;
+ float: left;
+ font-family: monospace;
+ margin-right: 3em;
+ line-height: 1;
+ height: 4em;
+ column-fill: auto;
+}
+div:last-of-type {
+ break-before: column;
+}
+</style>
+
+<p>Test passes if there are two identical blocks “A” letters below.
+<article>
+ <div>A<br>A</div>
+ <div>A<br>A</div>
+</article>
+<article>
+ <div>A<br>A</div>
+ <div>A<br>A</div>
+</article>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-style-counters-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-style-counters-001-ref.html
new file mode 100644
index 0000000000..c0c652b335
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-style-counters-001-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div
+ {
+ font-size: 3em;
+ }
+ </style>
+
+ <p>Test passes if there is the digit 5.
+
+ <div>5</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-style-counters-003-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-style-counters-003-ref.html
new file mode 100644
index 0000000000..12f9b989fd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-style-counters-003-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div
+ {
+ font-size: 3em;
+ }
+ </style>
+
+ <p>Test passes if there is the number 20.
+
+ <div>20</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-style-counters-004-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-style-counters-004-ref.html
new file mode 100644
index 0000000000..c362dbbf53
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-style-counters-004-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference Test</title>
+
+ <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+
+ <style>
+ div
+ {
+ font-size: 3em;
+ }
+ </style>
+
+ <p>Test passes if there is the number 13.
+
+ <div>13</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-style-counters-005-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-style-counters-005-ref.html
new file mode 100644
index 0000000000..9b2868b62d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-style-counters-005-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<style>
+.contain {
+ float: right;
+ clear: both;
+}
+.reset { counter-reset: c;}
+.increment:before { content: counters(c, ""); }
+.increment { counter-increment: c; }
+</style>
+<body>
+<div>1</div>
+<div class="contain">
+ <div>11</div>
+ <div>11</div>
+</div>
+<div>2</div>
+<div class="contain">
+ <div>21</div>
+ <div>22</div>
+</div>
+<div>3</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-li-container-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-li-container-ref.html
new file mode 100644
index 0000000000..e6c721ac2d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-li-container-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<title>CSS Containment: contain:style and &lt;ol&gt; ordinals (li container, ref)</title>
+<ol>
+ <li value="1">A</li>
+ <li value="2">B</li>
+ <li value="3">X</li>
+ <li value="4">Y</li>
+ <li value="5">C</li>
+ <li value="6">D</li>
+</ol>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-pseudo-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-pseudo-ref.html
new file mode 100644
index 0000000000..5b8e4d338c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-pseudo-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<title>CSS Containment: contain:style and &lt;ol&gt; ordinals (pseudo, ref)</title>
+<ol>
+ <li value="10">10A10</li>
+ <li value="11">11B11</li>
+ <div>
+ <li value="1">1X1</li>
+ <li value="2">2Y2</li>
+ </div>
+ <li value="12">12C12</li>
+ <li value="13">13D13</li>
+</ol>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-pseudo-reversed-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-pseudo-reversed-ref.html
new file mode 100644
index 0000000000..04cc67139a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-pseudo-reversed-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<title>CSS Containment: contain:style and &lt;ol&gt; ordinals (pseudo, reversed, ref)</title>
+<ol>
+ <li value="10">10A10</li>
+ <li value="9">9B9</li>
+ <div>
+ <li value="1">1X1</li>
+ <li value="2">2Y2</li>
+ </div>
+ <li value="8">8C8</li>
+ <li value="7">7D7</li>
+</ol>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-ref.html
new file mode 100644
index 0000000000..bee7deda2f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<title>CSS Containment: contain:style and &lt;ol&gt; ordinals (ref)</title>
+<ol>
+ <li value="1">A</li>
+ <li value="2">B</li>
+ <div>
+ <li value="1">X</li>
+ <li value="2">Y</li>
+ </div>
+ <li value="3">C</li>
+ <li value="4">D</li>
+</ol>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-reversed-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-reversed-ref.html
new file mode 100644
index 0000000000..bb7531790e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-reversed-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<title>CSS Containment: contain:style and &lt;ol&gt; ordinals (reversed, ref)</title>
+<ol>
+ <li value="4">A</li>
+ <li value="3">B</li>
+ <div>
+ <li value="1">X</li>
+ <li value="2">Y</li>
+ </div>
+ <li value="2">C</li>
+ <li value="1">D</li>
+</ol>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-start-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-start-ref.html
new file mode 100644
index 0000000000..93411804b1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-start-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<title>CSS Containment: contain:style and &lt;ol&gt; ordinals (start attribute, ref)</title>
+<ol>
+ <li value="10">A</li>
+ <li value="11">B</li>
+ <div>
+ <li value="1">X</li>
+ <li value="2">Y</li>
+ </div>
+ <li value="12">C</li>
+ <li value="13">D</li>
+</ol>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-start-reversed-ref.html b/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-start-reversed-ref.html
new file mode 100644
index 0000000000..60aefdf563
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-style-ol-ordinal-start-reversed-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<title>CSS Containment: contain:style and &lt;ol&gt; ordinals (start attribute, reversed, ref)</title>
+<ol>
+ <li value="10">A</li>
+ <li value="9">B</li>
+ <div>
+ <li value="1">X</li>
+ <li value="2">Y</li>
+ </div>
+ <li value="8">C</li>
+ <li value="7">D</li>
+</ol>
diff --git a/testing/web-platform/tests/css/css-contain/reference/contain-subgrid-001.html b/testing/web-platform/tests/css/css-contain/reference/contain-subgrid-001.html
new file mode 100644
index 0000000000..ab0d1fede5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/contain-subgrid-001.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain reference: layout/paint containment on subgrid</title>
+ <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+
+<style>
+.grid {
+ display: grid;
+ width: 40px;
+ height: 40px;
+ grid: [a] repeat(2,15px) [b] / [a] repeat(2,15px) [b];
+ gap: 10px;
+}
+
+.subgrid {
+ display: grid;
+ grid: none;
+ background: lightgrey;
+ grid-area:1/1/3/3;
+}
+
+.layout { contain: layout; }
+.paint { contain: paint; }
+
+.inner {
+ background: blue;
+ grid-area:a/a/b/b;
+}
+</style>
+
+<div class="grid"><div class="subgrid layout"><div class="inner"></div></div></div>
+<div class="grid"><div class="subgrid paint"><div class="inner"></div></div></div>
+<div class="grid"><div class="subgrid layout"><div class="inner"></div></div></div>
+<div class="grid"><div class="subgrid paint"><div class="inner"></div></div></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/counter-scoping-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/counter-scoping-001-ref.html
new file mode 100644
index 0000000000..2ebbb9a93c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/counter-scoping-001-ref.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test reference</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+
+<p>Test passes if the text below is "1 1.2" (not including the quotation marks).<p>
+<div>1 1.2</div>
+
diff --git a/testing/web-platform/tests/css/css-contain/reference/counter-scoping-003-ref.html b/testing/web-platform/tests/css/css-contain/reference/counter-scoping-003-ref.html
new file mode 100644
index 0000000000..49e7b85e87
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/counter-scoping-003-ref.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test reference</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+
+<p>Test passes if the text below is "1 2" (not including the quotation marks).<p>
+<div>1 2</div>
+
diff --git a/testing/web-platform/tests/css/css-contain/reference/counter-scoping-004-ref.html b/testing/web-platform/tests/css/css-contain/reference/counter-scoping-004-ref.html
new file mode 100644
index 0000000000..f6d8e38fd5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/counter-scoping-004-ref.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<meta charset="UTF-8">
+<title>CSS Test Reference</title>
+<style>
+ .list-item {
+ margin-left: 40px;
+ }
+</style>
+<div class="list-item">
+ [1] A1
+ <div class="list-item">[1] B1</div>
+ <div class="list-item">[2] B2</div>
+</div>
+<div class="list-item">[2] A2</div>
+<div class="list-item">[3] A3</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/pass_if_pass_below_clipped.html b/testing/web-platform/tests/css/css-contain/reference/pass_if_pass_below_clipped.html
new file mode 100644
index 0000000000..044783d1e5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/pass_if_pass_below_clipped.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<html>
+<head>
+ <title>Reference rendering - passes if there is the word "PASS" below</title>
+<style>
+div { overflow: hidden; }
+</style>
+</head>
+<body>
+ <p>Test passes if there is the word "PASS" below.</p>
+ <div>PASS</div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-contain/reference/quote-scoping-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/quote-scoping-001-ref.html
new file mode 100644
index 0000000000..0b0e9c467a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/quote-scoping-001-ref.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test reference</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<p>Test passes if the text below is "A1Z" (not including the quotation marks).<p>
+<div>A1Z</div>
+
diff --git a/testing/web-platform/tests/css/css-contain/reference/quote-scoping-002-ref.html b/testing/web-platform/tests/css/css-contain/reference/quote-scoping-002-ref.html
new file mode 100644
index 0000000000..c7239e3f48
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/quote-scoping-002-ref.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test reference</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+
+<p>Test passes if the text below is "AZZ" (not including the quotation marks).<p>
+<div>AZZ</span></div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/quote-scoping-003-ref.html b/testing/web-platform/tests/css/css-contain/reference/quote-scoping-003-ref.html
new file mode 100644
index 0000000000..2bc8d6730e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/quote-scoping-003-ref.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test reference</title>
+ <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+
+<p>Test passes if the text below is "AZ" (not including the quotation marks).<p>
+<div>AZ</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/quote-scoping-empty-style-boundaries-ref.html b/testing/web-platform/tests/css/css-contain/reference/quote-scoping-empty-style-boundaries-ref.html
new file mode 100644
index 0000000000..6437e08eb1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/quote-scoping-empty-style-boundaries-ref.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<html lang=en>
+ <meta charset=utf-8>
+ <title>CSS-contain test: nested style containment and the quote element following a style boundary without any quotes</title>
+ <link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+ <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
+
+<div>
+ <div>
+ <q></q>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/quote-scoping-invalidation-001-ref.html b/testing/web-platform/tests/css/css-contain/reference/quote-scoping-invalidation-001-ref.html
new file mode 100644
index 0000000000..5c1a6203e6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/quote-scoping-invalidation-001-ref.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSS-contain test reference: style containment dynamic containment set invalidation</title>
+<link rel="author" title="Daniil Sakhapov" href="sakhapov@google.com">
+
+<p>Test passes if the text below is "A1(19" (not including the quotation marks).<p>
+<div>A<div>1 (</div>1 9</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/quote-scoping-invalidation-002-ref.html b/testing/web-platform/tests/css/css-contain/reference/quote-scoping-invalidation-002-ref.html
new file mode 100644
index 0000000000..e48a080e92
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/quote-scoping-invalidation-002-ref.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSS-contain test reference: style containment dynamic containment set unset invalidation</title>
+<link rel="author" title="Daniil Sakhapov" href="sakhapov@google.com">
+
+<p>Test passes if the text below is "A1(+-" (not including the quotation marks).<p>
+<div>A<div>1 (</div>+ -</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/quote-scoping-invalidation-003-ref.html b/testing/web-platform/tests/css/css-contain/reference/quote-scoping-invalidation-003-ref.html
new file mode 100644
index 0000000000..766ad6cbe9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/quote-scoping-invalidation-003-ref.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSS-contain test reference: style containment dynamic containment set unset set invalidation</title>
+<link rel="author" title="Daniil Sakhapov" href="sakhapov@google.com">
+
+<p>Test passes if the text below is "A119" (not including the quotation marks).<p>
+<div>A<div>1</div>1 9</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/quote-scoping-invalidation-004-ref.html b/testing/web-platform/tests/css/css-contain/reference/quote-scoping-invalidation-004-ref.html
new file mode 100644
index 0000000000..8280075f00
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/quote-scoping-invalidation-004-ref.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSS-contain test reference: style containment invalidation with elements in different subtrees</title>
+<link rel="author" title="Daniil Sakhapov" href="sakhapov@google.com">
+
+<p>Test passes if the text below is "A111119" (not including the quotation marks).<p>
+<div>A<div>1 1</div><div>1 1</div>1 9</div>
diff --git a/testing/web-platform/tests/css/css-contain/reference/ref-if-there-is-no-red.xht b/testing/web-platform/tests/css/css-contain/reference/ref-if-there-is-no-red.xht
new file mode 100644
index 0000000000..a5b4e9f47a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/reference/ref-if-there-is-no-red.xht
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+ <head>
+
+ <title>CSS Reftest Reference</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+
+ </head>
+
+ <body>
+
+ <p>Test passes if there is <strong>no red</strong>.</p>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-contain/support/60x60-green.png b/testing/web-platform/tests/css/css-contain/support/60x60-green.png
new file mode 100644
index 0000000000..b3c8cf3eb4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/support/60x60-green.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-contain/support/blue-100x100.png b/testing/web-platform/tests/css/css-contain/support/blue-100x100.png
new file mode 100644
index 0000000000..3b72d5ce53
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/support/blue-100x100.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-contain/support/blue50wBy25h.png b/testing/web-platform/tests/css/css-contain/support/blue50wBy25h.png
new file mode 100644
index 0000000000..35d23ec234
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/support/blue50wBy25h.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-contain/support/blue50wBy46h.png b/testing/web-platform/tests/css/css-contain/support/blue50wBy46h.png
new file mode 100644
index 0000000000..303d040454
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/support/blue50wBy46h.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-contain/support/pattern-gg-gr-100x100.png b/testing/web-platform/tests/css/css-contain/support/pattern-gg-gr-100x100.png
new file mode 100644
index 0000000000..fd9b7e1ef2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/support/pattern-gg-gr-100x100.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-contain/support/swatch-blue.png b/testing/web-platform/tests/css/css-contain/support/swatch-blue.png
new file mode 100644
index 0000000000..bf2759634d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/support/swatch-blue.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-contain/support/swatch-orange.png b/testing/web-platform/tests/css/css-contain/support/swatch-orange.png
new file mode 100644
index 0000000000..d3cd498b52
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/support/swatch-orange.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-contain/support/swatch-red.png b/testing/web-platform/tests/css/css-contain/support/swatch-red.png
new file mode 100644
index 0000000000..1caf25c992
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/support/swatch-red.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-contain/support/swatch-yellow.png b/testing/web-platform/tests/css/css-contain/support/swatch-yellow.png
new file mode 100644
index 0000000000..1591aa0e2e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/support/swatch-yellow.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-contain/support/white.webm b/testing/web-platform/tests/css/css-contain/support/white.webm
new file mode 100644
index 0000000000..bbacad7ffd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-contain/support/white.webm
Binary files differ