Diff
Modified: trunk/LayoutTests/ChangeLog (195280 => 195281)
--- trunk/LayoutTests/ChangeLog 2016-01-19 10:13:55 UTC (rev 195280)
+++ trunk/LayoutTests/ChangeLog 2016-01-19 10:47:11 UTC (rev 195281)
@@ -1,5 +1,17 @@
2016-01-19 Ryosuke Niwa <[email protected]>
+ Text::splitText doesn't update Range end points anchored on parent nodes
+ https://bugs.webkit.org/show_bug.cgi?id=153227
+
+ Reviewed by Antti Koivisto.
+
+ Added a regression test since the rebaselined W3C test is incomprehensible.
+
+ * fast/dom/Range/update-range-in-split-text-expected.txt: Added.
+ * fast/dom/Range/update-range-in-split-text.html: Added.
+
+2016-01-19 Ryosuke Niwa <[email protected]>
+
innerHTML should always add a mutation record for removing all children
https://bugs.webkit.org/show_bug.cgi?id=148782
<rdar://problem/22571962>
Added: trunk/LayoutTests/fast/dom/Range/update-range-in-split-text-expected.txt (0 => 195281)
--- trunk/LayoutTests/fast/dom/Range/update-range-in-split-text-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/dom/Range/update-range-in-split-text-expected.txt 2016-01-19 10:47:11 UTC (rev 195281)
@@ -0,0 +1,40 @@
+
+text = createTextWithParent(); range = createRange(text.parentNode, 0, text.parentNode, 0); text.splitText(0)
+PASS range.startContainer is text.parentNode
+PASS range.startOffset is 0
+PASS range.endContainer is text.parentNode
+PASS range.endOffset is 0
+
+text = createTextWithParent(); range = createRange(text.parentNode, 1, text.parentNode, 1); text.splitText(0)
+PASS range.startContainer is text.parentNode
+PASS range.startOffset is 2
+PASS range.endContainer is text.parentNode
+PASS range.endOffset is 2
+
+text = createTextWithParent(); range = createRange(text.parentNode, 0, text.parentNode, 1); text.splitText(0)
+PASS range.startContainer is text.parentNode
+PASS range.startOffset is 0
+PASS range.endContainer is text.parentNode
+PASS range.endOffset is 2
+
+text = createTextWithParentAndSiblings(); range = createRange(text.parentNode, 1, text.parentNode, 1); text.splitText(0)
+PASS range.startContainer is text.parentNode
+PASS range.startOffset is 1
+PASS range.endContainer is text.parentNode
+PASS range.endOffset is 1
+
+text = createTextWithParentAndSiblings(); range = createRange(text.parentNode, 2, text.parentNode, 2); text.splitText(0)
+PASS range.startContainer is text.parentNode
+PASS range.startOffset is 3
+PASS range.endContainer is text.parentNode
+PASS range.endOffset is 3
+
+text = createTextWithParentAndSiblings(); range = createRange(text.parentNode, 1, text.parentNode, 2); text.splitText(0)
+PASS range.startContainer is text.parentNode
+PASS range.startOffset is 1
+PASS range.endContainer is text.parentNode
+PASS range.endOffset is 3
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/dom/Range/update-range-in-split-text.html (0 => 195281)
--- trunk/LayoutTests/fast/dom/Range/update-range-in-split-text.html (rev 0)
+++ trunk/LayoutTests/fast/dom/Range/update-range-in-split-text.html 2016-01-19 10:47:11 UTC (rev 195281)
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<body>
+<script src=""
+<div id="container" style="display: none;"></div>
+<script>
+
+function createTextWithParent()
+{
+ var container = document.getElementById('container');
+
+ var element = document.createElement('div');
+ element.textContent = 'hello';
+ container.appendChild(element);
+
+ return element.firstChild;
+}
+
+function createTextWithParentAndSiblings()
+{
+ var container = document.getElementById('container');
+
+ var element = document.createElement('div');
+ element.textContent = 'hello';
+ container.appendChild(element);
+
+ var sibling = document.createElement('b');
+ element.insertBefore(sibling, element.firstChild);
+
+ var sibling = document.createElement('i');
+ element.appendChild(sibling);
+
+ return element.childNodes[1];
+}
+
+function createRange(startContainer, startOffset, endContainer, endOffset) {
+ var range = document.createRange();
+ range.setStart(startContainer, startOffset);
+ range.setEnd(endContainer, endOffset);
+ return range;
+}
+
+debug('');
+evalAndLog('text = createTextWithParent(); range = createRange(text.parentNode, 0, text.parentNode, 0); text.splitText(0)');
+shouldBe('range.startContainer', 'text.parentNode');
+shouldBe('range.startOffset', '0');
+shouldBe('range.endContainer', 'text.parentNode');
+shouldBe('range.endOffset', '0');
+
+debug('');
+evalAndLog('text = createTextWithParent(); range = createRange(text.parentNode, 1, text.parentNode, 1); text.splitText(0)');
+shouldBe('range.startContainer', 'text.parentNode');
+shouldBe('range.startOffset', '2');
+shouldBe('range.endContainer', 'text.parentNode');
+shouldBe('range.endOffset', '2');
+
+debug('');
+evalAndLog('text = createTextWithParent(); range = createRange(text.parentNode, 0, text.parentNode, 1); text.splitText(0)');
+shouldBe('range.startContainer', 'text.parentNode');
+shouldBe('range.startOffset', '0');
+shouldBe('range.endContainer', 'text.parentNode');
+shouldBe('range.endOffset', '2');
+
+debug('');
+evalAndLog('text = createTextWithParentAndSiblings(); range = createRange(text.parentNode, 1, text.parentNode, 1); text.splitText(0)');
+shouldBe('range.startContainer', 'text.parentNode');
+shouldBe('range.startOffset', '1');
+shouldBe('range.endContainer', 'text.parentNode');
+shouldBe('range.endOffset', '1');
+
+debug('');
+evalAndLog('text = createTextWithParentAndSiblings(); range = createRange(text.parentNode, 2, text.parentNode, 2); text.splitText(0)');
+shouldBe('range.startContainer', 'text.parentNode');
+shouldBe('range.startOffset', '3');
+shouldBe('range.endContainer', 'text.parentNode');
+shouldBe('range.endOffset', '3');
+
+debug('');
+evalAndLog('text = createTextWithParentAndSiblings(); range = createRange(text.parentNode, 1, text.parentNode, 2); text.splitText(0)');
+shouldBe('range.startContainer', 'text.parentNode');
+shouldBe('range.startOffset', '1');
+shouldBe('range.endContainer', 'text.parentNode');
+shouldBe('range.endOffset', '3');
+
+</script>
+<script src=""
+</body>
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (195280 => 195281)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2016-01-19 10:13:55 UTC (rev 195280)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2016-01-19 10:47:11 UTC (rev 195281)
@@ -1,5 +1,16 @@
2016-01-19 Ryosuke Niwa <[email protected]>
+ Text::splitText doesn't update Range end points anchored on parent nodes
+ https://bugs.webkit.org/show_bug.cgi?id=153227
+
+ Reviewed by Antti Koivisto.
+
+ Rebaseline the test now that we're passing more test cases.
+
+ * web-platform-tests/dom/ranges/Range-mutations-expected.txt:
+
+2016-01-19 Ryosuke Niwa <[email protected]>
+
innerHTML should always add a mutation record for removing all children
https://bugs.webkit.org/show_bug.cgi?id=148782
<rdar://problem/22571962>
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/dom/ranges/Range-mutations-expected.txt (195280 => 195281)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/dom/ranges/Range-mutations-expected.txt 2016-01-19 10:13:55 UTC (rev 195280)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/dom/ranges/Range-mutations-expected.txt 2016-01-19 10:47:11 UTC (rev 195281)
@@ -99,18 +99,18 @@
FAIL detachedXmlTextNode.splitText(3), with selected range on detachedXmlTextNode from 1 to 3 assert_equals: Sanity check: selection must have exactly one range after adding the range expected 1 but got 0
PASS paras[0].firstChild.splitText(1), with unselected range collapsed at (paras[0], 0)
FAIL paras[0].firstChild.splitText(1), with selected range collapsed at (paras[0], 0) assert_equals: Sanity check: selection's range must initially be the same as the range we added expected object "" but got object ""
-FAIL paras[0].firstChild.splitText(1), with unselected range on paras[0] from 0 to 1 assert_equals: Wrong end offset expected 2 but got 1
+PASS paras[0].firstChild.splitText(1), with unselected range on paras[0] from 0 to 1
FAIL paras[0].firstChild.splitText(1), with selected range on paras[0] from 0 to 1 assert_equals: Sanity check: selection's range must initially be the same as the range we added expected object "Äb̈c̈d̈ëf̈g̈ḧ
" but got object "Äb̈c̈d̈ëf̈g̈ḧ"
-FAIL paras[0].firstChild.splitText(1), with unselected range collapsed at (paras[0], 1) assert_equals: Wrong start offset expected 2 but got 1
+PASS paras[0].firstChild.splitText(1), with unselected range collapsed at (paras[0], 1)
FAIL paras[0].firstChild.splitText(1), with selected range collapsed at (paras[0], 1) assert_equals: Sanity check: selection's range must initially be the same as the range we added expected object "" but got object ""
-FAIL paras[0].firstChild.splitText(1), with unselected range from (paras[0].firstChild, 1) to (paras[0], 1) assert_equals: Wrong end offset expected 2 but got 1
+PASS paras[0].firstChild.splitText(1), with unselected range from (paras[0].firstChild, 1) to (paras[0], 1)
FAIL paras[0].firstChild.splitText(1), with selected range from (paras[0].firstChild, 1) to (paras[0], 1) assert_equals: Sanity check: selection's range must initially be the same as the range we added expected object "̈b̈c̈d̈ëf̈g̈ḧ
" but got object "b̈c̈d̈ëf̈g̈ḧ"
-FAIL paras[0].firstChild.splitText(2), with unselected range from (paras[0].firstChild, 1) to (paras[0], 1) assert_equals: Wrong end offset expected 2 but got 1
+PASS paras[0].firstChild.splitText(2), with unselected range from (paras[0].firstChild, 1) to (paras[0], 1)
FAIL paras[0].firstChild.splitText(2), with selected range from (paras[0].firstChild, 1) to (paras[0], 1) assert_equals: Sanity check: selection's range must initially be the same as the range we added expected object "̈b̈c̈d̈ëf̈g̈ḧ
" but got object "b̈c̈d̈ëf̈g̈ḧ"
-FAIL paras[0].firstChild.splitText(3), with unselected range from (paras[0].firstChild, 1) to (paras[0], 1) assert_equals: Wrong end offset expected 2 but got 1
+PASS paras[0].firstChild.splitText(3), with unselected range from (paras[0].firstChild, 1) to (paras[0], 1)
FAIL paras[0].firstChild.splitText(3), with selected range from (paras[0].firstChild, 1) to (paras[0], 1) assert_equals: Sanity check: selection's range must initially be the same as the range we added expected object "̈b̈c̈d̈ëf̈g̈ḧ
" but got object "b̈c̈d̈ëf̈g̈ḧ"
PASS paras[0].firstChild.splitText(1), with unselected range from (paras[0], 0) to (paras[0].firstChild, 3)
Modified: trunk/Source/WebCore/ChangeLog (195280 => 195281)
--- trunk/Source/WebCore/ChangeLog 2016-01-19 10:13:55 UTC (rev 195280)
+++ trunk/Source/WebCore/ChangeLog 2016-01-19 10:47:11 UTC (rev 195281)
@@ -1,5 +1,36 @@
2016-01-19 Ryosuke Niwa <[email protected]>
+ Text::splitText doesn't update Range end points anchored on parent nodes
+ https://bugs.webkit.org/show_bug.cgi?id=153227
+
+ Reviewed by Antti Koivisto.
+
+ When a Text node is split into two and there is a Range whose boundary points' container node
+ is its parent and offset appears after the Text node, we must update the boundary points as specified
+ in step 7 of the concept "split" a Text node at https://dom.spec.whatwg.org/#concept-text-split
+
+ 1. Insert new node into parent before node’s next sibling.
+ 2. For each range whose start node is node and start offset is greater than offset, set its start node
+ to new node and decrease its start offset by offset.
+ 3. For each range whose end node is node and end offset is greater than offset, set its end node to
+ new node and decrease its end offset by offset.
+ 4. For each range whose start node is parent and start offset is equal to the index of node + 1,
+ increase its start offset by one.
+ 5. For each range whose end node is parent and end offset is equal to the index of node + 1, increase
+ its end offset by one.
+
+ Fixed the bug by implementing steps 4 and 5 in boundaryTextNodesSplit. New behavior matches the DOM spec
+ as well as the behavior of Firefox.
+
+ Test: fast/dom/Range/update-range-in-split-text.html
+
+ * dom/Range.cpp:
+ (WebCore::boundaryTextNodesSplit): See above.
+ * dom/RangeBoundaryPoint.h:
+ (WebCore::RangeBoundaryPoint::setToAfterChild): Added.
+
+2016-01-19 Ryosuke Niwa <[email protected]>
+
CharacterData::setData doesn't need ExceptionCode as an out argument
https://bugs.webkit.org/show_bug.cgi?id=153225
Modified: trunk/Source/WebCore/dom/Range.cpp (195280 => 195281)
--- trunk/Source/WebCore/dom/Range.cpp 2016-01-19 10:13:55 UTC (rev 195280)
+++ trunk/Source/WebCore/dom/Range.cpp 2016-01-19 10:47:11 UTC (rev 195281)
@@ -1712,12 +1712,19 @@
static inline void boundaryTextNodesSplit(RangeBoundaryPoint& boundary, Text* oldNode)
{
- if (boundary.container() != oldNode)
+ if (boundary.container() == oldNode) {
+ unsigned splitOffset = oldNode->length();
+ unsigned boundaryOffset = boundary.offset();
+ if (boundaryOffset > splitOffset)
+ boundary.set(oldNode->nextSibling(), boundaryOffset - splitOffset, 0);
return;
- unsigned boundaryOffset = boundary.offset();
- if (boundaryOffset <= oldNode->length())
- return;
- boundary.set(oldNode->nextSibling(), boundaryOffset - oldNode->length(), 0);
+ }
+ auto* parent = oldNode->parentNode();
+ if (boundary.container() == parent && boundary.childBefore() == oldNode) {
+ auto* newChild = oldNode->nextSibling();
+ ASSERT(newChild);
+ boundary.setToAfterChild(*newChild);
+ }
}
void Range::textNodeSplit(Text* oldNode)
Modified: trunk/Source/WebCore/dom/RangeBoundaryPoint.h (195280 => 195281)
--- trunk/Source/WebCore/dom/RangeBoundaryPoint.h 2016-01-19 10:13:55 UTC (rev 195280)
+++ trunk/Source/WebCore/dom/RangeBoundaryPoint.h 2016-01-19 10:47:11 UTC (rev 195281)
@@ -49,6 +49,7 @@
void setOffset(int offset);
void setToBeforeChild(Node&);
+ void setToAfterChild(Node&);
void setToStartOfNode(PassRefPtr<Node>);
void setToEndOfNode(PassRefPtr<Node>);
@@ -142,6 +143,14 @@
m_offsetInContainer = m_childBeforeBoundary ? invalidOffset : 0;
}
+inline void RangeBoundaryPoint::setToAfterChild(Node& child)
+{
+ ASSERT(child.parentNode());
+ m_childBeforeBoundary = &child;
+ m_containerNode = child.parentNode();
+ m_offsetInContainer = m_childBeforeBoundary ? invalidOffset : 0;
+}
+
inline void RangeBoundaryPoint::setToStartOfNode(PassRefPtr<Node> container)
{
ASSERT(container);