summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-highlight-api
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /testing/web-platform/tests/css/css-highlight-api
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/css/css-highlight-api')
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/Highlight-iteration-with-modifications.html91
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/Highlight-iteration.html201
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/Highlight-setlike-tampered-Set-prototype.html55
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/Highlight-setlike.html106
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/Highlight-type-attribute.tentative.html20
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/HighlightRegistry-iteration-with-modifications.html109
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/HighlightRegistry-iteration.html186
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/HighlightRegistry-maplike-tampered-Map-prototype.html61
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/HighlightRegistry-maplike.html75
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/highlight-pseudo-computed.html41
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/highlight-pseudo-parsing.html21
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/idlharness.window.js17
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/css-highlight-painting-underline-offset-001-ref.html12
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/css-highlight-painting-underline-offset-001.html21
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-001-ref.html9
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-001.html20
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-002-ref.html8
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-002.html24
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-003-ref.html6
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-003.html23
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-004-2-ref.html16
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-004-2.html34
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-004-ref.html16
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-004.html34
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-005.html20
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-006.html20
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-007.html24
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-008.html24
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-009.html30
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-010.html22
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-011.html20
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-012.html20
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-013.html20
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-014.html26
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-015.html27
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-016.html21
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-017.html27
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-018.html22
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-grammar-ref.html9
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-grammar.html31
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-selection-ref.html16
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-selection.html24
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-target-text-ref.html16
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-target-text.html23
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-001-ref.html16
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-001.html12
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-002.html33
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-003-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-003.html46
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-004-ref.html16
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-004.html45
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-005-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-005.html45
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-006-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-006.html50
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-001-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-001.html27
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-002.html21
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-003-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-003.html23
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-001.html27
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-002.html28
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-003.html27
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-004.html29
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-005.html37
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-006.html30
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-007-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-007.html34
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-overlapping-highlights-001-ref.html16
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-overlapping-highlights-001.html43
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-overlapping-highlights-002-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-overlapping-highlights-002.html53
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-prioritization-001.html28
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-prioritization-002.html27
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-001-ref.html3
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-001.html22
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-002.html21
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-003.html18
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-001-ref.html29
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-001.html36
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-dynamic-001-ref.html16
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-dynamic-001.html27
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-shadow.tentative.html21
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/resources/iframe-code.html13
-rw-r--r--testing/web-platform/tests/css/css-highlight-api/painting/resources/run-after-layout-and-paint.js11
85 files changed, 2677 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-highlight-api/Highlight-iteration-with-modifications.html b/testing/web-platform/tests/css/css-highlight-api/Highlight-iteration-with-modifications.html
new file mode 100644
index 0000000000..b1f0fb10ee
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/Highlight-iteration-with-modifications.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<title>Highlight iteration with insertions and deletions inbetween</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id='testDiv'>abc</div>
+<script>
+ 'use strict';
+ let container = document.getElementById('testDiv');
+ let range1 = new StaticRange({startContainer: container, startOffset: 0, endContainer: container, endOffset: 1});
+ let range2 = new Range();
+
+ // Test insertions using .add
+ test(() => {
+ let customHighlight = new Highlight();
+ let iterator = customHighlight[Symbol.iterator]();
+ customHighlight.add(range1);
+ let element = iterator.next();
+ assert_true(element.done, 'The iteration ends although we added a new range after starting the iteration');
+ assert_equals(element.value, undefined, 'A range added after starting the iteration is not found during the current iteration');
+ }, 'Highlight iteration is not modified when a new range is added after starting the iteration');
+
+ test(() => {
+ let customHighlight = new Highlight(range1);
+ let iterator = customHighlight[Symbol.iterator]();
+ customHighlight.add(range2);
+ let element = iterator.next();
+ assert_false(element.done, 'The iteration doesn\'t end although there was a second range added to the Highlight after starting the iteration');
+ assert_equals(element.value, range1, 'The range that was pointed to by the iterator is returned although a second range was added after starting the iteration');
+ element = iterator.next();
+ assert_true(element.done, 'The iteration ends after going through all the ranges that were in the Highlight when the iteration started although there was a range addition after starting the iteration');
+ assert_equals(element.value, undefined, '.next() returns undefined when the iteration ends');
+ }, 'Highlight iteration is not modified when a new range is added after starting the iteration with one range in the Highlight');
+
+ // Test deletions using .delete
+ test(() => {
+ let customHighlight = new Highlight(range1);
+ let iterator = customHighlight[Symbol.iterator]();
+ customHighlight.delete(range1);
+ let element = iterator.next();
+ assert_false(element.done, 'The iteration doesn\'t end although the range that was pointed to by the iterator was deleted');
+ assert_equals(element.value, range1, 'The range that was pointed to by the iterator is returned although it was deleted after starting the iteration');
+ element = iterator.next();
+ assert_true(element.done, 'The iteration ends after going through all the ranges although the range that was pointed to by the iterator was deleted after starting the iteration');
+ assert_equals(element.value, undefined, '.next() returns undefined when the iteration ends');
+ }, 'Highlight iteration is not modified when the range that was pointed to by the iterator was deleted after starting the iteration');
+
+ test(() => {
+ let customHighlight = new Highlight(range1, range2);
+ let iterator = customHighlight[Symbol.iterator]();
+ customHighlight.delete(range2);
+ let element = iterator.next();
+ assert_false(element.done, 'The iteration doesn\'t end when the range following to the one that was pointed to by the iterator was deleted');
+ assert_equals(element.value, range1, 'The range that was pointed to by the iterator is returned as it should although the next range was deleted immediately after starting the iteration');
+ element = iterator.next();
+ assert_false(element.done, 'The iteration doesn\'t end when you call .next twice since the beginning of the iteration although the second range was deleted');
+ assert_equals(element.value, range2, 'The range that was pointed to by the iterator is returned as it should although the next range was deleted immediately after starting the iteration');
+ element = iterator.next();
+ assert_true(element.done, 'The iteration ends after going through all the ranges although the second range was deleted immediately after starting the iteration');
+ assert_equals(element.value, undefined, '.next() returns undefined when the iteration ends');
+ }, 'Highlight iteration is not modified when the range that was immediately after the one pointed to by the iterator was deleted after starting the iteration');
+
+ test(() => {
+ let customHighlight = new Highlight(range1, range2);
+ let iterator = customHighlight[Symbol.iterator]();
+ let element = iterator.next();
+ assert_false(element.done, 'The iteration doesn\'t end when there are still two ranges to visit');
+ assert_equals(element.value, range1, 'The range that was pointed to by the iterator is returned as it should');
+ customHighlight.delete(range1);
+ element = iterator.next();
+ assert_false(element.done, 'The iteration doesn\'t end when the range previously visited is deleted and there is still a range to visit');
+ assert_equals(element.value, range2, 'The range that was pointed to by the iterator is returned as it should although the previous range was deleted after calling .next');
+ element = iterator.next();
+ assert_true(element.done, 'The iteration ends after going through all the ranges although the first range was deleted after the first call to .next');
+ assert_equals(element.value, undefined, '.next() returns undefined when the iteration ends');
+ }, 'Highlight iteration is not modified when a range that was already visited is deleted and there are still ranges to visit');
+
+ // Test deletions using .clear
+ test(() => {
+ let customHighlight = new Highlight(range1);
+ let iterator = customHighlight[Symbol.iterator]();
+ customHighlight.clear();
+ let element = iterator.next();
+ assert_false(element.done, 'The iteration doesn\'t end although the range that was pointed to by the iterator was deleted using .clear()');
+ assert_equals(element.value, range1, 'The range that was pointed to by the iterator is returned although it was deleted using .clear() after starting the iteration');
+ element = iterator.next();
+ assert_true(element.done, 'The iteration ends after going through all the ranges although the range that was pointed to by the iterator was deleted using .clear() after starting the iteration');
+ assert_equals(element.value, undefined, '.next() returns undefined when the iteration ends');
+ }, 'Highlight iteration is not modified when the range that was pointed to by the iterator was deleted using .clear() after starting the iteration');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-highlight-api/Highlight-iteration.html b/testing/web-platform/tests/css/css-highlight-api/Highlight-iteration.html
new file mode 100644
index 0000000000..f3268b49cd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/Highlight-iteration.html
@@ -0,0 +1,201 @@
+<!doctype html>
+<title>Highlight iteration</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id='testDiv'>abc</div>
+<script>
+ 'use strict';
+ let range1 = new Range();
+ let container = document.getElementById('testDiv');
+ let range2 = new StaticRange({startContainer: container, startOffset: 0, endContainer: container, endOffset: 0});
+
+ let rangeAdditionModeCollection = ["constructor", "add function"];
+ let iterationInitializationCollection = ["customHighlight[Symbol.iterator]()", "customHighlight.values()", "customHighlight.keys()"];
+
+ function getIterator(customHighlight, iterationInitialization){
+ var iterator;
+ if(iterationInitialization === "customHighlight[Symbol.iterator]()"){
+ iterator = customHighlight[Symbol.iterator]();
+ }
+ else if(iterationInitialization === "customHighlight.values()"){
+ iterator = customHighlight.values();
+ }
+ else if(iterationInitialization === "customHighlight.keys()"){
+ iterator = customHighlight.keys();
+ }
+ return iterator;
+ }
+
+ // Test .keys, .values, [Symbol.iterator]
+
+ for(let iterationInitialization of iterationInitializationCollection){
+ test(() => {
+ let customHighlight = new Highlight();
+ let iterator = getIterator(customHighlight, iterationInitialization);
+ let element = iterator.next();
+ assert_true(element.done, 'Highlight is iterable and .next() returns an element with .done===true when there are no more ranges to iterate');
+ assert_equals(element.value, undefined, 'Highlight is iterable and .next() returns an element with .value undefined when there are no more ranges to iterate.');
+ }, 'Highlight can be iterated when it\'s empty initializing the iterator with ' + iterationInitialization);
+ }
+
+ for(let rangeAdditionMode of rangeAdditionModeCollection){
+ for(let iterationInitialization of iterationInitializationCollection){
+ test(() => {
+ var customHighlight;
+ if(rangeAdditionMode === "constructor"){
+ customHighlight = new Highlight(range1);
+ }
+ else if(rangeAdditionMode === "add function"){
+ customHighlight = new Highlight();
+ customHighlight.add(range1);
+ }
+
+ let iterator = getIterator(customHighlight, iterationInitialization);
+ let element = iterator.next();
+ assert_false(element.done, 'Highlight is iterable and .next() returns an element with .done===false when the iteration didn\'t go past the last range');
+ assert_equals(element.value, range1, '.next() returns an element with .value corresponding to the first range added to the Highlight');
+ element = iterator.next();
+ assert_true(element.done, 'Highlight is iterable and .next() returns an element with .done===true when there are no more ranges to iterate');
+ assert_equals(element.value, undefined, 'Highlight is iterable and .next() returns an element with .value undefined when there are no more ranges to iterate.');
+ }, 'Highlight can be iterated over all of its ranges initializing the iterator with ' + iterationInitialization + ' and adding a range by passing it to the ' + rangeAdditionMode);
+
+ test(() => {
+ var customHighlight;
+ if(rangeAdditionMode === "constructor"){
+ customHighlight = new Highlight(range1, range2);
+ }
+ else if(rangeAdditionMode === "add function"){
+ customHighlight = new Highlight();
+ customHighlight.add(range1);
+ customHighlight.add(range2);
+ }
+
+ let iterator = getIterator(customHighlight, iterationInitialization);
+ let element = iterator.next();
+ assert_false(element.done, 'Highlight is iterable and .next() returns an element with .done===false when the iteration didn\'t go past the last range');
+ assert_equals(element.value, range1, '.next() returns an element with .value corresponding to the first range added to the Highlight');
+ element = iterator.next();
+ assert_false(element.done, 'Highlight is iterable and .next() returns an element with .done===false when the iteration didn\'t go past the last range');
+ assert_equals(element.value, range2, '.next() returns an element with .value corresponding to the second range added to the Highlight');
+ element = iterator.next();
+ assert_true(element.done, 'Highlight is iterable and .next() returns an element with .done===true when there are no more ranges to iterate');
+ assert_equals(element.value, undefined, 'Highlight is iterable and .next() returns an element with .value undefined when there are no more ranges to iterate.');
+ }, 'Highlight can be iterated over all of its ranges initializing the iterator with ' + iterationInitialization + ' and adding two ranges by passing them to the ' + rangeAdditionMode);
+ }
+ }
+
+ // Test .entries()
+
+ test(() => {
+ let customHighlight = new Highlight();
+ let iterator = customHighlight.entries();
+ let element = iterator.next();
+ assert_true(element.done, 'Highlight is iterable and .next() returns an element with .done===true when there are no more ranges to iterate');
+ assert_equals(element.value, undefined, 'Highlight is iterable and .next() returns an element with .value undefined when there are no more ranges to iterate.');
+ }, 'Highlight can be iterated when it\'s empty initializing the iterator with .entries()');
+
+ for(let rangeAdditionMode of rangeAdditionModeCollection){
+ test(() => {
+ var customHighlight;
+ if(rangeAdditionMode === "constructor"){
+ customHighlight = new Highlight(range1);
+ }
+ else if(rangeAdditionMode === "add function"){
+ customHighlight = new Highlight();
+ customHighlight.add(range1);
+ }
+
+ let iterator = customHighlight.entries();
+ let element = iterator.next();
+ assert_false(element.done, 'Highlight is iterable and .next() returns an element with .done===false when the iteration didn\'t go past the last range');
+ assert_equals(element.value[0], range1, '.next() returns an element with .value[0] corresponding to the first range added to the Highlight');
+ assert_equals(element.value[1], range1, '.next() returns an element with .value[1] corresponding to the first range added to the Highlight');
+ element = iterator.next();
+ assert_true(element.done, 'Highlight is iterable and .next() returns an element with .done===true when there are no more ranges to iterate');
+ assert_equals(element.value, undefined, 'Highlight is iterable and .next() returns an element with .value undefined when there are no more ranges to iterate.');
+ }, 'Highlight can be iterated over all of its ranges initializing the iterator with .entries() and adding a range by passing it to the ' + rangeAdditionMode);
+
+ test(() => {
+ var customHighlight;
+ if(rangeAdditionMode === "constructor"){
+ customHighlight = new Highlight(range1, range2);
+ }
+ else if(rangeAdditionMode === "add function"){
+ customHighlight = new Highlight();
+ customHighlight.add(range1);
+ customHighlight.add(range2);
+ }
+
+ let iterator = customHighlight.entries();
+ let element = iterator.next();
+ assert_false(element.done, 'Highlight is iterable and .next() returns an element with .done===false when the iteration didn\'t go past the last highlight');
+ assert_equals(element.value[0], range1, '.next() returns an element with .value[0] corresponding to the first range added to the Highlight');
+ assert_equals(element.value[1], range1, '.next() returns an element with .value[1] corresponding to the first range added to the Highlight');
+ element = iterator.next();
+ assert_false(element.done, 'Highlight is iterable and .next() returns an element with .done===false when the iteration didn\'t go past the last highlight');
+ assert_equals(element.value[0], range2, '.next() returns an element with .value[0] corresponding to the second range added to the Highlight');
+ assert_equals(element.value[1], range2, '.next() returns an element with .value[1] corresponding to the second range added to the Highlight');
+ element = iterator.next();
+ assert_true(element.done, 'Highlight is iterable and .next() returns an element with .done===true when there are no more ranges to iterate');
+ assert_equals(element.value, undefined, 'Highlight is iterable and .next() returns an element with .value undefined when there are no more ranges to iterate.');
+ }, 'Highlight can be iterated over all of its ranges initializing the iterator with .entries() and adding two ranges by passing them to the ' + rangeAdditionMode);
+ }
+
+ // Test .forEach
+
+ function compareArrays(array1, array2){
+ if(array1.length != array2.length){
+ return false;
+ }
+ for(let index=0; index<array1.length; ++index){
+ if(array1[index] != array2[index])
+ return false;
+ }
+ return true;
+ }
+
+ test(() => {
+ let customHighlight = new Highlight();
+ let expectedResult = [];
+ let actualResult = [];
+ customHighlight.forEach((range) => {actualResult.push(range);});
+ assert_true(compareArrays(actualResult, expectedResult), 'The ranges seen match the ranges added');
+ }, 'Highlight can be iterated through when it\'s empty using forEach.');
+
+ for(let rangeAdditionMode of rangeAdditionModeCollection){
+ test(() => {
+ var customHighlight;
+ if(rangeAdditionMode === "constructor"){
+ customHighlight = new Highlight(range1);
+ }
+ else if(rangeAdditionMode === "add function"){
+ customHighlight = new Highlight();
+ customHighlight.add(range1);
+ }
+
+ let expectedResult = [range1];
+ let actualResult = [];
+ customHighlight.forEach((range) => {actualResult.push(range);});
+ assert_true(compareArrays(actualResult, expectedResult), 'The ranges seen match the ranges added');
+ }, 'Highlight can be iterated through using forEach when it has one range that was added by passing it to the ' + rangeAdditionMode);
+
+ test(() => {
+ var customHighlight;
+ if(rangeAdditionMode === "constructor"){
+ customHighlight = new Highlight(range1, range2);
+ }
+ else if(rangeAdditionMode === "add function"){
+ customHighlight = new Highlight();
+ customHighlight.add(range1);
+ customHighlight.add(range2);
+ }
+
+ let expectedResult = [range1, range2];
+ let actualResult = [];
+ customHighlight.forEach((range) => {actualResult.push(range);});
+ assert_true(compareArrays(actualResult, expectedResult), 'The ranges seen match the ranges added');
+ }, 'Highlight can be iterated through using forEach when it has two ranges that were added by passing them to the ' + rangeAdditionMode);
+ }
+
+</script>
diff --git a/testing/web-platform/tests/css/css-highlight-api/Highlight-setlike-tampered-Set-prototype.html b/testing/web-platform/tests/css/css-highlight-api/Highlight-setlike-tampered-Set-prototype.html
new file mode 100644
index 0000000000..4c23f4850c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/Highlight-setlike-tampered-Set-prototype.html
@@ -0,0 +1,55 @@
+<!doctype html>
+<title>Highlight is a setlike interface that works as expected even if Set.prototype is tampered</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+"use strict";
+
+function tamperSetPrototype() {
+ delete Set.prototype.size;
+
+ Set.prototype.entries = null;
+ Set.prototype.forEach = undefined;
+ Set.prototype.has = "foo";
+ Set.prototype.keys = 0;
+ Set.prototype.values = Symbol();
+ Set.prototype[Symbol.iterator] = 1;
+ Set.prototype.add = true;
+ Set.prototype.clear = "";
+ Set.prototype.delete = -1.5;
+
+ Object.freeze(Set.prototype);
+}
+
+test(() => {
+ tamperSetPrototype();
+
+ const staticRange = new StaticRange({startContainer: document.body, endContainer: document.body, startOffset: 0, endOffset: 0});
+ const highlight = new Highlight(staticRange);
+
+ assert_equals(highlight.size, 1);
+ assert_true(highlight.has(staticRange));
+ assert_equals([...highlight.entries()][0][0], staticRange);
+
+ highlight.clear();
+ assert_equals(highlight.size, 0);
+
+ highlight.add(staticRange);
+ assert_equals(highlight.size, 1);
+
+ highlight.delete(staticRange);
+ assert_equals(highlight.size, 0);
+ assert_false(highlight.has(staticRange));
+
+ highlight.add(staticRange);
+ assert_equals([...highlight.keys()][0], staticRange);
+ assert_equals([...highlight.values()][0], staticRange);
+
+ let callbackCalled = false;
+ highlight.forEach(() => { callbackCalled = true; });
+ assert_true(callbackCalled);
+}, "Highlight is a setlike interface that works as expected even if Set.prototype is tampered.");
+</script>
diff --git a/testing/web-platform/tests/css/css-highlight-api/Highlight-setlike.html b/testing/web-platform/tests/css/css-highlight-api/Highlight-setlike.html
new file mode 100644
index 0000000000..0093f9be23
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/Highlight-setlike.html
@@ -0,0 +1,106 @@
+<!doctype html>
+<title> Highlight has a setlike interface </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id='testDiv'>abc</div>
+<script>
+ 'use strict';
+ let priority = 123;
+
+ test(() => {
+ let customHighlight = new Highlight();
+ assert_equals(customHighlight.priority, 0, 'Highlight uses 0 as priority by default.');
+
+ customHighlight.priority = priority;
+ assert_equals(customHighlight.priority, priority, 'Highlight sets priority correctly.');
+
+ assert_equals(customHighlight.size, 0, 'Highlight starts empty');
+ }, 'Highlight initializes empty (if no ranges are provided) and with priority 0.');
+
+ let range0 = new Range();
+ let range1 = new Range();
+ let range2 = new Range();
+
+ let container = document.getElementById('testDiv');
+ let staticRange0 = new StaticRange({startContainer: container, startOffset: 0, endContainer: container, endOffset: 0});
+ let staticRange1 = new StaticRange({startContainer: container, startOffset: 0, endContainer: container, endOffset: 0});
+ let staticRange2 = new StaticRange({startContainer: container, startOffset: 0, endContainer: container, endOffset: 0});
+
+ let rangeCollections = [[range0,range1,range2], [staticRange0,staticRange1,staticRange2], [range0,staticRange1,range2], [staticRange0,range1,staticRange2]]
+
+ var i;
+ for(i=0; i<rangeCollections.length; i++){
+ let rangesCombinationDescription = " (using the following combination of ranges [";
+ var j;
+ for(j=0; j<rangeCollections[i].length; j++){
+ if(j!=0) rangesCombinationDescription += ", ";
+ rangesCombinationDescription = rangesCombinationDescription + Object.prototype.toString.call(rangeCollections[i][j]);
+ }
+ rangesCombinationDescription += "])";
+
+ test(() => {
+ let customHighlight = new Highlight();
+ assert_false(customHighlight.has(rangeCollections[i][0]), 'Highlight.has returns false when it doesn\'t contain the range which is passed as the argument');
+ assert_false(customHighlight.has(rangeCollections[i][1]), 'Highlight.has returns false when it doesn\'t contain the range which is passed as the argument');
+ assert_false(customHighlight.has(rangeCollections[i][2]), 'Highlight.has returns false when it doesn\'t contain the range which is passed as the argument');
+ customHighlight.add(rangeCollections[i][0]);
+ assert_true(customHighlight.has(rangeCollections[i][0]), 'Highlight.has returns true when it contains the range which is passed as the argument');
+ assert_false(customHighlight.has(rangeCollections[i][1]), 'Highlight.has returns false when it doesn\'t contain the range which is passed as the argument');
+ assert_false(customHighlight.has(rangeCollections[i][2]), 'Highlight.has returns false when it doesn\'t contain the range which is passed as the argument');
+
+ assert_equals(customHighlight.size, 1, 'Highlight.size is 1 after only adding 1 range');
+ customHighlight.add(rangeCollections[i][0]);
+ assert_equals(customHighlight.size, 1, 'Highlight.size is 1 after only adding same range twice');
+
+ customHighlight.add(rangeCollections[i][1]);
+ assert_true(customHighlight.has(rangeCollections[i][0]), 'Highlight.has returns true when it contains the range which is passed as the argument');
+ assert_true(customHighlight.has(rangeCollections[i][1]), 'Highlight.has returns true when it contains the range which is passed as the argument');
+ assert_false(customHighlight.has(rangeCollections[i][2]), 'Highlight.has returns false when it doesn\'t contain the range which is passed as the argument');
+
+ assert_equals(customHighlight.size, 2, 'Highlight.size is 2 after only adding two different ranges');
+ }, 'Highlight add and has methods work as expected' + rangesCombinationDescription);
+
+ test(() => {
+ let customHighlight = new Highlight(rangeCollections[i][0], rangeCollections[i][1]);
+ assert_false(customHighlight.delete(rangeCollections[i][2]), 'Highlight.delete returns false when trying to delete a range that is not in the highlight');
+ assert_true(customHighlight.delete(rangeCollections[i][1]), 'Highlight.delete returns true when trying to delete a range that is in the highlight');
+ assert_false(customHighlight.delete(rangeCollections[i][1]), 'Highlight.delete returns false when trying to delete a range that was in the highlight before but it\'s not there anymore');
+ assert_true(customHighlight.delete(rangeCollections[i][0]), 'Highlight.delete returns true when trying to delete a range that is in the highlight');
+ assert_false(customHighlight.delete(rangeCollections[i][0]), 'Highlight.delete returns false when trying to delete a range that was in the highlight before but it\'s not there anymore');
+ }, 'Highlight delete method works as expected' + rangesCombinationDescription);
+
+ test(() => {
+ let customHighlight = new Highlight(rangeCollections[i][0], rangeCollections[i][0]);
+ assert_true(customHighlight.has(rangeCollections[i][0]), 'Highlight.has returns true when it is called with the range used twice in the constructor');
+ assert_equals(customHighlight.size, 1, 'Highlight behaves like a set when constructing it with two equal ranges.');
+
+ customHighlight = new Highlight(rangeCollections[i][0], rangeCollections[i][1], rangeCollections[i][0], rangeCollections[i][1]);
+ assert_true(customHighlight.has(rangeCollections[i][0]), 'Highlight.has returns true when it is called with one of the ranges used twice in the constructor');
+ assert_true(customHighlight.has(rangeCollections[i][1]), 'Highlight.has returns true when it is called with the other range used twice in the constructor');
+ assert_equals(customHighlight.size, 2, 'Highlight behaves like a set when constructing it with two pairs of equal ranges.');
+ }, 'Highlight constructor behaves like a set when using equal ranges' + rangesCombinationDescription);
+
+ test(() => {
+ let customHighlight = new Highlight(rangeCollections[i][0]);
+ assert_true(customHighlight.has(rangeCollections[i][0]), 'Highlight.has returns true when it is called with the range used in its constructor');
+ assert_equals(customHighlight.size, 1, 'Highlight.size is 1 after constructing it with one range');
+ }, 'Highlight constructor works as expected when called with one range' + rangesCombinationDescription);
+
+ test(() => {
+ let customHighlight = new Highlight(rangeCollections[i][0], rangeCollections[i][1]);
+ assert_true(customHighlight.has(rangeCollections[i][0]), 'Highlight.has returns true when it is called with the first range used in its constructor');
+ assert_true(customHighlight.has(rangeCollections[i][1]), 'Highlight.has returns true when it is called with the second range used in its constructor');
+ assert_equals(customHighlight.size, 2, 'Highlight.size is 2 after constructing it with two ranges');
+ }, 'Highlight constructor works as expected when called with two ranges' + rangesCombinationDescription);
+
+ test(() => {
+ let customHighlight = new Highlight(rangeCollections[i][0], rangeCollections[i][1]);
+ assert_equals(customHighlight.size, 2, 'Highlight has size 2 after constructing it with two ranges');
+ customHighlight.clear();
+ assert_equals(customHighlight.size, 0, 'Highlight becomes empty after executing clear()');
+ customHighlight.clear();
+ assert_equals(customHighlight.size, 0, 'Highlight is still empty after executing clear() twice');
+ }, 'Highlight clear method works as expected' + rangesCombinationDescription);
+ }
+</script>
diff --git a/testing/web-platform/tests/css/css-highlight-api/Highlight-type-attribute.tentative.html b/testing/web-platform/tests/css/css-highlight-api/Highlight-type-attribute.tentative.html
new file mode 100644
index 0000000000..97e3aaa3ca
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/Highlight-type-attribute.tentative.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title> Highlight type attribute tests </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ test(() => {
+ let customHighlight = new Highlight();
+ assert_equals(customHighlight.type, "highlight", 'Highlight uses \"highlight\" as default type.');
+
+ customHighlight.type = "type-not-listed-in-HighlightType-enum";
+ assert_equals(customHighlight.type, "highlight", 'Highlight type doesn\'t change after assigning an invalid value.');
+
+ customHighlight.type = "spelling-error";
+ assert_equals(customHighlight.type, "spelling-error", 'Highlight type changes to the assigned value if it\'s part of the HighlightType enum (\"spelling-error\"").');
+
+ customHighlight.type = "grammar-error";
+ assert_equals(customHighlight.type, "grammar-error", 'Highlight type changes to the assigned value if it\'s part of the HighlightType enum (\"grammar-error\").');
+ }, 'Highlight has a mutable \'type\' attribute that is a HighlightType enum.');
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/HighlightRegistry-iteration-with-modifications.html b/testing/web-platform/tests/css/css-highlight-api/HighlightRegistry-iteration-with-modifications.html
new file mode 100644
index 0000000000..7e1a0c08f3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/HighlightRegistry-iteration-with-modifications.html
@@ -0,0 +1,109 @@
+<!doctype html>
+<title>HighlightRegistry iteration with insertions and deletions inbetween</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ 'use strict';
+ let customHighlight1 = new Highlight();
+ let customHighlight2 = new Highlight();
+ let highlightName1 = "example1";
+ let highlightName2 = "example2";
+
+ // Test insertions using .add
+ test(() => {
+ let iterator = CSS.highlights[Symbol.iterator]();
+ CSS.highlights.set(highlightName1, customHighlight1);
+ let element = iterator.next();
+ assert_true(element.done, 'The iteration ends although we added a new Highlight after starting the iteration');
+ assert_equals(element.value, undefined, 'A Highlight added after starting the iteration is not found during the current iteration');
+ }, 'HighlightRegistry iteration is not modified when a new Highlight is added after starting the iteration');
+
+ CSS.highlights.clear();
+
+ test(() => {
+ CSS.highlights.set(highlightName1, customHighlight1);
+ let iterator = CSS.highlights[Symbol.iterator]();
+ CSS.highlights.set(highlightName2, customHighlight2);
+ let element = iterator.next();
+ assert_false(element.done, 'The iteration doesn\'t end although there was a second Highlight added to the HighlightRegistry after starting the iteration');
+ assert_equals(element.value[0], highlightName1, 'The highlight name that was pointed to by the iterator is returned although a second Highlight was added after starting the iteration');
+ assert_equals(element.value[1], customHighlight1, 'The Highlight that was pointed to by the iterator is returned although a second Highlight was added after starting the iteration');
+ element = iterator.next();
+ assert_true(element.done, 'The iteration ends after going through all the Highlights that were in the HighlightRegistry when the iteration started although there was a Highlight addition after starting the iteration');
+ assert_equals(element.value, undefined, 'A Highlight added after starting the iteration is not found during the current iteration');
+ }, 'HighlightRegistry iteration is not modified when a new Highlight is added after starting the iteration with one Highlight in the HighlightRegistry');
+
+ CSS.highlights.clear();
+
+ // Test deletions using .delete
+ test(() => {
+ CSS.highlights.set(highlightName1, customHighlight1);
+ let iterator = CSS.highlights[Symbol.iterator]();
+ CSS.highlights.delete(highlightName1);
+ let element = iterator.next();
+ assert_false(element.done, 'The iteration doesn\'t end although the Highlight that was pointed to by the iterator was deleted');
+ assert_equals(element.value[0], highlightName1, 'The highlight name that was pointed to by the iterator is returned although it was deleted after starting the iteration');
+ assert_equals(element.value[1], customHighlight1, 'The Highlight that was pointed to by the iterator is returned although it was deleted after starting the iteration');
+ element = iterator.next();
+ assert_true(element.done, 'The iteration ends after going through all the highlights although the Highlight that was pointed to by the iterator was deleted after starting the iteration');
+ assert_equals(element.value, undefined, '.next() returns undefined when the iteration ends');
+ }, 'HighlightRegistry iteration is not modified when the Highlight that was pointed to by the iterator was deleted after starting the iteration');
+
+ CSS.highlights.clear();
+
+ test(() => {
+ CSS.highlights.set(highlightName1, customHighlight1);
+ CSS.highlights.set(highlightName2, customHighlight2);
+ let iterator = CSS.highlights[Symbol.iterator]();
+ CSS.highlights.delete(highlightName2);
+ let element = iterator.next();
+ assert_false(element.done, 'The iteration doesn\'t end although the Highlight following to the one that was pointed to by the iterator was deleted');
+ assert_equals(element.value[0], highlightName1, 'The highlight name that was pointed to by the iterator is returned as it should although the next Highlight was deleted immediately after starting the iteration');
+ assert_equals(element.value[1], customHighlight1, 'The Highlight that was pointed to by the iterator is returned as it should although the next Highlight was deleted immediately after starting the iteration');
+ element = iterator.next();
+ assert_false(element.done, 'The iteration doesn\'t end when you call .next twice since the beginning of the iteration although the second Highlight was deleted');
+ assert_equals(element.value[0], highlightName2, 'The highlight name that was pointed to by the iterator is returned as it should although the next Highlight was deleted immediately after starting the iteration');
+ assert_equals(element.value[1], customHighlight2, 'The Highlight that was pointed to by the iterator is returned as it should although the next Highlight was deleted immediately after starting the iteration');
+ element = iterator.next();
+ assert_true(element.done, 'The iteration ends after going through all the highlights although the second Highlight was deleted immediately after starting the iteration');
+ assert_equals(element.value, undefined, '.next() returns undefined when the iteration ends');
+ }, 'HighlightRegistry iteration is not modified when the Highlight that was immediately after the one pointed to by the iterator was deleted after starting the iteration');
+
+ CSS.highlights.clear();
+
+ test(() => {
+ CSS.highlights.set(highlightName1, customHighlight1);
+ CSS.highlights.set(highlightName2, customHighlight2);
+ let iterator = CSS.highlights[Symbol.iterator]();
+ let element = iterator.next();
+ assert_false(element.done, 'The iteration doesn\'t end when there are still two Highlights to visit');
+ assert_equals(element.value[0], highlightName1, 'The highlight name that was pointed to by the iterator is returned as it should');
+ assert_equals(element.value[1], customHighlight1, 'The Highlight that was pointed to by the iterator is returned as it should');
+ CSS.highlights.delete(highlightName1);
+ element = iterator.next();
+ assert_false(element.done, 'The iteration doesn\'t end when the Highlight previously visited is deleted and there is still a Highlight to visit');
+ assert_equals(element.value[0], highlightName2, 'The highlight name that was pointed to by the iterator is returned as it should although the previous Highlight was deleted after calling .next');
+ assert_equals(element.value[1], customHighlight2, 'The Highlight that was pointed to by the iterator is returned as it should although the previous Highlight was deleted after calling .next');
+ element = iterator.next();
+ assert_true(element.done, 'The iteration ends after going through all the highlights although the first Highlight was deleted after the first call to .next');
+ assert_equals(element.value, undefined, '.next() returns undefined when the iteration ends');
+ }, 'HighlightRegistry iteration is not modified when a Highlight that was already visited is deleted and there are still Highlights to visit');
+
+ CSS.highlights.clear();
+
+ // Test deletions using .clear
+ test(() => {
+ CSS.highlights.set(highlightName1, customHighlight1);
+ let iterator = CSS.highlights[Symbol.iterator]();
+ CSS.highlights.clear();
+ let element = iterator.next();
+ assert_false(element.done, 'The iteration doesn\'t end although the Highlight that was pointed to by the iterator was deleted using .clear()');
+ assert_equals(element.value[0], highlightName1, 'The highlight name that was pointed to by the iterator is returned although it was deleted using .clear() after starting the iteration');
+ assert_equals(element.value[1], customHighlight1, 'The Highlight that was pointed to by the iterator is returned although it was deleted using .clear() after starting the iteration');
+ element = iterator.next();
+ assert_true(element.done, 'The iteration ends after going through all the highlights although the Highlight that was pointed to by the iterator was deleted using .clear() after starting the iteration');
+ assert_equals(element.value, undefined, '.next() returns undefined when the iteration ends');
+ }, 'HighlightRegistry iteration is not modified when the Highlight that was pointed to by the iterator was deleted using .clear() after starting the iteration');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-highlight-api/HighlightRegistry-iteration.html b/testing/web-platform/tests/css/css-highlight-api/HighlightRegistry-iteration.html
new file mode 100644
index 0000000000..b1bc1afecb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/HighlightRegistry-iteration.html
@@ -0,0 +1,186 @@
+<!doctype html>
+<title>HighlightRegistry iteration</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ 'use strict';
+ let customHighlight1 = new Highlight();
+ let customHighlight2 = new Highlight();
+ let highlightName1 = "example1";
+ let highlightName2 = "example2";
+
+ function getIterator(iterationInitialization){
+ var iterator;
+ if(iterationInitialization === "CSS.highlights[Symbol.iterator]()"){
+ iterator = CSS.highlights[Symbol.iterator]();
+ }
+ else if(iterationInitialization === "CSS.highlights.entries()"){
+ iterator = CSS.highlights.entries();
+ }
+ else if(iterationInitialization === "CSS.highlights.values()"){
+ iterator = CSS.highlights.values();
+ }
+ else if(iterationInitialization === "CSS.highlights.keys()"){
+ iterator = CSS.highlights.keys();
+ }
+ return iterator;
+ }
+
+
+ // Test .keys()
+
+ let iterationInitialization = "CSS.highlights.keys()";
+ test(() => {
+ let iterator = getIterator(iterationInitialization);
+ let element = iterator.next();
+ assert_true(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===true when there are no more highlight names to iterate');
+ assert_equals(element.value, undefined, 'HighlightRegistry is iterable and .next() returns an element with .value undefined when there are no more highlight names to iterate.');
+ }, 'HighlightRegistry can be iterated when it\'s empty initializing the iterator with ' + iterationInitialization);
+
+ test(() => {
+ CSS.highlights.set(highlightName1, customHighlight1);
+ let iterator = getIterator(iterationInitialization);
+ let element = iterator.next();
+ assert_false(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===false when the iteration didn\'t go past the last highlight name');
+ assert_equals(element.value, highlightName1, '.next() returns an element with .value corresponding to the first highlight name added to the HighlightRegistry');
+ element = iterator.next();
+ assert_true(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===true when there are no more highlight names to iterate');
+ assert_equals(element.value, undefined, 'HighlightRegistry is iterable and .next() returns an element with .value undefined when there are no more highlight names to iterate.');
+ }, 'HighlightRegistry can be iterated over all of its highlight names after adding one of them initializing the iterator with ' + iterationInitialization);
+
+ test(() => {
+ CSS.highlights.set(highlightName2, customHighlight2);
+ let iterator = getIterator(iterationInitialization);
+ let element = iterator.next();
+ assert_false(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===false when the iteration didn\'t go past the last highlight');
+ assert_equals(element.value, highlightName1, '.next() returns an element with .value corresponding to the first highlight name added to the HighlightRegistry');
+ element = iterator.next();
+ assert_false(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===false when the iteration didn\'t go past the last highlight');
+ assert_equals(element.value, highlightName2, '.next() returns an element with .value corresponding to the second highlight name added to the HighlightRegistry');
+ element = iterator.next();
+ assert_true(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===true when there are no more highlight names to iterate');
+ assert_equals(element.value, undefined, 'HighlightRegistry is iterable and .next() returns an element with .value undefined when there are no more highlight names to iterate.');
+ }, 'HighlightRegistry can be iterated over all of its highlight names after adding two of them initializing the iterator with ' + iterationInitialization);
+
+ CSS.highlights.clear();
+
+
+ // Test .values()
+
+ iterationInitialization = "CSS.highlights.values()";
+ test(() => {
+ let iterator = getIterator(iterationInitialization);
+ let element = iterator.next();
+ assert_true(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===true when there are no more highlights to iterate');
+ assert_equals(element.value, undefined, 'HighlightRegistry is iterable and .next() returns an element with .value undefined when there are no more highlights to iterate.');
+ }, 'HighlightRegistry can be iterated when it\'s empty initializing the iterator with ' + iterationInitialization);
+
+ test(() => {
+ CSS.highlights.set(highlightName1, customHighlight1);
+ let iterator = getIterator(iterationInitialization);
+ let element = iterator.next();
+ assert_false(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===false when the iteration didn\'t go past the last highlight');
+ assert_equals(element.value, customHighlight1, '.next() returns an element with .value corresponding to the first Highlight added to the HighlightRegistry');
+ element = iterator.next();
+ assert_true(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===true when there are no more highlights to iterate');
+ assert_equals(element.value, undefined, 'HighlightRegistry is iterable and .next() returns an element with .value undefined when there are no more highlights to iterate.');
+ }, 'HighlightRegistry can be iterated over all of its Highlights after adding one of them initializing the iterator with ' + iterationInitialization);
+
+ test(() => {
+ CSS.highlights.set(highlightName2, customHighlight2);
+ let iterator = getIterator(iterationInitialization);
+ let element = iterator.next();
+ assert_false(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===false when the iteration didn\'t go past the last highlight');
+ assert_equals(element.value, customHighlight1, '.next() returns an element with .value corresponding to the first Highlight added to the HighlightRegistry');
+ element = iterator.next();
+ assert_false(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===false when the iteration didn\'t go past the last highlight');
+ assert_equals(element.value, customHighlight2, '.next() returns an element with .value corresponding to the second Highlight added to the HighlightRegistry');
+ element = iterator.next();
+ assert_true(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===true when there are no more highlights to iterate');
+ assert_equals(element.value, undefined, 'HighlightRegistry is iterable and .next() returns an element with .value undefined when there are no more highlights to iterate.');
+ }, 'HighlightRegistry can be iterated over all of its Highlights after adding two of them initializing the iterator with ' + iterationInitialization);
+
+ CSS.highlights.clear();
+
+
+ // Test [Symbol.iterator]() and .entries()
+
+ let iterationInitializationCollection = ["CSS.highlights[Symbol.iterator]()", "CSS.highlights.entries()"];
+ for(let iterationInitialization of iterationInitializationCollection){
+ test(() => {
+ let iterator = getIterator(iterationInitialization);
+ let element = iterator.next();
+ assert_true(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===true when there are no more highlights to iterate');
+ assert_equals(element.value, undefined, 'HighlightRegistry is iterable and .next() returns an element with .value undefined when there are no more highlights to iterate.');
+ }, 'HighlightRegistry can be iterated when it\'s empty initializing the iterator with ' + iterationInitialization);
+
+ test(() => {
+ CSS.highlights.set(highlightName1, customHighlight1);
+ let iterator = getIterator(iterationInitialization);
+ let element = iterator.next();
+ assert_false(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===false when the iteration didn\'t go past the last highlight');
+ assert_equals(element.value[0], highlightName1, '.next() returns an element with .value[0] corresponding to the first Highlight name added to the HighlightRegistry');
+ assert_equals(element.value[1], customHighlight1, '.next() returns an element with .value[1] corresponding to the first Highlight added to the HighlightRegistry');
+ element = iterator.next();
+ assert_true(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===true when there are no more highlights to iterate');
+ assert_equals(element.value, undefined, 'HighlightRegistry is iterable and .next() returns an element with .value undefined when there are no more highlights to iterate.');
+ }, 'HighlightRegistry can be iterated over all of its Highlights after adding one of them initializing the iterator with ' + iterationInitialization);
+
+ test(() => {
+ CSS.highlights.set(highlightName2, customHighlight2);
+ let iterator = getIterator(iterationInitialization);
+ let element = iterator.next();
+ assert_false(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===false when the iteration didn\'t go past the last highlight');
+ assert_equals(element.value[0], highlightName1, '.next() returns an element with .value[0] corresponding to the first Highlight name added to the HighlightRegistry');
+ assert_equals(element.value[1], customHighlight1, '.next() returns an element with .value[1] corresponding to the first Highlight added to the HighlightRegistry');
+ element = iterator.next();
+ assert_false(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===false when the iteration didn\'t go past the last highlight');
+ assert_equals(element.value[0], highlightName2, '.next() returns an element with .value[0] corresponding to the second Highlight name added to the HighlightRegistry');
+ assert_equals(element.value[1], customHighlight2, '.next() returns an element with .value[1] corresponding to the second Highlight added to the HighlightRegistry');
+ element = iterator.next();
+ assert_true(element.done, 'HighlightRegistry is iterable and .next() returns an element with .done===true when there are no more highlights to iterate');
+ assert_equals(element.value, undefined, 'HighlightRegistry is iterable and .next() returns an element with .value undefined when there are no more highlights to iterate.');
+ }, 'HighlightRegistry can be iterated over all of its Highlights after adding two of them initializing the iterator with ' + iterationInitialization);
+
+ CSS.highlights.clear();
+ }
+
+
+ // Test .forEach
+
+ function compareArrays(array1, array2){
+ if(array1.length != array2.length){
+ return false;
+ }
+ for(let index=0; index<array1.length; ++index){
+ if(array1[index] != array2[index])
+ return false;
+ }
+ return true;
+ }
+
+ let expectedResult = [];
+
+ test(() => {
+ let actualResult = [];
+ CSS.highlights.forEach((highlight) => {actualResult.push(highlight);});
+ assert_true(compareArrays(actualResult, expectedResult), 'The highlights seen match the highlights added');
+ }, 'HighlightRegistry can be iterated through when it\'s empty using forEach.');
+
+ test(() => {
+ CSS.highlights.set(highlightName1, customHighlight1);
+ expectedResult.push(customHighlight1);
+ let actualResult = [];
+ CSS.highlights.forEach((highlight) => {actualResult.push(highlight);});
+ assert_true(compareArrays(actualResult, expectedResult), 'The highlights seen match the highlights added');
+ }, 'HighlightRegistry can be iterated through when it has one Highlight using forEach.');
+
+ test(() => {
+ CSS.highlights.set(highlightName2, customHighlight2);
+ expectedResult.push(customHighlight2);
+ let actualResult = [];
+ CSS.highlights.forEach((highlight) => {actualResult.push(highlight);});
+ assert_true(compareArrays(actualResult, expectedResult), 'The highlights seen match the highlights added');
+ }, 'HighlightRegistry can be iterated through when it has two Highlights using forEach.');
+</script>
diff --git a/testing/web-platform/tests/css/css-highlight-api/HighlightRegistry-maplike-tampered-Map-prototype.html b/testing/web-platform/tests/css/css-highlight-api/HighlightRegistry-maplike-tampered-Map-prototype.html
new file mode 100644
index 0000000000..3b38bd8f16
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/HighlightRegistry-maplike-tampered-Map-prototype.html
@@ -0,0 +1,61 @@
+<!doctype html>
+<title>HighlightRegistry is a maplike interface that works as expected even if Map.prototype is tampered</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+"use strict";
+
+function tamperMapPrototype() {
+ delete Map.prototype.size;
+
+ Map.prototype.entries = null;
+ Map.prototype.forEach = undefined;
+ Map.prototype.get = "foo";
+ Map.prototype.has = 0;
+ Map.prototype.keys = Symbol();
+ Map.prototype.values = 1;
+ Map.prototype[Symbol.iterator] = true;
+ Map.prototype.clear = false;
+ Map.prototype.delete = "";
+ Map.prototype.set = 3.14;
+
+ Object.freeze(Map.prototype);
+}
+
+test(() => {
+ tamperMapPrototype();
+
+ const highlight = new Highlight(new StaticRange({startContainer: document.body, endContainer: document.body, startOffset: 0, endOffset: 0}));
+ const highlightRegister = new HighlightRegister();
+
+ assert_equals(highlightRegister.size, 0);
+ highlightRegister.set("foo", highlight);
+ assert_equals(highlightRegister.size, 1);
+
+ assert_true(highlightRegister.has("foo"));
+ assert_equals([...highlightRegister.entries()][0][0], "foo");
+
+ highlightRegister.clear();
+ assert_equals(highlightRegister.size, 0);
+ assert_equals(highlightRegister.get("foo"), undefined);
+
+ highlightRegister.set("bar", highlight);
+ assert_equals(highlightRegister.get("bar"), highlight);
+ assert_equals([...highlightRegister][0][1], highlight);
+
+ highlightRegister.delete("bar");
+ assert_equals(highlightRegister.size, 0);
+ assert_false(highlightRegister.has("bar"));
+
+ highlightRegister.set("baz", highlight);
+ assert_equals([...highlightRegister.keys()][0], "baz");
+ assert_equals([...highlightRegister.values()][0], highlight);
+
+ let callbackCalled = false;
+ highlightRegister.forEach(() => { callbackCalled = true; });
+ assert_true(callbackCalled);
+}, "HighlightRegistry is a maplike interface that works as expected even if Map.prototype is tampered.");
+</script>
diff --git a/testing/web-platform/tests/css/css-highlight-api/HighlightRegistry-maplike.html b/testing/web-platform/tests/css/css-highlight-api/HighlightRegistry-maplike.html
new file mode 100644
index 0000000000..d8bbe4731f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/HighlightRegistry-maplike.html
@@ -0,0 +1,75 @@
+<!doctype html>
+<title>HighlightRegistry has a maplike interface</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ 'use strict';
+
+ test(() => {
+ assert_not_equals(window.HighlightRegistry, undefined, 'HighlightRegistry is in window');
+ assert_equals(typeof HighlightRegistry, 'function', 'HighlightRegistry is a function');
+ assert_throws_js(TypeError, function () { var x = new HighlightRegistry(); },
+ 'HighlightRegistry constructor throws');
+
+ assert_not_equals(CSS.highlights, undefined, 'CSS.highlights exists');
+ assert_equals(CSS.highlights.__proto__, window.HighlightRegistry.prototype,
+ 'CSS.highlights and window.HighlightRegistry have same prototype');
+
+ assert_equals(CSS.highlights.size, 0, 'HighlightRegistry starts empty');
+ }, 'HighlightRegistry initializes as it should.');
+
+ test(() => {
+ let name1 = "example1";
+ let name2 = "example2";
+ let h1 = new Highlight();
+ let h2 = new Highlight();
+
+ assert_false(CSS.highlights.has(name1), 'HighlightRegistry.has returns false when it doesn\'t have the key which is called with as argument.');
+ CSS.highlights.set(name1, h1);
+ assert_true(CSS.highlights.has(name1), 'HighlightRegistry.has returns true when it has the key which is called with as argument.');
+ assert_equals(CSS.highlights.size, 1, 'HighlightRegistry.size is 1 after only inserting 1 key.');
+
+ assert_false(CSS.highlights.delete(name2), 'HighlightRegistry.delete returns false when trying to delete an key that is not in the map.');
+ assert_equals(CSS.highlights.size, 1, 'HighlightRegistry.size stays the same after trying to delete a non-existing key.');
+
+ CSS.highlights.set(name2, h2);
+ assert_true(CSS.highlights.has(name1), 'HighlightRegistry.has returns true when it is called with the key inserted first');
+ assert_true(CSS.highlights.has(name2), 'HighlightRegistry.has returns true when it is called with the key inserted second');
+ assert_equals(CSS.highlights.get(name1), h1, 'HighlightRegistry.get returns the first Highlight when it is called with the key inserted first');
+ assert_equals(CSS.highlights.get(name2), h2, 'HighlightRegistry.get returns the second Highlight when it is called with the key inserted second');
+ assert_equals(CSS.highlights.size, 2, 'HighlightRegistry.size is 2 after only inserting two different keys.');
+
+ assert_true(CSS.highlights.delete(name2), 'HighlightRegistry.delete returns true when trying to delete a key that is in the group.');
+ assert_true(CSS.highlights.has(name1), 'HighlightRegistry.has returns true when it is called with the key inserted first');
+ assert_false(CSS.highlights.has(name2), 'HighlightRegistry.has returns true when it is called with the key that was deleted');
+ assert_equals(CSS.highlights.get(name1), h1, 'HighlightRegistry.get still returns the first Highlight when it is called with the key inserted first');
+ assert_equals(CSS.highlights.get(name2), undefined, 'HighlightRegistry.get returns undefined when it is called with a key that was deleted');
+ assert_equals(CSS.highlights.size, 1, 'HighlightRegistry.size decreases in 1 after deleting an existing key.');
+
+ assert_false(CSS.highlights.delete(name2), 'HighlightRegistry.delete returns false when trying to delete a key that was already deleted.');
+ assert_true(CSS.highlights.has(name1), 'HighlightRegistry.has returns true when it is called with the key inserted first');
+ assert_false(CSS.highlights.has(name2), 'HighlightRegistry.has returns false when it is called with a key that was deleted twice');
+ assert_equals(CSS.highlights.get(name1), h1, 'HighlightRegistry.get still returns the first Highlight when it is called with the key inserted first');
+ assert_equals(CSS.highlights.get(name2), undefined, 'HighlightRegistry.get still returns undefined when it is called with a key that was deleted');
+ assert_equals(CSS.highlights.size, 1, 'HighlightRegistry.size stays the same after trying to delete the same key for a second time.');
+
+ assert_true(CSS.highlights.delete(name1), 'HighlightRegistry.delete returns true when trying to delete the remaining key');
+ assert_false(CSS.highlights.has(name1), 'HighlightRegistry.has returns false when it is called with the key inserted first and then deleted');
+ assert_false(CSS.highlights.has(name2), 'HighlightRegistry.has returns false when it is called with the key inserted second and then deleted');
+ assert_equals(CSS.highlights.get(name1), undefined, 'HighlightRegistry.get returns undefined when it is called with a key that was deleted');
+ assert_equals(CSS.highlights.get(name2), undefined, 'HighlightRegistry.get returns undefined when it is called with a key that was deleted');
+ assert_equals(CSS.highlights.size, 0, 'HighlightRegistry.size decreases in 1 after deleting an existing key.');
+
+ CSS.highlights.set(name1, h1);
+ CSS.highlights.set(name1, h2);
+ assert_equals(CSS.highlights.size, 1, 'HighlightRegistry.size keeps the same after an insertion of a Highlight with an existing name');
+ assert_equals(CSS.highlights.get(name1), h2, 'The Highlight inserted with the same name as an existing one was effectively inserted into the registry');
+
+ CSS.highlights.clear();
+ assert_equals(CSS.highlights.size, 0, 'HighlightRegistry.clear empties the map.');
+ CSS.highlights.clear();
+ assert_equals(CSS.highlights.size, 0, 'HighlightRegistry.clear called with an empty registry keeps it empty.');
+ }, 'HighlightRegistry has a maplike interface.');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-highlight-api/highlight-pseudo-computed.html b/testing/web-platform/tests/css/css-highlight-api/highlight-pseudo-computed.html
new file mode 100644
index 0000000000..e50f1801b0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/highlight-pseudo-computed.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS ::highlight Pseudo-Element Test: ::highlight selector getComputedStyle</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ #target::highlight(foo) {
+ background-color: green;
+ color: lime;
+ }
+ #target::highlight(bar) {
+ background-color: cyan;
+ color: fuchsia;
+ }
+</style>
+<div id="target"></div>
+<script>
+ let highlightPseudo = "::highlight(foo)";
+ test(() => {
+ let style = getComputedStyle(target, highlightPseudo);
+ assert_equals(style.backgroundColor, "rgb(0, 128, 0)", "Background color is green.");
+ assert_equals(style.color, "rgb(0, 255, 0)", "Color is lime.");
+ }, `getComputedStyle() for ${highlightPseudo}`);
+
+ highlightPseudo = "::highlight(bar)";
+ test(() => {
+ let style = getComputedStyle(target, highlightPseudo);
+ assert_equals(style.backgroundColor, "rgb(0, 255, 255)", "Background color is cyan.");
+ assert_equals(style.color, "rgb(255, 0, 255)", "Color is fuchsia.");
+ }, `Different getComputedStyle() for ${highlightPseudo} and same element`);
+
+ for (const illHighlightPseudo of ["::highlight(foo):", "::highlight(foo))", "::highlight(foo)(", "::highlight", "::highlight(foo)(foo)", "::highlight(foo)()", ":::highlight(foo)", "::highlight(foo).", "::highlight(foo,bar)"]) {
+ test(() => {
+ let style = getComputedStyle(target, illHighlightPseudo);
+ let defaultStyle = getComputedStyle(target);
+ assert_equals(style.backgroundColor, defaultStyle.backgroundColor, "Background color is element's default.");
+ assert_equals(style.color, defaultStyle.color, "Color is element's default.");
+ }, `getComputedStyle() for ${illHighlightPseudo} should be element's default`);
+ }
+</script>
diff --git a/testing/web-platform/tests/css/css-highlight-api/highlight-pseudo-parsing.html b/testing/web-platform/tests/css/css-highlight-api/highlight-pseudo-parsing.html
new file mode 100644
index 0000000000..c6d999efdf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/highlight-pseudo-parsing.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS ::highlight Pseudo-Element Test: ::highlight selector parsing</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script>
+ const pseudo = "::highlight(foo)";
+ test_valid_selector(`${pseudo}`);
+ test_valid_selector(`.a${pseudo}`);
+ test_valid_selector(`div ${pseudo}`);
+ test_valid_selector(`::part(my-part)${pseudo}`);
+
+ test_invalid_selector(`::before${pseudo}`);
+ test_invalid_selector(`${pseudo}.a`);
+ test_invalid_selector(`${pseudo} div`);
+ test_invalid_selector(`${pseudo}::after`);
+ test_invalid_selector(`${pseudo}:hover`);
+ test_invalid_selector(`:not(${pseudo})`);
+</script>
diff --git a/testing/web-platform/tests/css/css-highlight-api/idlharness.window.js b/testing/web-platform/tests/css/css-highlight-api/idlharness.window.js
new file mode 100644
index 0000000000..7e9f3c4404
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/idlharness.window.js
@@ -0,0 +1,17 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+// https://drafts.csswg.org/css-highlight-api-1/
+
+'use strict';
+
+idl_test(
+ ['css-highlight-api'],
+ ['cssom'],
+ idl_array => {
+ idl_array.add_objects({
+ Highlight: ['new Highlight(new Range())'],
+ HighlightRegistry: ['CSS.highlights'],
+ });
+ }
+);
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/css-highlight-painting-underline-offset-001-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/css-highlight-painting-underline-offset-001-ref.html
new file mode 100644
index 0000000000..3d01bccf55
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/css-highlight-painting-underline-offset-001-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<title>CSS Highlight API Test: ::highlight with text-underline-offset, reference</title>
+<style>
+ #target {
+ text-decoration: wavy underline green 5px;
+ text-underline-offset: 20px;
+ }
+</style>
+<p id="target">The underline should be offset.</p>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/css-highlight-painting-underline-offset-001.html b/testing/web-platform/tests/css/css-highlight-api/painting/css-highlight-painting-underline-offset-001.html
new file mode 100644
index 0000000000..14b238ce17
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/css-highlight-painting-underline-offset-001.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<title>CSS Highlight API Test: ::highlight with text-underline-offset</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="css-highlight-painting-underline-offset-001-ref.html">
+<meta name="assert" content="Verify that text-underline-offset works in a ::highlight pseudo-element.">
+<style>
+ ::highlight(example) {
+ text-decoration: wavy underline green 5px;
+ text-underline-offset: 20px;
+ }
+</style>
+<p id="target">The underline should be offset.</p>
+<script>
+ let range = new Range();
+ range.setStart(target, 0);
+ range.setEnd(target, 1);
+ CSS.highlights.set(`example`, new Highlight(range));
+</script>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-001-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-001-ref.html
new file mode 100644
index 0000000000..b058789f6d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-001-ref.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<meta charset="utf-8">
+<style>
+ .highlighted {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span class="highlighted">One two </span><span>three…</span>
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-001.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-001.html
new file mode 100644
index 0000000000..82b61ec6de
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-001.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="::highlight overlay is painted">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span>One </span><span>two </span><span>three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 2);
+
+ CSS.highlights.set("example-highlight", new Highlight(r));
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-002-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-002-ref.html
new file mode 100644
index 0000000000..d063bbd497
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-002-ref.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<meta charset="utf-8">
+<style>
+ div {
+ color: red;
+ }
+</style>
+<body><div>abc</div>
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-002.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-002.html
new file mode 100644
index 0000000000..04b7dadbf8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-002.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-002-ref.html">
+<meta name="assert" value="Latest Highlight added to CSS.highlights has higher priority than the previous ones if there were no priorities explicitly set">
+<style>
+ div::highlight(bar) {
+ color: red;
+ }
+ div::highlight(foo) {
+ color: green;
+ }
+</style>
+<body><div>abc</div>
+<script>
+ let div = document.body.firstChild;
+ let r = new Range();
+ r.setStart(div, 0);
+ r.setEnd(div, 1);
+ let h = new Highlight(r);
+ CSS.highlights.set('foo', h);
+ CSS.highlights.set('bar', h);
+</script>
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-003-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-003-ref.html
new file mode 100644
index 0000000000..b2dccfa59f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-003-ref.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<meta charset="utf-8">
+<style>
+ span { background-color: rgba(0, 0, 255, 0.3); }
+</style>
+<body>L<span>orem I</span>psum. \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-003.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-003.html
new file mode 100644
index 0000000000..210f1a230f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-003.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-003-ref.html">
+<meta name="assert" value="Intersections of overlapping ranges contained in the same Highlight are painted only once">
+<style>
+ ::highlight(sample) { background-color: rgba(0, 0, 255, 0.3); }
+</style>
+<body>Lorem Ipsum.
+<script>
+ let textNode = document.body.firstChild;
+
+ let r1 = new Range();
+ r1.setStart(textNode, 1);
+ r1.setEnd(textNode, 5);
+
+ let r2 = new Range();
+ r2.setStart(textNode, 3);
+ r2.setEnd(textNode, 7);
+
+ CSS.highlights.set("sample", new Highlight(r1, r2));
+</script>
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-004-2-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-004-2-ref.html
new file mode 100644
index 0000000000..4ad1de63df
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-004-2-ref.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<meta charset="utf-8">
+<style>
+ .foo {
+ color:blue;
+ background-color:yellow;
+ }
+ .bar {
+ color:orange;
+ }
+ .bar-over-foo {
+ color:orange;
+ background-color:yellow;
+ }
+</style>
+<body><span class="foo">Som</span><span class="bar-over-foo">e t</span><span class="bar">ext</span> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-004-2.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-004-2.html
new file mode 100644
index 0000000000..0a612d66d1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-004-2.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-004-2-ref.html">
+<meta name="assert" value="When painting overlapping highlights with the same .priority, the one added last should be painted on top; and style properties not defined by the one on top (background-color in this case) should follow the rules of the next Highlight from top to bottom until there's one that overwrites default (or use default value otherwise).">
+<meta name="fuzzy" content="0-88;0-1">
+<style>
+ ::highlight(foo) {
+ color:blue;
+ background-color:yellow;
+ }
+ ::highlight(bar) {
+ color:orange;
+ }
+</style>
+<body>Some text
+<script>
+ let textNode = document.body.firstChild;
+
+ let r1 = new Range();
+ r1.setStart(textNode, 0);
+ r1.setEnd(textNode, 6);
+
+ let r2 = new Range();
+ r2.setStart(textNode, 3);
+ r2.setEnd(textNode, 9);
+
+ let h1 = new Highlight(r1);
+ let h2 = new Highlight(r2);
+
+ CSS.highlights.set("foo", h1);
+ CSS.highlights.set("bar", h2);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-004-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-004-ref.html
new file mode 100644
index 0000000000..8cb5b69d98
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-004-ref.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<meta charset="utf-8">
+<style>
+ .foo {
+ color:blue;
+ background-color:yellow;
+ }
+ .bar {
+ background-color:orange;
+ }
+ .bar-over-foo {
+ color:blue;
+ background-color:orange;
+ }
+</style>
+<body><span class="foo">Som</span><span class="bar-over-foo">e t</span><span class="bar">ext</span> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-004.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-004.html
new file mode 100644
index 0000000000..320617f8d1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-004.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-004-ref.html">
+<meta name="assert" value="When painting overlapping highlights with the same .priority, the one added last should be painted on top; and style properties not defined by the one on top (color in this case) should follow the rules of the next Highlight from top to bottom until there's one that overwrites default (or use default value otherwise).">
+<meta name="fuzzy" content="0-255;0-110">
+<style>
+ ::highlight(foo) {
+ color:blue;
+ background-color:yellow;
+ }
+ ::highlight(bar) {
+ background-color:orange;
+ }
+</style>
+<body>Some text
+<script>
+ let textNode = document.body.firstChild;
+
+ let r1 = new Range();
+ r1.setStart(textNode, 0);
+ r1.setEnd(textNode, 6);
+
+ let r2 = new Range();
+ r2.setStart(textNode, 3);
+ r2.setEnd(textNode, 9);
+
+ let h1 = new Highlight(r1);
+ let h2 = new Highlight(r2);
+
+ CSS.highlights.set("foo", h1);
+ CSS.highlights.set("bar", h2);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-005.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-005.html
new file mode 100644
index 0000000000..f9b728c9c5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-005.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="Highlight is repainted after modifying (setEnd()) a Range contained in it">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span>One </span><span>two </span><span>three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 1);
+ CSS.highlights.set("example-highlight", new Highlight(r));
+ r.setEnd(document.body, 2);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-006.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-006.html
new file mode 100644
index 0000000000..b4369dcacc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-006.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="Highlight is repainted after modifying (setStart()) a Range contained in it">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span>One </span><span>two </span><span>three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 1);
+ r.setEnd(document.body, 2);
+ CSS.highlights.set("example-highlight", new Highlight(r));
+ r.setStart(document.body, 0);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-007.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-007.html
new file mode 100644
index 0000000000..6cfdac2c7e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-007.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="Highlight is repainted after adding a Range to it after registering it in the HighlightRegistry">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span>One </span><span>two </span><span>three…</span>
+<script>
+ let r1 = new Range();
+ r1.setStart(document.body, 0);
+ r1.setEnd(document.body, 1);
+ let h = new Highlight(r1);
+ let r2 = new Range();
+ r2.setStart(document.body, 1);
+ r2.setEnd(document.body, 2);
+ CSS.highlights.set("example-highlight", h);
+ h.add(r2);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-008.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-008.html
new file mode 100644
index 0000000000..3da1d82ce3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-008.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="Highlight is repainted after deleting a Range from it after registering it in the HighlightRegistry">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span>One </span><span>two </span><span>three…</span>
+<script>
+ let r1 = new Range();
+ r1.setStart(document.body, 0);
+ r1.setEnd(document.body, 2);
+ let r2 = new Range();
+ r2.setStart(document.body, 1);
+ r2.setEnd(document.body, 3);
+ let h = new Highlight(r1, r2);
+ CSS.highlights.set("example-highlight", h);
+ h.delete(r2);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-009.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-009.html
new file mode 100644
index 0000000000..cee2394d62
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-009.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="Highlight is repainted correctly when collapsing a Range after registering a Highlight that contains it in the HighlightRegistry">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+ ::highlight(another-highlight) {
+ background-color: red;
+ color: orange;
+ }
+</style>
+<body><span>One </span><span>two </span><span>three…</span>
+<script>
+ let r1 = new Range();
+ r1.setStart(document.body, 0);
+ r1.setEnd(document.body, 2);
+ let r2 = new Range();
+ r2.setStart(document.body, 1);
+ r2.setEnd(document.body, 3);
+ let h1 = new Highlight(r1);
+ let h2 = new Highlight(r2);
+ CSS.highlights.set("example-highlight", h1);
+ CSS.highlights.set("another-highlight", h2);
+ r2.collapse();
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-010.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-010.html
new file mode 100644
index 0000000000..cdd2daf85c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-010.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="Highlight is repainted correctly after inserting a node in the middle of a Range contained in it">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span>two </span><span>three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 1);
+ CSS.highlights.set("example-highlight", new Highlight(r));
+ let newNode = document.createElement("span");
+ newNode.innerText = "One ";
+ document.body.insertBefore(newNode, document.body.firstChild);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-011.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-011.html
new file mode 100644
index 0000000000..5eef8508b6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-011.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="Highlight is repainted correctly after removing a node included in a Range contained in it">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span>One </span><span>two </span><span>two-point-five </span><span>three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 3);
+ CSS.highlights.set("example-highlight", new Highlight(r));
+ document.body.removeChild(document.body.children[2]);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-012.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-012.html
new file mode 100644
index 0000000000..cc8bb62e1e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-012.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="Highlight is repainted correctly after modifying the inner text of a node included in a Range contained in it">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span>Zero </span><span>two </span><span>three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 2);
+ CSS.highlights.set("example-highlight", new Highlight(r));
+ document.body.firstChild.innerText = "One ";
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-013.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-013.html
new file mode 100644
index 0000000000..021f1cb19f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-013.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="Highlight is repainted correctly after modifying text content of a node included in a Range contained in it">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span id="first">One </span><span id="second">two-point-five </span><span id="third">three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.querySelector("#first").firstChild, 0);
+ r.setEnd(document.querySelector("#third").firstChild, 0);
+ CSS.highlights.set("example-highlight", new Highlight(r));
+ document.querySelector("#second").firstChild.textContent = "two ";
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-014.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-014.html
new file mode 100644
index 0000000000..5313fe0954
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-014.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="Registering the same Highlight under different names and again with a used name works as it should.">
+<style>
+ ::highlight(foo) {
+ color: blue;
+ }
+ ::highlight(bar) {
+ background-color: yellow;
+ }
+</style>
+<body><span>One </span><span>two </span><span>three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 2);
+
+ let h = new Highlight(r);
+
+ CSS.highlights.set("foo", h);
+ CSS.highlights.set("bar", h);
+ CSS.highlights.set("foo", h);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-015.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-015.html
new file mode 100644
index 0000000000..62ce114dfa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-015.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="Unregistering only once a Highlight that was registered under different names works as it should and is still being painted.">
+<style>
+ ::highlight(foo) {
+ color: red;
+ }
+ ::highlight(bar) {
+ color: blue;
+ background-color: yellow;
+ }
+</style>
+<body><span>One </span><span>two </span><span>three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 2);
+
+ let h = new Highlight(r);
+
+ CSS.highlights.set("foo", h);
+ CSS.highlights.set("bar", h);
+ CSS.highlights.delete("foo");
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-016.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-016.html
new file mode 100644
index 0000000000..58b580e6b7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-016.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: Painting</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="Highlighted elements must be correctly painted and there should be no caching that doesn't take highlight names into account">
+<style>
+ #affected::highlight(foo) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span></span><span id="affected">One </span><span id="affected">two </span><span>three…</span>
+<script>
+ // The first <span> style resolution shouldn't cause caching an empty set of matched properties that could be used with the spans that should be highlighted later.
+ const node = document.body;
+ let r = new Range();
+ r.setStart(node, 1);
+ r.setEnd(node, 3);
+ CSS.highlights.set("foo", new Highlight(r));
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-017.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-017.html
new file mode 100644
index 0000000000..c3184a986a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-017.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>CSS Highlight API Test: ::highlight color with transparent originating color</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/#custom-highlight-pseudo">
+<link rel="help" href="https://crbug.com/1273943">
+<meta name="assert" content="This test checks that ::highlight pseudo-element uses the specified color even when the originating element text color was trasnparent.">
+<link rel="match" href="/css/reference/pass_if_pass_below.html">
+<style>
+ div {
+ color: transparent;
+ }
+ ::highlight(example-highlight) {
+ color: black;
+ }
+</style>
+
+<p>Test passes if there is the word "PASS" below.</p>
+<div id="target">PASS</div>
+
+<script>
+ let r = new Range();
+ r.setStart(target, 0);
+ r.setEnd(target, 1);
+
+ CSS.highlights.set("example-highlight", new Highlight(r));
+</script>
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-018.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-018.html
new file mode 100644
index 0000000000..95bef09bbe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-018.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: Range across contain boundary is painted</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="Highlight should be painted even though a Range that crosses a css-contain boundary is a part of it">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+ #target {
+ contain: paint;
+ }
+</style>
+<body><span>One </span><span id="target"><span>two </span><span>three…</span></span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.querySelector("#target"), 1);
+ CSS.highlights.set("example-highlight", new Highlight(r));
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-grammar-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-grammar-ref.html
new file mode 100644
index 0000000000..d660daf7c7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-grammar-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<style>
+ ::grammar-error {
+ background-color: lime;
+ color: green;
+ }
+</style>
+<span>Many thing can happen.</span> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-grammar.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-grammar.html
new file mode 100644
index 0000000000..93d2560040
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-grammar.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-below-grammar-ref.html">
+<meta name="assert" value="Highlight overlay is painted below all other pseudo overlays (comparing only to grammar suffices since it's the one immediately above ::highlight, assuming ::grammar-error is painted in the correct order)">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+ ::grammar-error {
+ background-color: lime;
+ color: green;
+ }
+</style>
+<!--
+ The grammar mistakes in the text below are intentional and part of this test.
+
+ https://html.spec.whatwg.org/multipage/interaction.html#spelling-and-grammar-checking
+ • contenteditable makes the text “checkable for the purposes of [spelling and grammar checking]”
+ • spellcheck tries to enable spelling and grammar checking (subject to user preferences)
+ • lang tries to guide the UA towards checking the text in English (but the UA may ignore this)
+-->
+<span contenteditable="true" spellcheck="true" lang="en">Many thing can happen.</div>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 1);
+ CSS.highlights.set("example-highlight", new Highlight(r));
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-selection-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-selection-ref.html
new file mode 100644
index 0000000000..5c7bd9361b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-selection-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<style>
+ #highlighted {
+ background: cyan;
+ color: blue;
+ }
+ ::selection {
+ background: blue;
+ color: cyan;
+ }
+</style>
+<body><span id="highlighted">Text should be blue over cyan here and <span id="selected">cyan over blue here</span>.</span>
+<script>
+ getSelection().setBaseAndExtent(selected, 0, selected, 1);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-selection.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-selection.html
new file mode 100644
index 0000000000..cd5ad36a69
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-selection.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-below-selection-ref.html">
+<meta name="assert" value="Highlight overlay is painted below selection overlay">
+<style>
+ ::highlight(foo) {
+ background: cyan;
+ color: blue;
+ }
+ ::selection {
+ background: blue;
+ color: cyan;
+ }
+</style>
+<body>Text should be blue over cyan here and <span id="selected">cyan over blue here</span>.
+<script>
+ let highlightRange = new Range();
+ highlightRange.setStart(document.body.firstChild, 0);
+ highlightRange.setEnd(document.body.lastChild, 0);
+ CSS.highlights.set("foo", new Highlight(highlightRange));
+ getSelection().setBaseAndExtent(selected, 0, selected, 1);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-target-text-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-target-text-ref.html
new file mode 100644
index 0000000000..70d6926364
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-target-text-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<style>
+ #highlight {
+ background-color: yellow;
+ color: limegreen;
+ }
+ #highlight-and-target-text {
+ background-color: orange;
+ color: limegreen;
+ }
+ #target-text {
+ background-color: orange;
+ }
+</style>
+<span id="highlight">Some </span><span id="highlight-and-target-text">te</span><span id="target-text">xt</span> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-target-text.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-target-text.html
new file mode 100644
index 0000000000..e55ce783de
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-below-target-text.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-below-target-text-ref.html">
+<meta name="assert" value="Style properties defined in a ::highlight shouldn't be overriden by default values if there's another pseudo overlay painted on top of it (::target-text in this case) which doesn't specify a value for that property (color in this case)">
+<style>
+ ::highlight(foo) {
+ color:limegreen;
+ background-color:yellow;
+ }
+ ::target-text {
+ background-color:orange;
+ }
+</style>
+<body>Some text
+<script>
+ let r = new Range();
+ r.setStart(document.body.firstChild, 0);
+ r.setEnd(document.body.firstChild, 7);
+ CSS.highlights.set("foo", new Highlight(r));
+ window.location.href = `custom-highlight-painting-below-target-text.html#:~:text=text`;
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-001-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-001-ref.html
new file mode 100644
index 0000000000..aa8915c1d7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-001-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<body>
+<iframe
+ id="iframe"
+ srcdoc="
+ <style>
+ span {
+ color: blue;
+ background-color: cyan;
+ }
+ </style>
+ <span id='span-iframe'>abc</span>
+ "
+ >
+</iframe> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-001.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-001.html
new file mode 100644
index 0000000000..240c112c5d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-001.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-iframe-001-ref.html">
+<meta name="assert" value="Registered Highlights inside an iframe are correctly painted.">
+<body>
+<iframe
+ id="iframe"
+ src="resources/iframe-code.html"
+ >
+</iframe> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-002.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-002.html
new file mode 100644
index 0000000000..388457f9cb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-002.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-iframe-001-ref.html">
+<meta name="assert" value="Creating a Highlight in the root Document and registering it in an iframe's CSS.highlights is painted correctly.">
+<body>
+ <iframe
+ id="iframe"
+ srcdoc="
+ <style>
+ ::highlight(foo) {
+ color: blue;
+ background-color: cyan;
+ }
+ </style>
+ <span id='span-iframe'>abc</span>
+ "
+ >
+</iframe>
+<script>
+ let iframe = document.querySelector("#iframe");
+ iframe.onload = () => {
+ let spanIframe = iframe.contentDocument.querySelector("#span-iframe");
+ let rangeIframe = new Range();
+ rangeIframe.setStart(spanIframe, 0);
+ rangeIframe.setEnd(spanIframe, 1);
+
+ let h = new Highlight();
+ h.add(rangeIframe);
+ iframe.contentWindow.CSS.highlights.set("foo", h);
+ }
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-003-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-003-ref.html
new file mode 100644
index 0000000000..9d80a9f005
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-003-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<style>
+ #span-doc {
+ color: green;
+ background-color: greenyellow;
+ }
+</style>
+<body>
+<iframe
+ id="iframe"
+ srcdoc="
+ <style>
+ span {
+ color: blue;
+ background-color: cyan;
+ }
+ </style>
+ <span id='span-iframe'>abc</span>
+ "
+ >
+</iframe>
+<br>
+<span id="span-doc">abc</span> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-003.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-003.html
new file mode 100644
index 0000000000..8614d35ed6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-003.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-iframe-003-ref.html">
+<meta name="assert" value="Creating a Highlight in the root Document with a Range in the root document and another one in an iframe is correctly painted when added to both CSS.highlights (root document's and iframe's).">
+<style>
+ ::highlight(foo) {
+ color: green;
+ background-color: greenyellow;
+ }
+</style>
+<body>
+ <iframe
+ id="iframe"
+ srcdoc="
+ <style>
+ ::highlight(foo) {
+ color: blue;
+ background-color: cyan;
+ }
+ </style>
+ <span id='span-iframe'>abc</span>
+ "
+ >
+</iframe>
+<br>
+<span id="span-doc">abc</span>
+<script>
+ let spanDoc = document.querySelector("#span-doc");
+ let rangeDoc = new Range();
+ rangeDoc.setStart(spanDoc, 0);
+ rangeDoc.setEnd(spanDoc, 1);
+
+ let iframe = document.querySelector("#iframe");
+ iframe.onload = () => {
+ let spanIframe = iframe.contentDocument.querySelector("#span-iframe");
+ let rangeIframe = new Range();
+ rangeIframe.setStart(spanIframe, 0);
+ rangeIframe.setEnd(spanIframe, 1);
+
+ let h = new Highlight(rangeDoc, rangeIframe);
+ iframe.contentWindow.CSS.highlights.set("foo", h);
+ CSS.highlights.set("foo", h);
+ }
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-004-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-004-ref.html
new file mode 100644
index 0000000000..622ea40c80
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-004-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<style>
+ #span-doc {
+ color: green;
+ background-color: greenyellow;
+ }
+</style>
+<body>
+<iframe
+ id="iframe"
+ srcdoc="<span id='span-iframe'>abc</span>"
+ >
+</iframe>
+<br>
+<span id="span-doc">abc</span> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-004.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-004.html
new file mode 100644
index 0000000000..d13d75a561
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-004.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-iframe-004-ref.html">
+<meta name="assert" value="Creating a Highlight in the root Document with a Range in the root document and another one in an iframe is correctly painted when added to the root document's CSS.highlights (only root document's range is painted).">
+<style>
+ ::highlight(foo) {
+ color: green;
+ background-color: greenyellow;
+ }
+</style>
+<body>
+ <iframe
+ id="iframe"
+ srcdoc="
+ <style>
+ ::highlight(foo) {
+ color: blue;
+ background-color: cyan;
+ }
+ </style>
+ <span id='span-iframe'>abc</span>
+ "
+ >
+</iframe>
+<br>
+<span id="span-doc">abc</span>
+<script>
+ let spanDoc = document.querySelector("#span-doc");
+ let rangeDoc = new Range();
+ rangeDoc.setStart(spanDoc, 0);
+ rangeDoc.setEnd(spanDoc, 1);
+
+ let iframe = document.querySelector("#iframe");
+ iframe.onload = () => {
+ let spanIframe = iframe.contentDocument.querySelector("#span-iframe");
+ let rangeIframe = new Range();
+ rangeIframe.setStart(spanIframe, 0);
+ rangeIframe.setEnd(spanIframe, 1);
+
+ let h = new Highlight(rangeDoc, rangeIframe);
+ CSS.highlights.set("foo", h);
+ }
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-005-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-005-ref.html
new file mode 100644
index 0000000000..7a492e32c0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-005-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<body>
+<iframe
+ id="iframe"
+ srcdoc="
+ <style>
+ span {
+ color: blue;
+ background-color: cyan;
+ }
+ </style>
+ <span id='span-iframe'>abc</span>
+ "
+ >
+</iframe>
+<br>
+<span id="span-doc">abc</span> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-005.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-005.html
new file mode 100644
index 0000000000..d31590c639
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-005.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-iframe-005-ref.html">
+<meta name="assert" value="Creating a Highlight in the root Document with a Range in the root document and another one in an iframe is correctly painted when added to the iframe's CSS.highlights (only the iframe's range is painted).">
+<style>
+ ::highlight(foo) {
+ color: green;
+ background-color: greenyellow;
+ }
+</style>
+<body>
+ <iframe
+ id="iframe"
+ srcdoc="
+ <style>
+ ::highlight(foo) {
+ color: blue;
+ background-color: cyan;
+ }
+ </style>
+ <span id='span-iframe'>abc</span>
+ "
+ >
+</iframe>
+<br>
+<span id="span-doc">abc</span>
+<script>
+ let spanDoc = document.querySelector("#span-doc");
+ let rangeDoc = new Range();
+ rangeDoc.setStart(spanDoc, 0);
+ rangeDoc.setEnd(spanDoc, 1);
+
+ let iframe = document.querySelector("#iframe");
+ iframe.onload = () => {
+ let spanIframe = iframe.contentDocument.querySelector("#span-iframe");
+ let rangeIframe = new Range();
+ rangeIframe.setStart(spanIframe, 0);
+ rangeIframe.setEnd(spanIframe, 1);
+
+ let h = new Highlight(rangeDoc, rangeIframe);
+ iframe.contentWindow.CSS.highlights.set("foo", h);
+ }
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-006-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-006-ref.html
new file mode 100644
index 0000000000..f5a871d0fe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-006-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<body>
+<iframe
+ id="iframe"
+ srcdoc="<span id='span-iframe'>abc</span>"
+ >
+</iframe>
+<br>
+<span id="span-doc">abc</span> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-006.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-006.html
new file mode 100644
index 0000000000..2b1e88e659
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-006.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-iframe-006-ref.html">
+<meta name="assert" value="Ranges contained in a registered Highlight that are moved to another document different than the owner of the HighlightRegistry where the Highlight has been registered should not be painted anymore.">
+<script src="resources/run-after-layout-and-paint.js"></script>
+<style>
+ ::highlight(foo) {
+ color: green;
+ background-color: greenyellow;
+ }
+</style>
+<body>
+ <iframe
+ id="iframe"
+ srcdoc="
+ <style>
+ ::highlight(foo) {
+ color: blue;
+ background-color: cyan;
+ }
+ </style>
+ <span id='span-iframe'>abc</span>
+ "
+ >
+</iframe>
+<br>
+<span id="span-doc">abc</span>
+<script>
+ let spanDoc = document.querySelector("#span-doc");
+ let r = new Range();
+ r.setStart(spanDoc, 0);
+ r.setEnd(spanDoc, 1);
+
+ let h = new Highlight(r);
+ CSS.highlights.set("foo", h);
+
+ let iframe = document.querySelector("#iframe");
+ iframe.onload = () => {
+ let spanIframe = iframe.contentDocument.querySelector("#span-iframe");
+ runAfterLayoutAndPaint(()=>{
+ r.setStart(spanIframe, 0);
+ r.setEnd(spanIframe, 1);
+ document.documentElement.removeAttribute("class");
+ });
+ }
+</script>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-001-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-001-ref.html
new file mode 100644
index 0000000000..0d5385287c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-001-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<style>
+ span {
+ background-color: green;
+ }
+</style>
+<body>
+<div>There should be only one green rectangle below from [ to ]:</div>
+<div>[<span>&nbsp;&nbsp;&nbsp;<strong>&nbsp;&nbsp;&nbsp;</strong>&nbsp;&nbsp;&nbsp;</span>]</div> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-001.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-001.html
new file mode 100644
index 0000000000..eb5e5e1181
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-001.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: Inheritance</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-inheritance-001-ref.html">
+<meta name="assert" value="Highlighted elements inherit style properties from their parent if they're not set">
+<style>
+ div::highlight(div-highlight) {
+ background-color: green;
+ color: red;
+ }
+ span::highlight(span-highlight) {
+ color: blue;
+ }
+</style>
+<body>
+<div>There should be only one green rectangle below from [ to ]:</div>
+<div id="target">[<span>&nbsp;&nbsp;&nbsp;<strong>&nbsp;&nbsp;&nbsp;</strong>&nbsp;&nbsp;&nbsp;</span>]</div>
+<script>
+ let r = new Range();
+ const node = document.getElementById("target");
+ r.setStart(node, 1);
+ r.setEnd(node, 2);
+
+ CSS.highlights.set("div-highlight", new Highlight(r));
+ CSS.highlights.set("span-highlight", new Highlight(r));
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-002.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-002.html
new file mode 100644
index 0000000000..fbed69392c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-002.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: Inheritance</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-inheritance-001-ref.html">
+<meta name="assert" value="Highlighted elements inherit style properties from their parent even if there's not a ::highlight selector directly applying to them or their parent.">
+<style>
+ div::highlight(div-highlight) {
+ background-color: green;
+ }
+</style>
+<body>
+<div>There should be only one green rectangle below from [ to ]:</div>
+<div id="target">[<span>&nbsp;&nbsp;&nbsp;<strong>&nbsp;&nbsp;&nbsp;</strong>&nbsp;&nbsp;&nbsp;</span>]</div>
+<script>
+ const node = document.getElementById("target");
+ let r = new Range();
+ r.setStart(node, 1);
+ r.setEnd(node, 2);
+ CSS.highlights.set("div-highlight", new Highlight(r));
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-003-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-003-ref.html
new file mode 100644
index 0000000000..cdab7615e4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-003-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<style>
+ div {
+ color: #00000080;
+ }
+</style>
+<body>
+<div>foobar</div>
+</body>
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-003.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-003.html
new file mode 100644
index 0000000000..e449ebf334
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-003.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: Inheritance</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-inheritance-003-ref.html">
+<meta name="assert" value="Unstyled highlights should not be visible">
+<style>
+ div {
+ color: #00000080;
+ background-color: red;
+ width: 0;
+ }
+</style>
+<body>
+<div id="target">foobar</div>
+<script>
+ const node = document.getElementById("target");
+ let r = new Range();
+ r.setStart(node.firstChild, 0);
+ r.setEnd(node.firstChild, 3);
+ CSS.highlights.set("div-highlight", new Highlight(r));
+</script>
+</body> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-001.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-001.html
new file mode 100644
index 0000000000..aef391ec0f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-001.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="::highlight overlay is correctly invalidated and repainted">
+<script src="resources/run-after-layout-and-paint.js"></script>
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span>One </span><span>two </span><span>three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 2);
+
+ // Force frame paint before registering the Highlight.
+ runAfterLayoutAndPaint(()=>{
+ CSS.highlights.set("example-highlight", new Highlight(r));
+ document.documentElement.removeAttribute("class");
+ });
+</script>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-002.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-002.html
new file mode 100644
index 0000000000..99271ff7a0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-002.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-staticrange-001-ref.html">
+<meta name="assert" value="::highlight overlay is correctly invalidated and repainted after deletion">
+<script src="resources/run-after-layout-and-paint.js"></script>
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span>One </span><span>two </span><span>three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 2);
+ CSS.highlights.set("example-highlight", new Highlight(r));
+
+ // Force frame paint before deleting the Highlight.
+ runAfterLayoutAndPaint(()=>{
+ CSS.highlights.delete("example-highlight");
+ document.documentElement.removeAttribute("class");
+ });
+</script>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-003.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-003.html
new file mode 100644
index 0000000000..d1f8722388
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-003.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="::highlight overlay is correctly invalidated and repainted after modifying its range">
+<script src="resources/run-after-layout-and-paint.js"></script>
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span>One </span><span>two </span><span>three…</span>
+<script>
+ let r = new Range();
+ CSS.highlights.set("example-highlight", new Highlight(r));
+
+ // Force frame paint before modifying the Highlight's range.
+ runAfterLayoutAndPaint(()=>{
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 2);
+ document.documentElement.removeAttribute("class");
+ });
+</script>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-004.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-004.html
new file mode 100644
index 0000000000..62f05a84ab
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-004.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="::highlight overlay is correctly invalidated and repainted after adding a range to it">
+<script src="resources/run-after-layout-and-paint.js"></script>
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span>One </span><span>two </span><span>three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 2);
+ let h = new Highlight();
+ CSS.highlights.set("example-highlight", h);
+
+ // Force frame paint before modifying the Highlight.
+ runAfterLayoutAndPaint(()=>{
+ h.add(r);
+ document.documentElement.removeAttribute("class");
+ });
+</script>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-005.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-005.html
new file mode 100644
index 0000000000..cabc4c3b9c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-005.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="::highlight overlay is correctly invalidated and repainted after modifying its priority">
+<script src="resources/run-after-layout-and-paint.js"></script>
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+ ::highlight(another-highlight) {
+ background-color: red;
+ color: orange;
+ }
+</style>
+<body><span>One </span><span>two </span><span>three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 2);
+ let h1 = new Highlight(r);
+ let h2 = new Highlight(r);
+ h1.priority = 1;
+ h2.priority = 2;
+ CSS.highlights.set("example-highlight", h1);
+ CSS.highlights.set("another-highlight", h2);
+
+ // Force frame paint before modifying the Highlight.
+ runAfterLayoutAndPaint(()=>{
+ h1.priority = 3;
+ document.documentElement.removeAttribute("class");
+ });
+</script>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-006.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-006.html
new file mode 100644
index 0000000000..81c2298e13
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-006.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="::highlight overlay is correctly invalidated and repainted after inserting a new node inside one of its ranges">
+<script src="resources/run-after-layout-and-paint.js"></script>
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span>two </span><span>three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 1);
+ CSS.highlights.set("example-highlight", new Highlight(r));
+ let newNode = document.createElement("span");
+ newNode.innerText = "One ";
+
+ // Force frame paint before inserting a new node.
+ runAfterLayoutAndPaint(()=>{
+ document.body.insertBefore(newNode, document.body.firstChild);
+ document.documentElement.removeAttribute("class");
+ });
+</script>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-007-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-007-ref.html
new file mode 100644
index 0000000000..88f3d0f3d6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-007-ref.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<meta charset="utf-8">
+<style>
+ .highlighted {
+ background: blue;
+ }
+</style>
+<body>
+ <span class="highlighted">Hello</span>
+</body>
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-007.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-007.html
new file mode 100644
index 0000000000..f23a869728
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-007.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: CSS Rule change</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-invalidation-007-ref.html">
+<meta name="assert" value="::highlight overlay is correctly invalidated and repainted after CSS rule is changed">
+<script src="resources/run-after-layout-and-paint.js"></script>
+<style>
+ span::highlight(example-highlight) {
+ background: yellow;
+ }
+
+ .blue::highlight(example-highlight) {
+ background: blue;
+ }
+</style>
+<body>
+ <span>Hello</span>
+<script>
+ const range = new Range();
+ const span = document.querySelector("span");
+ range.setStart(span, 0);
+ range.setEnd(span, 1);
+ CSS.highlights.set("example-highlight", new Highlight(range));
+
+ // Force frame paint before changing style
+ runAfterLayoutAndPaint(() => {
+ span.className = "blue";
+ document.documentElement.removeAttribute("class");
+ });
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-overlapping-highlights-001-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-overlapping-highlights-001-ref.html
new file mode 100644
index 0000000000..3c08ad55ae
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-overlapping-highlights-001-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<style>
+ body {
+ font-size: 3em;
+ font-weight: bolder;
+
+ }
+ #affected1 {
+ color: red;
+ }
+ #affected2 {
+ color: green;
+ }
+</style>
+<body><span id="affected1">This should have 'highlight1' style (red).</span><span id="affected2">This should have 'highlight2' style (green).</span> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-overlapping-highlights-001.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-overlapping-highlights-001.html
new file mode 100644
index 0000000000..0b380574bc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-overlapping-highlights-001.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: Overlapping Highlights</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-overlapping-highlights-001-ref.html">
+<meta name="assert" value="UAs must not define any styles for custom highlight pseudo-elements in the default UA stylesheet.">
+<style>
+ body {
+ font-size: 3em;
+ font-weight: bolder;
+ }
+ #affected1::highlight(highlight1) {
+ color: red;
+ }
+ #affected2::highlight(highlight2) {
+ color: green;
+ }
+</style>
+<body><span id="affected1">This should have 'highlight1' style (red).</span><span id="affected2">This should have 'highlight2' style (green).</span>
+<script>
+ /*
+ This test is meant to verify that:
+ - UAs must not define any styles for custom highlight pseudo-elements in
+ the default UA stylesheet.
+ - UAs do not paint unstyled custom highlights.
+
+ In this test, highlight2 has higher priority because it was registered
+ later, so it is painted over highlight1. This includes painting for
+ span#affected1, where there is no CSS rule for highlight2. But since unstyled
+ custom highlights are not painted, span#affected1 is still painted with the
+ styles for highlight1.
+
+ See https://drafts.csswg.org/css-highlight-api-1/#default-styles
+ */
+
+ const node = document.body;
+ let r = new Range();
+ r.setStart(node, 0);
+ r.setEnd(node, 2);
+
+ CSS.highlights.set("highlight1", new Highlight(r));
+ CSS.highlights.set("highlight2", new Highlight(r));
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-overlapping-highlights-002-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-overlapping-highlights-002-ref.html
new file mode 100644
index 0000000000..2907681b75
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-overlapping-highlights-002-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<style>
+ div {
+ font-size: 3em;
+ font-weight: bolder;
+ }
+ #affected1 {
+ color: green;
+ background-color: rgb(0, 255, 0, 0.5);
+ }
+ #affected2 {
+ color: red;
+ background-color: rgba(100, 0, 100, 0.5);
+ }
+</style>
+<body><div><span id="affected1">Green on lime.</span><span id="affected2">Red on maroon.</span></div> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-overlapping-highlights-002.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-overlapping-highlights-002.html
new file mode 100644
index 0000000000..2dda273abf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-overlapping-highlights-002.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: Overlapping Highlights</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-overlapping-highlights-002-ref.html">
+<meta name="assert" value="UAs must not define any styles for custom highlight pseudo-elements in the default UA stylesheet.">
+<style>
+ div {
+ font-size: 3em;
+ font-weight: bolder;
+ }
+ #affected1::highlight(highlight1) {
+ color: green;
+ background-color: rgb(0, 255, 0, 0.5);
+ }
+ #affected2::highlight(highlight2) {
+ color: red;
+ background-color: rgba(100, 0, 100, 0.5);
+ }
+</style>
+<body><div><span id="affected1">Green on lime.</span><span id="affected2">Red on maroon.</span></div>
+<script>
+ /*
+ This test is meant to verify that:
+ - UAs must not define any styles for custom highlight pseudo-elements in
+ the default UA stylesheet.
+ - UAs do not paint unstyled custom highlights.
+
+ In this test, highlight1 has higher priority, so it is painted over
+ highlight2. This includes painting for span#affected2, where there is no CSS
+ rule for highlight1. But since unstyled custom highlights are not painted,
+ span#affected2 is still painted with the styles for highlight2.
+
+ See https://drafts.csswg.org/css-highlight-api-1/#default-styles
+ */
+
+ const div = document.querySelector("div");
+
+ let r = new Range();
+ r.setStart(div, 0);
+ r.setEnd(div, 2);
+ let r2 = new Range();
+ r2.setStart(div, 0);
+ r2.setEnd(div, 2);
+
+ let h = new Highlight(r);
+ h.priority = 3;
+ let h2 = new Highlight(r2);
+ h2.priority = 2;
+
+ CSS.highlights.set("highlight1", h);
+ CSS.highlights.set("highlight2", h2);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-prioritization-001.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-prioritization-001.html
new file mode 100644
index 0000000000..cc2a53be54
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-prioritization-001.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="Highlights are prioritized correctly by changing their .priority (higher priority is painted on top no matter the order of insertion into the HighlightRegistry)">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+ ::highlight(another-highlight) {
+ background-color: red;
+ color: orange;
+ }
+</style>
+<body><span>One </span><span>two </span><span>three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 2);
+ let h1 = new Highlight(r);
+ let h2 = new Highlight(r);
+ h1.priority = 2;
+ h2.priority = 1;
+ CSS.highlights.set("example-highlight", h1);
+ CSS.highlights.set("another-highlight", h2);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-prioritization-002.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-prioritization-002.html
new file mode 100644
index 0000000000..756368a8e6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-prioritization-002.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="Highlights are repainted correctly when changing their priority after adding them to the HighlightRegistry">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+ ::highlight(another-highlight) {
+ background-color: red;
+ color: orange;
+ }
+</style>
+<body><span>One </span><span>two </span><span>three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 2);
+ let h1 = new Highlight(r);
+ let h2 = new Highlight(r);
+ CSS.highlights.set("example-highlight", h1);
+ CSS.highlights.set("another-highlight", h2);
+ h1.priority = 1;
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-001-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-001-ref.html
new file mode 100644
index 0000000000..a89d86dc81
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-001-ref.html
@@ -0,0 +1,3 @@
+<!doctype html>
+<meta charset="utf-8">
+<body><span>One two three…</span>
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-001.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-001.html
new file mode 100644
index 0000000000..ee81bb89d7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-001.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: Invalid StaticRanges are not painted</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-staticrange-001-ref.html">
+<meta name="assert" value="StaticRanges that are invalid or collapsed should not be painted when they're in a Highlight">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span id="first">One </span><span id="second">two </span><span id="third">three…</span>
+<script>
+ let h = new Highlight();
+ h.add(new StaticRange({startContainer: document.body, startOffset: 0, endContainer: document.body, endOffset: 0}));
+ h.add(new StaticRange({startContainer: document.body, startOffset: 1, endContainer: document.body, endOffset: 0}));
+ h.add(new StaticRange({startContainer: document.body, startOffset: 1, endContainer: document.body, endOffset: 100}));
+ h.add(new StaticRange({startContainer: document, startOffset: 0, endContainer: document, endOffset: 1}));
+ h.add(new StaticRange({startContainer: document.querySelector("#third").firstChild, startOffset: 1, endContainer: document.querySelector("#first").firstChild, endOffset: 2}));
+ CSS.highlights.set("example-highlight", h);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-002.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-002.html
new file mode 100644
index 0000000000..43a0b06c35
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-002.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: StaticRange across contain boundary is painted</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="A StaticRange crossing a contain boundary should be painted">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+ #contained {
+ contain: paint;
+ }
+</style>
+<body><span>One <span id="contained">two </span>three…</span>
+<script>
+ let h = new Highlight();
+ h.add(new StaticRange({startContainer: document.body.firstChild.childNodes[0], startOffset: 0, endContainer: document.body.firstChild.childNodes[1], endOffset: 1}));
+ CSS.highlights.set("example-highlight", h);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-003.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-003.html
new file mode 100644
index 0000000000..11de279fd6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-003.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: </title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="Highlight is repainted correctly after removing a node included in a StaticRange contained in it (StaticRange not modified)">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ }
+</style>
+<body><span>One </span><span>one-point-five </span><span>two </span><span>three…</span>
+<script>
+ let r = new StaticRange({startContainer: document.body, startOffset: 0, endContainer: document.body, endOffset: 2});
+ CSS.highlights.set("example-highlight", new Highlight(r));
+ document.body.removeChild(document.body.children[1]);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-001-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-001-ref.html
new file mode 100644
index 0000000000..568e5f9321
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-001-ref.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Highlight API Test: Reference ::highlight painting text-decoration</title>
+<style>
+ div {
+ float: left;
+ margin: 0.5em;
+ /* Setting transparent color is a workaround to avoid hitting the following Chromium bug: https://crbug.com/1179938.
+ This could be removed once that bug is fixed. */
+ color: transparent;
+ }
+</style>
+<p>The test passes if it matches the reference file.</p>
+<script>
+ let textDecorationStyles = [
+ "solid green underline", "double green underline", "dotted green underline", "dashed green underline", "wavy green underline",
+ "solid blue overline", "double blue overline", "dotted blue overline", "dashed blue overline", "wavy blue overline",
+ "solid magenta line-through", "double magenta line-through", "dotted magenta line-through", "dashed magenta line-through", "wavy magenta line-through",
+ "solid brown underline overline line-through", "double brown underline overline line-through", "dotted brown underline overline line-through", "dashed brown underline overline line-through", "wavy brown underline overline line-through",
+ ];
+
+ textDecorationStyles.forEach((textDecorationStyle, index) => {
+ document.styleSheets[0].insertRule(`#id${index} { text-decoration: ${textDecorationStyle}; }`);
+ let element = document.createElement("div");
+ element.id = `id${index}`;
+ element.innerHTML = textDecorationStyle;
+ document.body.appendChild(element);
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-001.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-001.html
new file mode 100644
index 0000000000..72201e6e78
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-001.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Highlight API Test: ::highlight painting text-decoration</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-text-decoration-001-ref.html">
+<meta name="assert" content="This test checks that ::highlight pseudo-element paints text-decorations defined by it.">
+<meta name="fuzzy" content="0-255;0-27">
+<style>
+ div {
+ float: left;
+ margin: 0.5em;
+ /* Setting transparent color is a workaround to avoid hitting the following Chromium bug: https://crbug.com/1179938.
+ This could be removed once that bug is fixed. */
+ color: transparent;
+ }
+</style>
+<p>The test passes if it matches the reference file.</p>
+<script>
+ let textDecorationStyles = [
+ "solid green underline", "double green underline", "dotted green underline", "dashed green underline", "wavy green underline",
+ "solid blue overline", "double blue overline", "dotted blue overline", "dashed blue overline", "wavy blue overline",
+ "solid magenta line-through", "double magenta line-through", "dotted magenta line-through", "dashed magenta line-through", "wavy magenta line-through",
+ "solid brown underline overline line-through", "double brown underline overline line-through", "dotted brown underline overline line-through", "dashed brown underline overline line-through", "wavy brown underline overline line-through",
+ ];
+
+ textDecorationStyles.forEach((textDecorationStyle, index) => {
+ document.styleSheets[0].insertRule(`::highlight(h${index}) { text-decoration: ${textDecorationStyle}; }`);
+ let element = document.createElement("div");
+ element.innerHTML = textDecorationStyle;
+ document.body.appendChild(element);
+ let range = new Range();
+ range.setStart(element, 0);
+ range.setEnd(element, 1);
+ CSS.highlights.set(`h${index}`, new Highlight(range));
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-dynamic-001-ref.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-dynamic-001-ref.html
new file mode 100644
index 0000000000..3a713aa844
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-dynamic-001-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Highlight API Test: Reference ::highlight dynamic change text-decoration</title>
+<style>
+ ::highlight(example) {
+ text-decoration: solid underline green;
+ }
+</style>
+<p>The test passes if it line below has a green underline.</p>
+<div id="target">target</div>
+<script>
+ let range = new Range();
+ range.setStart(target, 0);
+ range.setEnd(target, 1);
+ CSS.highlights.set(`example`, new Highlight(range));
+</script>
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-dynamic-001.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-dynamic-001.html
new file mode 100644
index 0000000000..050c7c77ce
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-dynamic-001.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>CSS Highlight API Test: ::highlight dynamic change text-decoration</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-text-decoration-dynamic-001-ref.html">
+<meta name="assert" content="This test checks that it's possible to modify dynamically the text-decoration of a custom highlight through ::highlight pseudo-element.">
+<script src="/common/reftest-wait.js"></script>
+<style>
+ ::highlight(example) {
+ text-decoration: solid underline red;
+ }
+</style>
+<p>The test passes if it line below has a green underline.</p>
+<div id="target">target</div>
+<script>
+ let range = new Range();
+ range.setStart(target, 0);
+ range.setEnd(target, 1);
+ CSS.highlights.set(`example`, new Highlight(range));
+
+ requestAnimationFrame(() => requestAnimationFrame(() => {
+ document.styleSheets[0].cssRules[0].style.textDecorationColor = "green";
+ takeScreenshot();
+ }));
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-shadow.tentative.html b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-shadow.tentative.html
new file mode 100644
index 0000000000..b0952dfb9b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/custom-highlight-painting-text-shadow.tentative.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Highlight API Test: text-decoration</title>
+<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/">
+<link rel="match" href="custom-highlight-painting-001-ref.html">
+<meta name="assert" value="::highlight overlay does not paint text-shadow">
+<style>
+ ::highlight(example-highlight) {
+ background-color: yellow;
+ color: blue;
+ text-shadow: 1px 2px rgba(255, 0, 0, 0.5);
+ }
+</style>
+<body><span>One </span><span>two </span><span>three…</span>
+<script>
+ let r = new Range();
+ r.setStart(document.body, 0);
+ r.setEnd(document.body, 2);
+
+ CSS.highlights.set("example-highlight", new Highlight(r));
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/resources/iframe-code.html b/testing/web-platform/tests/css/css-highlight-api/painting/resources/iframe-code.html
new file mode 100644
index 0000000000..a4a1829be2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/resources/iframe-code.html
@@ -0,0 +1,13 @@
+<style>
+ ::highlight(foo) {
+ color: blue;
+ background-color: cyan;
+ }
+</style>
+<span id='span-iframe'>abc</span>
+<script>
+ let r = new Range();
+ r.setStart(document.querySelector('#span-iframe'), 0);
+ r.setEnd(document.querySelector('#span-iframe'), 1);
+ CSS.highlights.set('foo', new Highlight(r));
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-highlight-api/painting/resources/run-after-layout-and-paint.js b/testing/web-platform/tests/css/css-highlight-api/painting/resources/run-after-layout-and-paint.js
new file mode 100644
index 0000000000..75d3e279a4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-highlight-api/painting/resources/run-after-layout-and-paint.js
@@ -0,0 +1,11 @@
+// This is inspired in runAfterLayoutAndPaint() from
+// third_party/blink/web_tests/resources/run-after-layout-and-paint.js.
+function runAfterLayoutAndPaint(callback) {
+ // See http://crrev.com/c/1395193/10/third_party/blink/web_tests/http/tests/resources/run-after-layout-and-paint.js
+ // for more discussions.
+ requestAnimationFrame(function() {
+ requestAnimationFrame(function() {
+ callback();
+ });
+ });
+} \ No newline at end of file