Browse Source

LibWeb: Assert that nodes share shadow-including root in BP calculation

Previously, it was assumed that nodes must share the same root, prior
to the calculation of their relative boundary point positions. This is
no longer the case, since `Selection.setBaseAndExtent()` now accepts
anchor and focus nodes that may be in different shadow trees.
Tim Ledbetter 8 tháng trước cách đây
mục cha
commit
163b8a69e3

+ 3 - 1
Libraries/LibWeb/DOM/Range.cpp

@@ -120,7 +120,9 @@ GC::Ref<Node> Range::root() const
 RelativeBoundaryPointPosition position_of_boundary_point_relative_to_other_boundary_point(GC::Ref<Node> node_a, u32 offset_a, GC::Ref<Node> node_b, u32 offset_b)
 {
     // 1. Assert: nodeA and nodeB have the same root.
-    VERIFY(&node_a->root() == &node_b->root());
+    //    NOTE: Nodes may not share the same root if they belong to different shadow trees,
+    //          so we assert that they share the same shadow-including root instead.
+    VERIFY(&node_a->shadow_including_root() == &node_b->shadow_including_root());
 
     // 2. If nodeA is nodeB, then return equal if offsetA is offsetB, before if offsetA is less than offsetB, and after if offsetA is greater than offsetB.
     if (node_a == node_b) {

+ 13 - 0
Tests/LibWeb/Text/expected/wpt-import/selection/shadow-dom/tentative/Selection-direction.txt

@@ -0,0 +1,13 @@
+Harness status: OK
+
+Found 7 tests
+
+6 Pass
+1 Fail
+Pass	direction returns "none" when there is no selection
+Pass	direction returns "forward" when there is a forward-direction selection in the document tree
+Pass	direction returns "backward" when there is a backward-direction selection in the document tree
+Pass	direction returns "forward" when there is a forward selection in the shadow tree
+Pass	direction returns "backward" when there is a backward selection in the shadow tree
+Pass	direction returns "forward" when there is a forward selection that crosses shadow boundaries
+Fail	direction returns "backward" when there is a forward selection that crosses shadow boundaries

+ 66 - 0
Tests/LibWeb/Text/input/wpt-import/selection/shadow-dom/tentative/Selection-direction.html

@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html>
+<body>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="Selection's direction should return none, forwad, or backward">
+<link rel="help" href="https://w3c.github.io/selection-api/#dom-selection-direction">
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-actions.js"></script>
+<script src='../../../resources/testdriver-vendor.js'></script>
+<div id="container"></div>
+<script>
+
+test(() => {
+    getSelection().removeAllRanges();
+    assert_equals(getSelection().direction, 'none');
+}, 'direction returns "none" when there is no selection');
+
+test(() => {
+    container.innerHTML = 'hello, world';
+    getSelection().setBaseAndExtent(container.firstChild, 0, container.firstChild, 5);
+    assert_equals(getSelection().direction, 'forward');
+}, 'direction returns "forward" when there is a forward-direction selection in the document tree');
+
+test(() => {
+    container.innerHTML = 'hello, world';
+    getSelection().setBaseAndExtent(container.firstChild, 4, container.firstChild, 3);
+    assert_equals(getSelection().direction, 'backward');
+}, 'direction returns "backward" when there is a backward-direction selection in the document tree');
+
+test(() => {
+    container.innerHTML = 'a<div id="host"></div>b';
+    const shadowRoot = host.attachShadow({mode: 'closed'});
+    shadowRoot.innerHTML = 'hello, world';
+    getSelection().setBaseAndExtent(shadowRoot.firstChild, 0, shadowRoot.firstChild, 5);
+    assert_equals(getSelection().direction, 'forward');
+}, 'direction returns "forward" when there is a forward selection in the shadow tree');
+
+test(() => {
+    container.innerHTML = 'a<div id="host"></div>b';
+    const shadowRoot = host.attachShadow({mode: 'closed'});
+    shadowRoot.innerHTML = 'hello, world';
+    getSelection().setBaseAndExtent(shadowRoot.firstChild, 5, shadowRoot.firstChild, 3);
+    assert_equals(getSelection().direction, 'backward');
+}, 'direction returns "backward" when there is a backward selection in the shadow tree');
+
+test(() => {
+    container.innerHTML = 'a<div id="host"></div>b';
+    const shadowRoot = host.attachShadow({mode: 'closed'});
+    shadowRoot.innerHTML = 'hello, world';
+    getSelection().setBaseAndExtent(shadowRoot.firstChild, 7, container, 2);
+    assert_equals(getSelection().direction, 'forward');
+}, 'direction returns "forward" when there is a forward selection that crosses shadow boundaries');
+
+test(() => {
+    container.innerHTML = 'a<div id="host"></div>b';
+    const shadowRoot = host.attachShadow({mode: 'closed'});
+    shadowRoot.innerHTML = 'hello, world';
+    getSelection().setBaseAndExtent(shadowRoot.firstChild, 7, container, 1);
+    assert_equals(getSelection().direction, 'backward');
+}, 'direction returns "backward" when there is a forward selection that crosses shadow boundaries');
+
+</script>
+</body>
+</html>