Commit 8fd47d1c authored by yosin@chromium.org's avatar yosin@chromium.org

Update owner document of Range objects if start/end boundary points in different document

This patch updates owner document of Range objects when orphan Node object moved
to another document in new member function |Range::updateOwnerDocumentIfNeeded|.

Note: when we move non-null parent Node object to another document, it is done
by removeChild and appendChild and Range objects to reset to start of document.

The root cause of issue 350362 is boundary points of Range objects isn't
adjusted when owner document of Range and boundary points are different.

Because |Range::nodeChildrenChanged|, which adjusts boundary points for
|Node.appendChild|, is called for Range objects in another document which
isn't owner of Range.

This patch also updates "move-detached-child-in-range.html" to have right
value.

BUG=350362
TEST=LayoutTests/fast/dom/Range/range-extract-contents-after-move-to-another-document-crash.html
TEST=LayoutTests/fast/dom/move-detached-child-in-range.html

Review URL: https://codereview.chromium.org/332173003

git-svn-id: svn://svn.chromium.org/blink/trunk@176410 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent a85a541e
<!DOCTYPE html>
<html>
<head>
<script>
if (window.testRunner)
testRunner.dumpAsText();
onload = function() {
var target = document.getElementById('target');
var child1 = document.getElementById('c1');
var child2 = document.getElementById('c2');
var child3 = document.getElementById('c3');
document.body.removeChild(target);
var range = document.createRange();
range.selectNode(child2)
target.removeChild(child3);
var anotherDocument = document.implementation.createDocument('', null);
anotherDocument.appendChild(target);
target.appendChild(child1);
range.extractContents();
document.body.textContent = 'PASS if Blink doesn\'t crash.';
};
</script>
</head>
<body>
<span id="target">
<b id="c1"></b><div id="c2"></div><input id="c3">
</span>
</body>
</html>
Final end container, offset: [object HTMLHeadingElement], 1
Final end container, offset: [object HTMLHeadingElement], 0
......@@ -3768,6 +3768,17 @@ void Document::updateRangesAfterChildrenChanged(ContainerNode* container)
}
}
void Document::updateRangesAfterNodeMovedToAnotherDocument(const Node& node)
{
ASSERT(node.document() != this);
if (m_ranges.isEmpty())
return;
AttachedRangeSet ranges = m_ranges;
AttachedRangeSet::const_iterator end = ranges.end();
for (AttachedRangeSet::const_iterator it = ranges.begin(); it != end; ++it)
(*it)->updateOwnerDocumentIfNeeded();
}
void Document::nodeChildrenWillBeRemoved(ContainerNode& container)
{
NoEventDispatchAssertion assertNoEventDispatch;
......
......@@ -679,6 +679,7 @@ public:
void detachRange(Range*);
void updateRangesAfterChildrenChanged(ContainerNode*);
void updateRangesAfterNodeMovedToAnotherDocument(const Node&);
// nodeChildrenWillBeRemoved is used when removing all node children at once.
void nodeChildrenWillBeRemoved(ContainerNode&);
// nodeWillBeRemoved is only safe when removing one node at a time.
......
......@@ -1939,7 +1939,7 @@ void Node::didMoveToNewDocument(Document& oldDocument)
}
oldDocument.markers().removeMarkers(this);
oldDocument.updateRangesAfterNodeMovedToAnotherDocument(*this);
if (const TouchEventTargetSet* touchHandlers = oldDocument.touchEventTargets()) {
while (touchHandlers->contains(this)) {
......
......@@ -1544,6 +1544,19 @@ void Range::didMergeTextNodes(const NodeWithIndex& oldNode, unsigned offset)
boundaryTextNodesMerged(m_end, oldNode, offset);
}
void Range::updateOwnerDocumentIfNeeded()
{
ASSERT(m_start.container());
ASSERT(m_end.container());
Document& newDocument = m_start.container()->document();
ASSERT(newDocument == m_end.container()->document());
if (newDocument == m_ownerDocument)
return;
m_ownerDocument->detachRange(this);
m_ownerDocument = &newDocument;
m_ownerDocument->attachRange(this);
}
static inline void boundaryTextNodeSplit(RangeBoundaryPoint& boundary, Text& oldNode)
{
Node* boundaryContainer = boundary.container();
......
......@@ -132,6 +132,7 @@ public:
void didRemoveText(Node*, unsigned offset, unsigned length);
void didMergeTextNodes(const NodeWithIndex& oldNode, unsigned offset);
void didSplitTextNode(Text& oldNode);
void updateOwnerDocumentIfNeeded();
// Expand range to a unit (word or sentence or block or document) boundary.
// Please refer to https://bugs.webkit.org/show_bug.cgi?id=27632 comment #5
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment