When a selected node in nested ShadowDOM is deleted, selection have wrong range.
authorshinyak@chromium.org <shinyak@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 Jan 2013 04:44:20 +0000 (04:44 +0000)
committershinyak@chromium.org <shinyak@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 Jan 2013 04:44:20 +0000 (04:44 +0000)
https://bugs.webkit.org/show_bug.cgi?id=106526

Reviewed by Ryosuke Niwa.

Source/WebCore:

Since FrameSelection and htmlediting did not consider nested Shadow DOM, the FrameSelection still selects
removed elements if selected nodes in nested Shadow DOM are removed.

We have to use containsIncludingShadowDOM to handle with nested Shadow DOM correctly.

Test: fast/dom/shadow/selection-in-nested-shadow.html

* editing/FrameSelection.cpp:
(WebCore::removingNodeRemovesPosition):
* editing/htmlediting.cpp:
(WebCore::updatePositionForNodeRemoval):

LayoutTests:

* fast/dom/shadow/selection-in-nested-shadow-expected.txt: Added.
* fast/dom/shadow/selection-in-nested-shadow.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@139401 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/dom/shadow/selection-in-nested-shadow-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/shadow/selection-in-nested-shadow.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/editing/FrameSelection.cpp
Source/WebCore/editing/htmlediting.cpp

index 7b82938..5d1b60a 100644 (file)
@@ -1,3 +1,13 @@
+2013-01-10  Shinya Kawanaka  <shinyak@chromium.org>
+
+        When a selected node in nested ShadowDOM is deleted, selection have wrong range.
+        https://bugs.webkit.org/show_bug.cgi?id=106526
+
+        Reviewed by Ryosuke Niwa.
+
+        * fast/dom/shadow/selection-in-nested-shadow-expected.txt: Added.
+        * fast/dom/shadow/selection-in-nested-shadow.html: Added.
+
 2013-01-10  James Robinson  <jamesr@chromium.org>
 
         [chromium] Store scrollable layer's contents size for coordinated scrollable layers
diff --git a/LayoutTests/fast/dom/shadow/selection-in-nested-shadow-expected.txt b/LayoutTests/fast/dom/shadow/selection-in-nested-shadow-expected.txt
new file mode 100644 (file)
index 0000000..f4cba20
--- /dev/null
@@ -0,0 +1,12 @@
+Select text in non-nested ShadowDOM and remove an element containing shadow host.
+Then the anchor node of the selection should become be the parent element of the removed element (container).
+PASS window.getSelection().anchorNode is container
+
+Select text in nested ShadowDOM and remove an element containing shadow host.
+In this case, the anchor node of the selection should also become be the parent element of the removed element (container).
+PASS window.getSelection().anchorNode is container
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/dom/shadow/selection-in-nested-shadow.html b/LayoutTests/fast/dom/shadow/selection-in-nested-shadow.html
new file mode 100644 (file)
index 0000000..d91e33e
--- /dev/null
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/resources/js-test-pre.js"></script>
+<script src="polyfill.js"></script>
+</head>
+<body>
+
+<div id="container">
+    <div id="container1"><div id="host1"></div></div>
+    <div id="container2"><div id="host2"></div></div>
+</div>
+<pre id="console"></pre>
+
+<script>
+var shadowRoot1 = host1.webkitCreateShadowRoot();
+shadowRoot1.innerHTML = '<div id="target1">Element in Shadow DOM</div>';
+
+var shadowRoot2 = host2.webkitCreateShadowRoot();
+var host3 = document.createElement('div');
+var shadowRoot3 = host3.webkitCreateShadowRoot();
+shadowRoot2.appendChild(host3);
+shadowRoot3.innerHTML = '<div id="target2">Element in nested Shadow DOM</div>';
+
+var target1 = shadowRoot1.getElementById('target1');
+var target2 = shadowRoot3.getElementById('target2');
+
+// non-nested ShadowDOM case.
+debug('Select text in non-nested ShadowDOM and remove an element containing shadow host.');
+debug('Then the anchor node of the selection should become be the parent element of the removed element (container).');
+eventSender.mouseMoveTo(target1.offsetLeft + 2, target1.offsetTop + target1.offsetHeight / 2);
+eventSender.mouseDown();
+eventSender.mouseMoveTo(target1.offsetLeft + target1.offsetWidth - 2, target1.offsetTop + target1.offsetHeight / 2);
+eventSender.mouseUp();
+container.removeChild(container1);
+shouldBe('window.getSelection().anchorNode', 'container');
+debug('');
+
+// nested ShadowDOM case.
+debug('Select text in nested ShadowDOM and remove an element containing shadow host.');
+debug('In this case, the anchor node of the selection should also become be the parent element of the removed element (container).');
+eventSender.mouseMoveTo(target2.offsetLeft + 2, target2.offsetTop + target2.offsetHeight / 2);
+eventSender.mouseDown();
+eventSender.mouseMoveTo(target2.offsetLeft + target2.offsetWidth - 2, target2.offsetTop + target2.offsetHeight / 2);
+eventSender.mouseUp();
+container.removeChild(container2);
+shouldBe('window.getSelection().anchorNode', 'container');
+debug('');
+</script>
+
+<script src="../../js/resources/js-test-post.js"></script>
+</body>
+
+</html>
index 42beddb..9c52348 100644 (file)
@@ -1,3 +1,22 @@
+2013-01-10  Shinya Kawanaka  <shinyak@chromium.org>
+
+        When a selected node in nested ShadowDOM is deleted, selection have wrong range.
+        https://bugs.webkit.org/show_bug.cgi?id=106526
+
+        Reviewed by Ryosuke Niwa.
+
+        Since FrameSelection and htmlediting did not consider nested Shadow DOM, the FrameSelection still selects
+        removed elements if selected nodes in nested Shadow DOM are removed.
+
+        We have to use containsIncludingShadowDOM to handle with nested Shadow DOM correctly.
+
+        Test: fast/dom/shadow/selection-in-nested-shadow.html
+
+        * editing/FrameSelection.cpp:
+        (WebCore::removingNodeRemovesPosition):
+        * editing/htmlediting.cpp:
+        (WebCore::updatePositionForNodeRemoval):
+
 2013-01-10  Hajime Morrita  <morrita@google.com>
 
         [Shadow DOM] Refactoring: InsertionPoint could simplify its subclass hooks
index d751886..09bbb23 100644 (file)
@@ -338,7 +338,7 @@ static bool removingNodeRemovesPosition(Node* node, const Position& position)
         return false;
 
     Element* element = static_cast<Element*>(node);
-    return element->contains(position.anchorNode()) || element->contains(position.anchorNode()->shadowAncestorNode());
+    return element->containsIncludingShadowDOM(position.anchorNode());
 }
 
 static void clearRenderViewSelection(const Position& position)
index c3b5ef3..96ef863 100644 (file)
@@ -994,15 +994,15 @@ void updatePositionForNodeRemoval(Position& position, Node* node)
     case Position::PositionIsOffsetInAnchor:
         if (position.containerNode() == node->parentNode() && static_cast<unsigned>(position.offsetInContainerNode()) > node->nodeIndex())
             position.moveToOffset(position.offsetInContainerNode() - 1);
-        else if (node->contains(position.containerNode()) || node->contains(position.containerNode()->shadowAncestorNode()))
+        else if (node->containsIncludingShadowDOM(position.containerNode()))
             position = positionInParentBeforeNode(node);
         break;
     case Position::PositionIsAfterAnchor:
-        if (node->contains(position.anchorNode()) || node->contains(position.anchorNode()->shadowAncestorNode()))
+        if (node->containsIncludingShadowDOM(position.anchorNode()))
             position = positionInParentAfterNode(node);
         break;
     case Position::PositionIsBeforeAnchor:
-        if (node->contains(position.anchorNode()) || node->contains(position.anchorNode()->shadowAncestorNode()))
+        if (node->containsIncludingShadowDOM(position.anchorNode()))
             position = positionInParentBeforeNode(node);
         break;
     }