summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/dom/Range.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/dom/Range.cpp')
-rw-r--r--Source/WebCore/dom/Range.cpp262
1 files changed, 118 insertions, 144 deletions
diff --git a/Source/WebCore/dom/Range.cpp b/Source/WebCore/dom/Range.cpp
index a41fc49..e224843 100644
--- a/Source/WebCore/dom/Range.cpp
+++ b/Source/WebCore/dom/Range.cpp
@@ -594,6 +594,21 @@ bool Range::intersectsNode(Node* refNode, ExceptionCode& ec)
return true; // all other cases
}
+static inline Node* highestAncestorUnderCommonRoot(Node* node, Node* commonRoot)
+{
+ if (node == commonRoot)
+ return 0;
+
+ ASSERT(commonRoot->contains(node));
+
+ while (node->parentNode() != commonRoot)
+ node = node->parentNode();
+
+ return node;
+}
+
+static inline unsigned lengthOfContentsInNode() { return numeric_limits<unsigned>::max(); }
+
PassRefPtr<DocumentFragment> Range::processContents(ActionType action, ExceptionCode& ec)
{
typedef Vector<RefPtr<Node> > NodeVector;
@@ -601,7 +616,7 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception
RefPtr<DocumentFragment> fragment;
if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
fragment = DocumentFragment::create(m_ownerDocument.get());
-
+
ec = 0;
if (collapsed(ec))
return fragment.release();
@@ -613,68 +628,16 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception
return 0;
ASSERT(commonRoot);
- // what is the highest node that partially selects the start of the range?
- Node* partialStart = 0;
- if (m_start.container() != commonRoot) {
- partialStart = m_start.container();
- while (partialStart->parentNode() != commonRoot)
- partialStart = partialStart->parentNode();
- }
-
- // what is the highest node that partially selects the end of the range?
- Node* partialEnd = 0;
- if (m_end.container() != commonRoot) {
- partialEnd = m_end.container();
- while (partialEnd->parentNode() != commonRoot)
- partialEnd = partialEnd->parentNode();
- }
-
- // Simple case: the start and end containers are the same. We just grab
- // everything >= start offset and < end offset
if (m_start.container() == m_end.container()) {
- Node::NodeType startNodeType = m_start.container()->nodeType();
- if (startNodeType == Node::TEXT_NODE || startNodeType == Node::CDATA_SECTION_NODE || startNodeType == Node::COMMENT_NODE) {
- if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
- RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_start.container()->cloneNode(true));
- c->deleteData(m_end.offset(), c->length() - m_end.offset(), ec);
- c->deleteData(0, m_start.offset(), ec);
- fragment->appendChild(c.release(), ec);
- }
- if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
- static_cast<CharacterData*>(m_start.container())->deleteData(m_start.offset(), m_end.offset() - m_start.offset(), ec);
- } else if (startNodeType == Node::PROCESSING_INSTRUCTION_NODE) {
- if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
- RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_start.container()->cloneNode(true));
- c->setData(c->data().substring(m_start.offset(), m_end.offset() - m_start.offset()), ec);
- fragment->appendChild(c.release(), ec);
- }
- if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
- ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_start.container());
- String data(pi->data());
- data.remove(m_start.offset(), m_end.offset() - m_start.offset());
- pi->setData(data, ec);
- }
- } else {
- RefPtr<Node> n = m_start.container()->firstChild();
- int i;
- for (i = 0; n && i < m_start.offset(); i++) // skip until start offset
- n = n->nextSibling();
- int endOffset = m_end.offset();
- RefPtr<Node> next;
- for (; n && i < endOffset; n = next, i++) { // delete until end offset
- next = n->nextSibling();
- if (action == EXTRACT_CONTENTS)
- fragment->appendChild(n, ec); // will remove n from its parent
- else if (action == CLONE_CONTENTS)
- fragment->appendChild(n->cloneNode(true), ec);
- else
- toContainerNode(m_start.container())->removeChild(n.get(), ec);
- }
- }
- return fragment.release();
+ processContentsBetweenOffsets(action, fragment, m_start.container(), m_start.offset(), m_end.offset(), ec);
+ return fragment;
}
- // Complex case: Start and end containers are different.
+ // what is the highest node that partially selects the start / end of the range?
+ Node* partialStart = highestAncestorUnderCommonRoot(m_start.container(), commonRoot);
+ Node* partialEnd = highestAncestorUnderCommonRoot(m_end.container(), commonRoot);
+
+ // Start and end containers are different.
// There are three possibilities here:
// 1. Start container == commonRoot (End container must be a descendant)
// 2. End container == commonRoot (Start container must be a descendant)
@@ -693,49 +656,7 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception
RefPtr<Node> leftContents;
if (m_start.container() != commonRoot) {
- // process the left-hand side of the range, up until the last ancestor of
- // start container before commonRoot
- Node::NodeType startNodeType = m_start.container()->nodeType();
- if (startNodeType == Node::TEXT_NODE || startNodeType == Node::CDATA_SECTION_NODE || startNodeType == Node::COMMENT_NODE) {
- if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
- RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_start.container()->cloneNode(true));
- c->deleteData(0, m_start.offset(), ec);
- leftContents = c.release();
- }
- if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
- static_cast<CharacterData*>(m_start.container())->deleteData(
- m_start.offset(), static_cast<CharacterData*>(m_start.container())->length() - m_start.offset(), ec);
- } else if (startNodeType == Node::PROCESSING_INSTRUCTION_NODE) {
- if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
- RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_start.container()->cloneNode(true));
- c->setData(c->data().substring(m_start.offset()), ec);
- leftContents = c.release();
- }
- if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
- ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_start.container());
- String data(pi->data());
- pi->setData(data.left(m_start.offset()), ec);
- }
- } else {
- if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
- leftContents = m_start.container()->cloneNode(false);
- NodeVector nodes;
- Node* n = m_start.container()->firstChild();
- for (int i = 0; n; n = n->nextSibling(), i++) {
- if (i < m_start.offset())
- continue; // Skip until start offset.
- nodes.append(n);
- }
- for (NodeVector::const_iterator it = nodes.begin(); it != nodes.end(); it++) {
- Node* n = it->get();
- if (action == EXTRACT_CONTENTS)
- leftContents->appendChild(n, ec); // Will remove n from start container.
- else if (action == CLONE_CONTENTS)
- leftContents->appendChild(n->cloneNode(true), ec);
- else
- toContainerNode(m_start.container())->removeChild(n, ec);
- }
- }
+ leftContents = processContentsBetweenOffsets(action, 0, m_start.container(), m_start.offset(), lengthOfContentsInNode(), ec);
NodeVector ancestorNodes;
for (ContainerNode* n = m_start.container()->parentNode(); n && n != commonRoot; n = n->parentNode())
@@ -767,46 +688,7 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception
RefPtr<Node> rightContents;
if (m_end.container() != commonRoot) {
- // delete the right-hand side of the range, up until the last ancestor of
- // end container before commonRoot
- Node::NodeType endNodeType = m_end.container()->nodeType();
- if (endNodeType == Node::TEXT_NODE || endNodeType == Node::CDATA_SECTION_NODE || endNodeType == Node::COMMENT_NODE) {
- if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
- RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_end.container()->cloneNode(true));
- c->deleteData(m_end.offset(), static_cast<CharacterData*>(m_end.container())->length() - m_end.offset(), ec);
- rightContents = c;
- }
- if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
- static_cast<CharacterData*>(m_end.container())->deleteData(0, m_end.offset(), ec);
- } else if (endNodeType == Node::PROCESSING_INSTRUCTION_NODE) {
- if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
- RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_end.container()->cloneNode(true));
- c->setData(c->data().left(m_end.offset()), ec);
- rightContents = c.release();
- }
- if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
- ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_end.container());
- pi->setData(pi->data().substring(m_end.offset()), ec);
- }
- } else {
- if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
- rightContents = m_end.container()->cloneNode(false);
- Node* n = m_end.container()->firstChild();
- if (n && m_end.offset()) {
- NodeVector nodes;
- for (int i = 0; i < m_end.offset() && n; i++, n = n->nextSibling())
- nodes.append(n);
- for (int i = nodes.size() - 1; i >= 0; i--) {
- n = nodes[i].get();
- if (action == EXTRACT_CONTENTS)
- rightContents->insertBefore(n, rightContents->firstChild(), ec); // will remove n from its parent
- else if (action == CLONE_CONTENTS)
- rightContents->insertBefore(n->cloneNode(true), rightContents->firstChild(), ec);
- else
- toContainerNode(m_end.container())->removeChild(n, ec);
- }
- }
- }
+ rightContents = processContentsBetweenOffsets(action, 0, m_end.container(), 0, m_end.offset(), ec);
ContainerNode* rightParent = m_end.container()->parentNode();
Node* n = m_end.container()->previousSibling();
@@ -892,6 +774,98 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception
return fragment.release();
}
+PassRefPtr<Node> Range::processContentsBetweenOffsets(ActionType action, PassRefPtr<DocumentFragment> fragment,
+ Node* container, unsigned startOffset, unsigned endOffset, ExceptionCode& ec)
+{
+ ASSERT(container);
+ ASSERT(startOffset <= endOffset);
+
+ RefPtr<Node> result;
+ switch (container->nodeType()) {
+ case Node::TEXT_NODE:
+ case Node::CDATA_SECTION_NODE:
+ case Node::COMMENT_NODE:
+ ASSERT(endOffset <= static_cast<CharacterData*>(container)->length() || endOffset == lengthOfContentsInNode());
+ if (endOffset == lengthOfContentsInNode())
+ endOffset = static_cast<CharacterData*>(container)->length();
+ if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
+ RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(container->cloneNode(true));
+ if (c->length() - endOffset)
+ c->deleteData(endOffset, c->length() - endOffset, ec);
+ if (startOffset)
+ c->deleteData(0, startOffset, ec);
+ if (fragment) {
+ result = fragment;
+ result->appendChild(c.release(), ec);
+ } else
+ result = c.release();
+ }
+ if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
+ static_cast<CharacterData*>(container)->deleteData(startOffset, endOffset - startOffset, ec);
+ break;
+ case Node::PROCESSING_INSTRUCTION_NODE:
+ ASSERT(endOffset <= static_cast<ProcessingInstruction*>(container)->data().length() || endOffset == lengthOfContentsInNode());
+ if (endOffset == lengthOfContentsInNode())
+ endOffset = static_cast<ProcessingInstruction*>(container)->data().length();
+ if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
+ RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(container->cloneNode(true));
+ c->setData(c->data().substring(startOffset, endOffset - startOffset), ec);
+ if (fragment) {
+ result = fragment;
+ result->appendChild(c.release(), ec);
+ } else
+ result = c.release();
+ }
+ if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
+ ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(container);
+ String data(pi->data());
+ data.remove(startOffset, endOffset - startOffset);
+ pi->setData(data, ec);
+ }
+ break;
+ case Node::ELEMENT_NODE:
+ case Node::ATTRIBUTE_NODE:
+ case Node::ENTITY_REFERENCE_NODE:
+ case Node::ENTITY_NODE:
+ case Node::DOCUMENT_NODE:
+ case Node::DOCUMENT_TYPE_NODE:
+ case Node::DOCUMENT_FRAGMENT_NODE:
+ case Node::NOTATION_NODE:
+ case Node::XPATH_NAMESPACE_NODE:
+ // FIXME: Should we assert that some nodes never appear here?
+ if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
+ if (fragment)
+ result = fragment;
+ else
+ result = container->cloneNode(false);
+ }
+
+ Node* n = container->firstChild();
+ Vector<RefPtr<Node> > nodes;
+ for (unsigned i = startOffset; n && i; i--)
+ n = n->nextSibling();
+ for (unsigned i = startOffset; n && i < endOffset; i++, n = n->nextSibling())
+ nodes.append(n);
+
+ for (unsigned i = 0; i < nodes.size(); i++) {
+ switch (action) {
+ case DELETE_CONTENTS:
+ container->removeChild(nodes[i].get(), ec);
+ break;
+ case EXTRACT_CONTENTS:
+ result->appendChild(nodes[i].release(), ec); // will remove n from its parent
+ break;
+ case CLONE_CONTENTS:
+ result->appendChild(nodes[i]->cloneNode(true), ec);
+ break;
+ }
+ }
+ break;
+ }
+
+ return result;
+}
+
PassRefPtr<DocumentFragment> Range::extractContents(ExceptionCode& ec)
{
checkDeleteExtract(ec);
@@ -1079,7 +1053,7 @@ PassRefPtr<DocumentFragment> Range::createContextualFragment(const String& marku
// Logic from deprecatedCreateContextualFragment should just be moved into
// this function. Range::createContextualFragment semantics do not make
// sense for the rest of the DOM implementation to use.
- RefPtr<DocumentFragment> fragment = static_cast<HTMLElement*>(element)->deprecatedCreateContextualFragment(markup);
+ RefPtr<DocumentFragment> fragment = toHTMLElement(element)->deprecatedCreateContextualFragment(markup);
if (!fragment) {
ec = NOT_SUPPORTED_ERR;
return 0;