Skip to content

Commit 34624b5

Browse files
mrobinsonservo-wpt-sync
authored andcommitted
script: Align live range update steps with specification
This change reworks the live range update steps that show up in various places in the specification so that they match what the specification says. Now updates to live ranges uses the existing `set_start` and `set_end` APIs which simplify the code greatly as they already handle updating the `Node`'s live range list. This is preparation work for adding a new live-ish range type for selections (which will have a few different requirements than a real DOM live range). Improvements to spec compliance of `Node#normalize()`: - Instead of issuing one mutation event per merged node during only issue a single one. - The change to the preserved node's data happens before the merged nodes' removal. - Indices for live range updates would be stale when merging more than two nodes. Notes on performance: - This switches to accessing a rooted `SmallVec` of live ranges per-node. In cases where a node has 4 or fewer live ranges, this will not allocate, otherwise this adds a new vector allocation for an edge case. - The amount of rooting should be unchanged as the old code had to root all accessed `Range`'s anyway. - In some cases we avoid calculating node indices where they were before using `LazyCell`. Signed-off-by: Martin Robinson <mrobinson@igalia.com>
1 parent e68a4b9 commit 34624b5

1 file changed

Lines changed: 87 additions & 0 deletions

File tree

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<!doctype html>
2+
<title>Range mutation tests - normalize</title>
3+
<link rel="help" href="https://dom.spec.whatwg.org/#dom-node-normalize">;
4+
<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
5+
<div id=log></div>
6+
<script src="/resources/testharness.js"></script>
7+
<script src="/resources/testharnessreport.js"></script>
8+
9+
<script>
10+
function createTestNode(t) {
11+
// Create a node with adjacent 4 text children.
12+
const parentNode = document.createElement("div");
13+
parentNode.append(document.createElement("span"), "A", "BB", "CCC", "DDDD", document.createElement("span"));
14+
document.body.append(parentNode);
15+
t.add_cleanup(() => parentNode.remove());
16+
return parentNode;
17+
}
18+
19+
function normalizeTestNode(testNode) {
20+
testNode.normalize();
21+
assert_equals(testNode.childNodes.length, 3);
22+
assert_equals(testNode.childNodes[1].data, "ABBCCCDDDD");
23+
}
24+
25+
test(t => {
26+
let testNode = createTestNode(t);
27+
let range = document.createRange();
28+
range.setStart(testNode.childNodes[1], 0);
29+
range.setEnd(testNode.childNodes[4], 4);
30+
normalizeTestNode(testNode);
31+
assert_equals(range.startContainer, testNode.childNodes[1]);
32+
assert_equals(range.startOffset, 0);
33+
assert_equals(range.endContainer, testNode.childNodes[1]);
34+
assert_equals(range.endOffset, 10);
35+
}, "Live range updates properly when its boundaries span multiple merged text nodes");
36+
37+
test(t => {
38+
let testNode = createTestNode(t);
39+
let range = document.createRange();
40+
range.setStart(testNode.childNodes[3], 2);
41+
range.setEnd(testNode.childNodes[3], 2);
42+
43+
normalizeTestNode(testNode);
44+
45+
assert_equals(range.startContainer, testNode.childNodes[1]);
46+
assert_equals(range.startOffset, 5);
47+
assert_equals(range.endContainer, testNode.childNodes[1]);
48+
assert_equals(range.endOffset, 5);
49+
}, "Live range updates properly when collapsed into single merged text node in range of multiple")
50+
51+
test(t => {
52+
let testNode = createTestNode(t);
53+
let range = document.createRange();
54+
range.setStart(testNode, 3);
55+
range.setEnd(testNode, 4);
56+
57+
normalizeTestNode(testNode);
58+
59+
assert_equals(range.startContainer, testNode.childNodes[1]);
60+
assert_equals(range.startOffset, 3);
61+
assert_equals(range.endContainer, testNode.childNodes[1]);
62+
assert_equals(range.endOffset, 6);
63+
}, "Live range updates properly when its boundaries are initially indices to merged nodes")
64+
65+
test(t => {
66+
let testNode = createTestNode(t);
67+
let range1 = document.createRange();
68+
let range2 = document.createRange();
69+
70+
range1.setStart(testNode, 0);
71+
range1.setEnd(testNode, 0);
72+
range2.setStart(testNode, 5);
73+
range2.setEnd(testNode, 5);
74+
75+
normalizeTestNode(testNode);
76+
77+
assert_equals(range1.startContainer, testNode);
78+
assert_equals(range1.startOffset, 0);
79+
assert_equals(range1.endContainer, testNode);
80+
assert_equals(range1.endOffset, 0);
81+
82+
assert_equals(range2.startContainer, testNode);
83+
assert_equals(range2.startOffset, 2);
84+
assert_equals(range2.endContainer, testNode);
85+
assert_equals(range2.endOffset, 2);
86+
}, "Live range updates properly when text nodes merged before and after them")
87+
</script>

0 commit comments

Comments
 (0)