Home | History | Annotate | Download | only in editing
      1 /*
      2  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
      3  * Copyright (C) 2008, 2009, 2010, 2011 Google Inc. All rights reserved.
      4  * Copyright (C) 2011 Igalia S.L.
      5  * Copyright (C) 2011 Motorola Mobility. All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include "config.h"
     30 #include "core/editing/markup.h"
     31 
     32 #include "CSSPropertyNames.h"
     33 #include "CSSValueKeywords.h"
     34 #include "HTMLNames.h"
     35 #include "bindings/v8/ExceptionState.h"
     36 #include "core/css/CSSPrimitiveValue.h"
     37 #include "core/css/CSSValue.h"
     38 #include "core/css/StylePropertySet.h"
     39 #include "core/dom/CDATASection.h"
     40 #include "core/dom/ChildListMutationScope.h"
     41 #include "core/dom/ContextFeatures.h"
     42 #include "core/dom/DocumentFragment.h"
     43 #include "core/dom/ElementTraversal.h"
     44 #include "core/dom/ExceptionCode.h"
     45 #include "core/dom/NodeTraversal.h"
     46 #include "core/dom/Range.h"
     47 #include "core/editing/Editor.h"
     48 #include "core/editing/MarkupAccumulator.h"
     49 #include "core/editing/TextIterator.h"
     50 #include "core/editing/VisibleSelection.h"
     51 #include "core/editing/VisibleUnits.h"
     52 #include "core/editing/htmlediting.h"
     53 #include "core/html/HTMLBodyElement.h"
     54 #include "core/html/HTMLElement.h"
     55 #include "core/html/HTMLHtmlElement.h"
     56 #include "core/html/HTMLTableElement.h"
     57 #include "core/html/HTMLTextFormControlElement.h"
     58 #include "core/frame/Frame.h"
     59 #include "core/rendering/RenderObject.h"
     60 #include "platform/weborigin/KURL.h"
     61 #include "wtf/StdLibExtras.h"
     62 #include "wtf/text/StringBuilder.h"
     63 
     64 using namespace std;
     65 
     66 namespace WebCore {
     67 
     68 using namespace HTMLNames;
     69 
     70 static bool propertyMissingOrEqualToNone(StylePropertySet*, CSSPropertyID);
     71 
     72 class AttributeChange {
     73 public:
     74     AttributeChange()
     75         : m_name(nullAtom, nullAtom, nullAtom)
     76     {
     77     }
     78 
     79     AttributeChange(PassRefPtr<Element> element, const QualifiedName& name, const String& value)
     80         : m_element(element), m_name(name), m_value(value)
     81     {
     82     }
     83 
     84     void apply()
     85     {
     86         m_element->setAttribute(m_name, AtomicString(m_value));
     87     }
     88 
     89 private:
     90     RefPtr<Element> m_element;
     91     QualifiedName m_name;
     92     String m_value;
     93 };
     94 
     95 static void completeURLs(DocumentFragment& fragment, const String& baseURL)
     96 {
     97     Vector<AttributeChange> changes;
     98 
     99     KURL parsedBaseURL(ParsedURLString, baseURL);
    100 
    101     for (Element* element = ElementTraversal::firstWithin(fragment); element; element = ElementTraversal::next(*element, &fragment)) {
    102         if (!element->hasAttributes())
    103             continue;
    104         unsigned length = element->attributeCount();
    105         for (unsigned i = 0; i < length; i++) {
    106             const Attribute* attribute = element->attributeItem(i);
    107             if (element->isURLAttribute(*attribute) && !attribute->value().isEmpty())
    108                 changes.append(AttributeChange(element, attribute->name(), KURL(parsedBaseURL, attribute->value()).string()));
    109         }
    110     }
    111 
    112     size_t numChanges = changes.size();
    113     for (size_t i = 0; i < numChanges; ++i)
    114         changes[i].apply();
    115 }
    116 
    117 class StyledMarkupAccumulator : public MarkupAccumulator {
    118 public:
    119     enum RangeFullySelectsNode { DoesFullySelectNode, DoesNotFullySelectNode };
    120 
    121     StyledMarkupAccumulator(Vector<Node*>* nodes, EAbsoluteURLs, EAnnotateForInterchange, const Range*, Node* highestNodeToBeSerialized = 0);
    122     Node* serializeNodes(Node* startNode, Node* pastEnd);
    123     virtual void appendString(const String& s) { return MarkupAccumulator::appendString(s); }
    124     void wrapWithNode(Node*, bool convertBlocksToInlines = false, RangeFullySelectsNode = DoesFullySelectNode);
    125     void wrapWithStyleNode(StylePropertySet*, Document*, bool isBlock = false);
    126     String takeResults();
    127 
    128 private:
    129     void appendStyleNodeOpenTag(StringBuilder&, StylePropertySet*, Document*, bool isBlock = false);
    130     const String& styleNodeCloseTag(bool isBlock = false);
    131     virtual void appendText(StringBuilder& out, Text*);
    132     String renderedText(const Node*, const Range*);
    133     String stringValueForRange(const Node*, const Range*);
    134     void appendElement(StringBuilder& out, Element*, bool addDisplayInline, RangeFullySelectsNode);
    135     void appendElement(StringBuilder& out, Element* element, Namespaces*) { appendElement(out, element, false, DoesFullySelectNode); }
    136 
    137     enum NodeTraversalMode { EmitString, DoNotEmitString };
    138     Node* traverseNodesForSerialization(Node* startNode, Node* pastEnd, NodeTraversalMode);
    139 
    140     bool shouldAnnotate() { return m_shouldAnnotate == AnnotateForInterchange; }
    141     bool shouldApplyWrappingStyle(Node* node) const
    142     {
    143         return m_highestNodeToBeSerialized && m_highestNodeToBeSerialized->parentNode() == node->parentNode()
    144             && m_wrappingStyle && m_wrappingStyle->style();
    145     }
    146 
    147     Vector<String> m_reversedPrecedingMarkup;
    148     const EAnnotateForInterchange m_shouldAnnotate;
    149     Node* m_highestNodeToBeSerialized;
    150     RefPtr<EditingStyle> m_wrappingStyle;
    151 };
    152 
    153 inline StyledMarkupAccumulator::StyledMarkupAccumulator(Vector<Node*>* nodes, EAbsoluteURLs shouldResolveURLs, EAnnotateForInterchange shouldAnnotate,
    154     const Range* range, Node* highestNodeToBeSerialized)
    155     : MarkupAccumulator(nodes, shouldResolveURLs, range)
    156     , m_shouldAnnotate(shouldAnnotate)
    157     , m_highestNodeToBeSerialized(highestNodeToBeSerialized)
    158 {
    159 }
    160 
    161 void StyledMarkupAccumulator::wrapWithNode(Node* node, bool convertBlocksToInlines, RangeFullySelectsNode rangeFullySelectsNode)
    162 {
    163     StringBuilder markup;
    164     if (node->isElementNode())
    165         appendElement(markup, toElement(node), convertBlocksToInlines && isBlock(const_cast<Node*>(node)), rangeFullySelectsNode);
    166     else
    167         appendStartMarkup(markup, node, 0);
    168     m_reversedPrecedingMarkup.append(markup.toString());
    169     appendEndTag(node);
    170     if (m_nodes)
    171         m_nodes->append(node);
    172 }
    173 
    174 void StyledMarkupAccumulator::wrapWithStyleNode(StylePropertySet* style, Document* document, bool isBlock)
    175 {
    176     StringBuilder openTag;
    177     appendStyleNodeOpenTag(openTag, style, document, isBlock);
    178     m_reversedPrecedingMarkup.append(openTag.toString());
    179     appendString(styleNodeCloseTag(isBlock));
    180 }
    181 
    182 void StyledMarkupAccumulator::appendStyleNodeOpenTag(StringBuilder& out, StylePropertySet* style, Document* document, bool isBlock)
    183 {
    184     // wrappingStyleForSerialization should have removed -webkit-text-decorations-in-effect
    185     ASSERT(propertyMissingOrEqualToNone(style, CSSPropertyWebkitTextDecorationsInEffect));
    186     if (isBlock)
    187         out.appendLiteral("<div style=\"");
    188     else
    189         out.appendLiteral("<span style=\"");
    190     appendAttributeValue(out, style->asText(), document->isHTMLDocument());
    191     out.append('\"');
    192     out.append('>');
    193 }
    194 
    195 const String& StyledMarkupAccumulator::styleNodeCloseTag(bool isBlock)
    196 {
    197     DEFINE_STATIC_LOCAL(const String, divClose, ("</div>"));
    198     DEFINE_STATIC_LOCAL(const String, styleSpanClose, ("</span>"));
    199     return isBlock ? divClose : styleSpanClose;
    200 }
    201 
    202 String StyledMarkupAccumulator::takeResults()
    203 {
    204     StringBuilder result;
    205     result.reserveCapacity(totalLength(m_reversedPrecedingMarkup) + length());
    206 
    207     for (size_t i = m_reversedPrecedingMarkup.size(); i > 0; --i)
    208         result.append(m_reversedPrecedingMarkup[i - 1]);
    209 
    210     concatenateMarkup(result);
    211 
    212     // We remove '\0' characters because they are not visibly rendered to the user.
    213     return result.toString().replace(0, "");
    214 }
    215 
    216 void StyledMarkupAccumulator::appendText(StringBuilder& out, Text* text)
    217 {
    218     const bool parentIsTextarea = text->parentElement() && text->parentElement()->tagQName() == textareaTag;
    219     const bool wrappingSpan = shouldApplyWrappingStyle(text) && !parentIsTextarea;
    220     if (wrappingSpan) {
    221         RefPtr<EditingStyle> wrappingStyle = m_wrappingStyle->copy();
    222         // FIXME: <rdar://problem/5371536> Style rules that match pasted content can change it's appearance
    223         // Make sure spans are inline style in paste side e.g. span { display: block }.
    224         wrappingStyle->forceInline();
    225         // FIXME: Should this be included in forceInline?
    226         wrappingStyle->style()->setProperty(CSSPropertyFloat, CSSValueNone);
    227 
    228         appendStyleNodeOpenTag(out, wrappingStyle->style(), &text->document());
    229     }
    230 
    231     if (!shouldAnnotate() || parentIsTextarea)
    232         MarkupAccumulator::appendText(out, text);
    233     else {
    234         const bool useRenderedText = !enclosingNodeWithTag(firstPositionInNode(text), selectTag);
    235         String content = useRenderedText ? renderedText(text, m_range) : stringValueForRange(text, m_range);
    236         StringBuilder buffer;
    237         appendCharactersReplacingEntities(buffer, content, 0, content.length(), EntityMaskInPCDATA);
    238         out.append(convertHTMLTextToInterchangeFormat(buffer.toString(), text));
    239     }
    240 
    241     if (wrappingSpan)
    242         out.append(styleNodeCloseTag());
    243 }
    244 
    245 String StyledMarkupAccumulator::renderedText(const Node* node, const Range* range)
    246 {
    247     if (!node->isTextNode())
    248         return String();
    249 
    250     const Text* textNode = toText(node);
    251     unsigned startOffset = 0;
    252     unsigned endOffset = textNode->length();
    253 
    254     if (range && node == range->startContainer())
    255         startOffset = range->startOffset();
    256     if (range && node == range->endContainer())
    257         endOffset = range->endOffset();
    258 
    259     Position start = createLegacyEditingPosition(const_cast<Node*>(node), startOffset);
    260     Position end = createLegacyEditingPosition(const_cast<Node*>(node), endOffset);
    261     return plainText(Range::create(node->document(), start, end).get());
    262 }
    263 
    264 String StyledMarkupAccumulator::stringValueForRange(const Node* node, const Range* range)
    265 {
    266     if (!range)
    267         return node->nodeValue();
    268 
    269     String str = node->nodeValue();
    270     if (node == range->endContainer())
    271         str.truncate(range->endOffset());
    272     if (node == range->startContainer())
    273         str.remove(0, range->startOffset());
    274     return str;
    275 }
    276 
    277 void StyledMarkupAccumulator::appendElement(StringBuilder& out, Element* element, bool addDisplayInline, RangeFullySelectsNode rangeFullySelectsNode)
    278 {
    279     const bool documentIsHTML = element->document().isHTMLDocument();
    280     appendOpenTag(out, element, 0);
    281 
    282     const unsigned length = element->hasAttributes() ? element->attributeCount() : 0;
    283     const bool shouldAnnotateOrForceInline = element->isHTMLElement() && (shouldAnnotate() || addDisplayInline);
    284     const bool shouldOverrideStyleAttr = shouldAnnotateOrForceInline || shouldApplyWrappingStyle(element);
    285     for (unsigned i = 0; i < length; ++i) {
    286         const Attribute* attribute = element->attributeItem(i);
    287         // We'll handle the style attribute separately, below.
    288         if (attribute->name() == styleAttr && shouldOverrideStyleAttr)
    289             continue;
    290         appendAttribute(out, element, *attribute, 0);
    291     }
    292 
    293     if (shouldOverrideStyleAttr) {
    294         RefPtr<EditingStyle> newInlineStyle;
    295 
    296         if (shouldApplyWrappingStyle(element)) {
    297             newInlineStyle = m_wrappingStyle->copy();
    298             newInlineStyle->removePropertiesInElementDefaultStyle(element);
    299             newInlineStyle->removeStyleConflictingWithStyleOfNode(element);
    300         } else
    301             newInlineStyle = EditingStyle::create();
    302 
    303         if (element->isStyledElement() && element->inlineStyle())
    304             newInlineStyle->overrideWithStyle(element->inlineStyle());
    305 
    306         if (shouldAnnotateOrForceInline) {
    307             if (shouldAnnotate())
    308                 newInlineStyle->mergeStyleFromRulesForSerialization(toHTMLElement(element));
    309 
    310             if (addDisplayInline)
    311                 newInlineStyle->forceInline();
    312 
    313             // If the node is not fully selected by the range, then we don't want to keep styles that affect its relationship to the nodes around it
    314             // only the ones that affect it and the nodes within it.
    315             if (rangeFullySelectsNode == DoesNotFullySelectNode && newInlineStyle->style())
    316                 newInlineStyle->style()->removeProperty(CSSPropertyFloat);
    317         }
    318 
    319         if (!newInlineStyle->isEmpty()) {
    320             out.appendLiteral(" style=\"");
    321             appendAttributeValue(out, newInlineStyle->style()->asText(), documentIsHTML);
    322             out.append('\"');
    323         }
    324     }
    325 
    326     appendCloseTag(out, element);
    327 }
    328 
    329 Node* StyledMarkupAccumulator::serializeNodes(Node* startNode, Node* pastEnd)
    330 {
    331     if (!m_highestNodeToBeSerialized) {
    332         Node* lastClosed = traverseNodesForSerialization(startNode, pastEnd, DoNotEmitString);
    333         m_highestNodeToBeSerialized = lastClosed;
    334     }
    335 
    336     if (m_highestNodeToBeSerialized && m_highestNodeToBeSerialized->parentNode())
    337         m_wrappingStyle = EditingStyle::wrappingStyleForSerialization(m_highestNodeToBeSerialized->parentNode(), shouldAnnotate());
    338 
    339     return traverseNodesForSerialization(startNode, pastEnd, EmitString);
    340 }
    341 
    342 Node* StyledMarkupAccumulator::traverseNodesForSerialization(Node* startNode, Node* pastEnd, NodeTraversalMode traversalMode)
    343 {
    344     const bool shouldEmit = traversalMode == EmitString;
    345     Vector<Node*> ancestorsToClose;
    346     Node* next;
    347     Node* lastClosed = 0;
    348     for (Node* n = startNode; n != pastEnd; n = next) {
    349         // According to <rdar://problem/5730668>, it is possible for n to blow
    350         // past pastEnd and become null here. This shouldn't be possible.
    351         // This null check will prevent crashes (but create too much markup)
    352         // and the ASSERT will hopefully lead us to understanding the problem.
    353         ASSERT(n);
    354         if (!n)
    355             break;
    356 
    357         next = NodeTraversal::next(*n);
    358         bool openedTag = false;
    359 
    360         if (isBlock(n) && canHaveChildrenForEditing(n) && next == pastEnd)
    361             // Don't write out empty block containers that aren't fully selected.
    362             continue;
    363 
    364         if (!n->renderer() && !enclosingNodeWithTag(firstPositionInOrBeforeNode(n), selectTag)) {
    365             next = NodeTraversal::nextSkippingChildren(*n);
    366             // Don't skip over pastEnd.
    367             if (pastEnd && pastEnd->isDescendantOf(n))
    368                 next = pastEnd;
    369         } else {
    370             // Add the node to the markup if we're not skipping the descendants
    371             if (shouldEmit)
    372                 appendStartTag(n);
    373 
    374             // If node has no children, close the tag now.
    375             if (!n->childNodeCount()) {
    376                 if (shouldEmit)
    377                     appendEndTag(n);
    378                 lastClosed = n;
    379             } else {
    380                 openedTag = true;
    381                 ancestorsToClose.append(n);
    382             }
    383         }
    384 
    385         // If we didn't insert open tag and there's no more siblings or we're at the end of the traversal, take care of ancestors.
    386         // FIXME: What happens if we just inserted open tag and reached the end?
    387         if (!openedTag && (!n->nextSibling() || next == pastEnd)) {
    388             // Close up the ancestors.
    389             while (!ancestorsToClose.isEmpty()) {
    390                 Node* ancestor = ancestorsToClose.last();
    391                 if (next != pastEnd && next->isDescendantOf(ancestor))
    392                     break;
    393                 // Not at the end of the range, close ancestors up to sibling of next node.
    394                 if (shouldEmit)
    395                     appendEndTag(ancestor);
    396                 lastClosed = ancestor;
    397                 ancestorsToClose.removeLast();
    398             }
    399 
    400             // Surround the currently accumulated markup with markup for ancestors we never opened as we leave the subtree(s) rooted at those ancestors.
    401             ContainerNode* nextParent = next ? next->parentNode() : 0;
    402             if (next != pastEnd && n != nextParent) {
    403                 Node* lastAncestorClosedOrSelf = n->isDescendantOf(lastClosed) ? lastClosed : n;
    404                 for (ContainerNode* parent = lastAncestorClosedOrSelf->parentNode(); parent && parent != nextParent; parent = parent->parentNode()) {
    405                     // All ancestors that aren't in the ancestorsToClose list should either be a) unrendered:
    406                     if (!parent->renderer())
    407                         continue;
    408                     // or b) ancestors that we never encountered during a pre-order traversal starting at startNode:
    409                     ASSERT(startNode->isDescendantOf(parent));
    410                     if (shouldEmit)
    411                         wrapWithNode(parent);
    412                     lastClosed = parent;
    413                 }
    414             }
    415         }
    416     }
    417 
    418     return lastClosed;
    419 }
    420 
    421 static bool isHTMLBlockElement(const Node* node)
    422 {
    423     return node->hasTagName(tdTag)
    424         || node->hasTagName(thTag)
    425         || isNonTableCellHTMLBlockElement(node);
    426 }
    427 
    428 static Node* ancestorToRetainStructureAndAppearanceForBlock(Node* commonAncestorBlock)
    429 {
    430     if (!commonAncestorBlock)
    431         return 0;
    432 
    433     if (commonAncestorBlock->hasTagName(tbodyTag) || commonAncestorBlock->hasTagName(trTag)) {
    434         ContainerNode* table = commonAncestorBlock->parentNode();
    435         while (table && !isHTMLTableElement(table))
    436             table = table->parentNode();
    437 
    438         return table;
    439     }
    440 
    441     if (isNonTableCellHTMLBlockElement(commonAncestorBlock))
    442         return commonAncestorBlock;
    443 
    444     return 0;
    445 }
    446 
    447 static inline Node* ancestorToRetainStructureAndAppearance(Node* commonAncestor)
    448 {
    449     return ancestorToRetainStructureAndAppearanceForBlock(enclosingBlock(commonAncestor));
    450 }
    451 
    452 static inline Node* ancestorToRetainStructureAndAppearanceWithNoRenderer(Node* commonAncestor)
    453 {
    454     Node* commonAncestorBlock = enclosingNodeOfType(firstPositionInOrBeforeNode(commonAncestor), isHTMLBlockElement);
    455     return ancestorToRetainStructureAndAppearanceForBlock(commonAncestorBlock);
    456 }
    457 
    458 static bool propertyMissingOrEqualToNone(StylePropertySet* style, CSSPropertyID propertyID)
    459 {
    460     if (!style)
    461         return false;
    462     RefPtr<CSSValue> value = style->getPropertyCSSValue(propertyID);
    463     if (!value)
    464         return true;
    465     if (!value->isPrimitiveValue())
    466         return false;
    467     return toCSSPrimitiveValue(value.get())->getValueID() == CSSValueNone;
    468 }
    469 
    470 static bool needInterchangeNewlineAfter(const VisiblePosition& v)
    471 {
    472     VisiblePosition next = v.next();
    473     Node* upstreamNode = next.deepEquivalent().upstream().deprecatedNode();
    474     Node* downstreamNode = v.deepEquivalent().downstream().deprecatedNode();
    475     // Add an interchange newline if a paragraph break is selected and a br won't already be added to the markup to represent it.
    476     return isEndOfParagraph(v) && isStartOfParagraph(next) && !(upstreamNode->hasTagName(brTag) && upstreamNode == downstreamNode);
    477 }
    478 
    479 static PassRefPtr<EditingStyle> styleFromMatchedRulesAndInlineDecl(const Node* node)
    480 {
    481     if (!node->isHTMLElement())
    482         return 0;
    483 
    484     // FIXME: Having to const_cast here is ugly, but it is quite a bit of work to untangle
    485     // the non-const-ness of styleFromMatchedRulesForElement.
    486     HTMLElement* element = const_cast<HTMLElement*>(toHTMLElement(node));
    487     RefPtr<EditingStyle> style = EditingStyle::create(element->inlineStyle());
    488     style->mergeStyleFromRules(element);
    489     return style.release();
    490 }
    491 
    492 static bool isElementPresentational(const Node* node)
    493 {
    494     return node->hasTagName(uTag) || node->hasTagName(sTag) || node->hasTagName(strikeTag)
    495         || node->hasTagName(iTag) || node->hasTagName(emTag) || node->hasTagName(bTag) || node->hasTagName(strongTag);
    496 }
    497 
    498 static Node* highestAncestorToWrapMarkup(const Range* range, EAnnotateForInterchange shouldAnnotate, Node* constrainingAncestor)
    499 {
    500     Node* commonAncestor = range->commonAncestorContainer(IGNORE_EXCEPTION);
    501     ASSERT(commonAncestor);
    502     Node* specialCommonAncestor = 0;
    503     if (shouldAnnotate == AnnotateForInterchange) {
    504         // Include ancestors that aren't completely inside the range but are required to retain
    505         // the structure and appearance of the copied markup.
    506         specialCommonAncestor = ancestorToRetainStructureAndAppearance(commonAncestor);
    507 
    508         if (Node* parentListNode = enclosingNodeOfType(firstPositionInOrBeforeNode(range->firstNode()), isListItem)) {
    509             if (WebCore::areRangesEqual(VisibleSelection::selectionFromContentsOfNode(parentListNode).toNormalizedRange().get(), range)) {
    510                 specialCommonAncestor = parentListNode->parentNode();
    511                 while (specialCommonAncestor && !isListElement(specialCommonAncestor))
    512                     specialCommonAncestor = specialCommonAncestor->parentNode();
    513             }
    514         }
    515 
    516         // Retain the Mail quote level by including all ancestor mail block quotes.
    517         if (Node* highestMailBlockquote = highestEnclosingNodeOfType(firstPositionInOrBeforeNode(range->firstNode()), isMailBlockquote, CanCrossEditingBoundary))
    518             specialCommonAncestor = highestMailBlockquote;
    519     }
    520 
    521     Node* checkAncestor = specialCommonAncestor ? specialCommonAncestor : commonAncestor;
    522     if (checkAncestor->renderer()) {
    523         Node* newSpecialCommonAncestor = highestEnclosingNodeOfType(firstPositionInNode(checkAncestor), &isElementPresentational, CanCrossEditingBoundary, constrainingAncestor);
    524         if (newSpecialCommonAncestor)
    525             specialCommonAncestor = newSpecialCommonAncestor;
    526     }
    527 
    528     // If a single tab is selected, commonAncestor will be a text node inside a tab span.
    529     // If two or more tabs are selected, commonAncestor will be the tab span.
    530     // In either case, if there is a specialCommonAncestor already, it will necessarily be above
    531     // any tab span that needs to be included.
    532     if (!specialCommonAncestor && isTabSpanTextNode(commonAncestor))
    533         specialCommonAncestor = commonAncestor->parentNode();
    534     if (!specialCommonAncestor && isTabSpanNode(commonAncestor))
    535         specialCommonAncestor = commonAncestor;
    536 
    537     if (Node *enclosingAnchor = enclosingNodeWithTag(firstPositionInNode(specialCommonAncestor ? specialCommonAncestor : commonAncestor), aTag))
    538         specialCommonAncestor = enclosingAnchor;
    539 
    540     return specialCommonAncestor;
    541 }
    542 
    543 // FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForInterchange?
    544 // FIXME: At least, annotation and style info should probably not be included in range.markupString()
    545 static String createMarkupInternal(Document& document, const Range* range, const Range* updatedRange, Vector<Node*>* nodes,
    546     EAnnotateForInterchange shouldAnnotate, bool convertBlocksToInlines, EAbsoluteURLs shouldResolveURLs, Node* constrainingAncestor)
    547 {
    548     ASSERT(range);
    549     ASSERT(updatedRange);
    550     DEFINE_STATIC_LOCAL(const String, interchangeNewlineString, ("<br class=\"" AppleInterchangeNewline "\">"));
    551 
    552     bool collapsed = updatedRange->collapsed(ASSERT_NO_EXCEPTION);
    553     if (collapsed)
    554         return emptyString();
    555     Node* commonAncestor = updatedRange->commonAncestorContainer(ASSERT_NO_EXCEPTION);
    556     if (!commonAncestor)
    557         return emptyString();
    558 
    559     document.updateLayoutIgnorePendingStylesheets();
    560 
    561     Node* body = enclosingNodeWithTag(firstPositionInNode(commonAncestor), bodyTag);
    562     Node* fullySelectedRoot = 0;
    563     // FIXME: Do this for all fully selected blocks, not just the body.
    564     if (body && areRangesEqual(VisibleSelection::selectionFromContentsOfNode(body).toNormalizedRange().get(), range))
    565         fullySelectedRoot = body;
    566     Node* specialCommonAncestor = highestAncestorToWrapMarkup(updatedRange, shouldAnnotate, constrainingAncestor);
    567     StyledMarkupAccumulator accumulator(nodes, shouldResolveURLs, shouldAnnotate, updatedRange, specialCommonAncestor);
    568     Node* pastEnd = updatedRange->pastLastNode();
    569 
    570     Node* startNode = updatedRange->firstNode();
    571     VisiblePosition visibleStart(updatedRange->startPosition(), VP_DEFAULT_AFFINITY);
    572     VisiblePosition visibleEnd(updatedRange->endPosition(), VP_DEFAULT_AFFINITY);
    573     if (shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAfter(visibleStart)) {
    574         if (visibleStart == visibleEnd.previous())
    575             return interchangeNewlineString;
    576 
    577         accumulator.appendString(interchangeNewlineString);
    578         startNode = visibleStart.next().deepEquivalent().deprecatedNode();
    579 
    580         if (pastEnd && Range::compareBoundaryPoints(startNode, 0, pastEnd, 0, ASSERT_NO_EXCEPTION) >= 0)
    581             return interchangeNewlineString;
    582     }
    583 
    584     Node* lastClosed = accumulator.serializeNodes(startNode, pastEnd);
    585 
    586     if (specialCommonAncestor && lastClosed) {
    587         // Also include all of the ancestors of lastClosed up to this special ancestor.
    588         for (ContainerNode* ancestor = lastClosed->parentNode(); ancestor; ancestor = ancestor->parentNode()) {
    589             if (ancestor == fullySelectedRoot && !convertBlocksToInlines) {
    590                 RefPtr<EditingStyle> fullySelectedRootStyle = styleFromMatchedRulesAndInlineDecl(fullySelectedRoot);
    591 
    592                 // Bring the background attribute over, but not as an attribute because a background attribute on a div
    593                 // appears to have no effect.
    594                 if ((!fullySelectedRootStyle || !fullySelectedRootStyle->style() || !fullySelectedRootStyle->style()->getPropertyCSSValue(CSSPropertyBackgroundImage))
    595                     && toElement(fullySelectedRoot)->hasAttribute(backgroundAttr))
    596                     fullySelectedRootStyle->style()->setProperty(CSSPropertyBackgroundImage, "url('" + toElement(fullySelectedRoot)->getAttribute(backgroundAttr) + "')");
    597 
    598                 if (fullySelectedRootStyle->style()) {
    599                     // Reset the CSS properties to avoid an assertion error in addStyleMarkup().
    600                     // This assertion is caused at least when we select all text of a <body> element whose
    601                     // 'text-decoration' property is "inherit", and copy it.
    602                     if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->style(), CSSPropertyTextDecoration))
    603                         fullySelectedRootStyle->style()->setProperty(CSSPropertyTextDecoration, CSSValueNone);
    604                     if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->style(), CSSPropertyWebkitTextDecorationsInEffect))
    605                         fullySelectedRootStyle->style()->setProperty(CSSPropertyWebkitTextDecorationsInEffect, CSSValueNone);
    606                     accumulator.wrapWithStyleNode(fullySelectedRootStyle->style(), &document, true);
    607                 }
    608             } else {
    609                 // Since this node and all the other ancestors are not in the selection we want to set RangeFullySelectsNode to DoesNotFullySelectNode
    610                 // so that styles that affect the exterior of the node are not included.
    611                 accumulator.wrapWithNode(ancestor, convertBlocksToInlines, StyledMarkupAccumulator::DoesNotFullySelectNode);
    612             }
    613             if (nodes)
    614                 nodes->append(ancestor);
    615 
    616             lastClosed = ancestor;
    617 
    618             if (ancestor == specialCommonAncestor)
    619                 break;
    620         }
    621     }
    622 
    623     // FIXME: The interchange newline should be placed in the block that it's in, not after all of the content, unconditionally.
    624     if (shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAfter(visibleEnd.previous()))
    625         accumulator.appendString(interchangeNewlineString);
    626 
    627     return accumulator.takeResults();
    628 }
    629 
    630 String createMarkup(const Range* range, Vector<Node*>* nodes, EAnnotateForInterchange shouldAnnotate, bool convertBlocksToInlines, EAbsoluteURLs shouldResolveURLs, Node* constrainingAncestor)
    631 {
    632     if (!range)
    633         return emptyString();
    634 
    635     Document& document = range->ownerDocument();
    636     const Range* updatedRange = range;
    637 
    638     return createMarkupInternal(document, range, updatedRange, nodes, shouldAnnotate, convertBlocksToInlines, shouldResolveURLs, constrainingAncestor);
    639 }
    640 
    641 PassRefPtr<DocumentFragment> createFragmentFromMarkup(Document& document, const String& markup, const String& baseURL, ParserContentPolicy parserContentPolicy)
    642 {
    643     // We use a fake body element here to trick the HTML parser to using the InBody insertion mode.
    644     RefPtr<HTMLBodyElement> fakeBody = HTMLBodyElement::create(document);
    645     RefPtr<DocumentFragment> fragment = DocumentFragment::create(document);
    646 
    647     fragment->parseHTML(markup, fakeBody.get(), parserContentPolicy);
    648 
    649     if (!baseURL.isEmpty() && baseURL != blankURL() && baseURL != document.baseURL())
    650         completeURLs(*fragment, baseURL);
    651 
    652     return fragment.release();
    653 }
    654 
    655 static const char fragmentMarkerTag[] = "webkit-fragment-marker";
    656 
    657 static bool findNodesSurroundingContext(Document* document, RefPtr<Node>& nodeBeforeContext, RefPtr<Node>& nodeAfterContext)
    658 {
    659     for (Node* node = document->firstChild(); node; node = NodeTraversal::next(*node)) {
    660         if (node->nodeType() == Node::COMMENT_NODE && toCharacterData(node)->data() == fragmentMarkerTag) {
    661             if (!nodeBeforeContext)
    662                 nodeBeforeContext = node;
    663             else {
    664                 nodeAfterContext = node;
    665                 return true;
    666             }
    667         }
    668     }
    669     return false;
    670 }
    671 
    672 static void trimFragment(DocumentFragment* fragment, Node* nodeBeforeContext, Node* nodeAfterContext)
    673 {
    674     RefPtr<Node> next;
    675     for (RefPtr<Node> node = fragment->firstChild(); node; node = next) {
    676         if (nodeBeforeContext->isDescendantOf(node.get())) {
    677             next = NodeTraversal::next(*node);
    678             continue;
    679         }
    680         next = NodeTraversal::nextSkippingChildren(*node);
    681         ASSERT(!node->contains(nodeAfterContext));
    682         node->parentNode()->removeChild(node.get(), ASSERT_NO_EXCEPTION);
    683         if (nodeBeforeContext == node)
    684             break;
    685     }
    686 
    687     ASSERT(nodeAfterContext->parentNode());
    688     for (RefPtr<Node> node = nodeAfterContext; node; node = next) {
    689         next = NodeTraversal::nextSkippingChildren(*node);
    690         node->parentNode()->removeChild(node.get(), ASSERT_NO_EXCEPTION);
    691     }
    692 }
    693 
    694 PassRefPtr<DocumentFragment> createFragmentFromMarkupWithContext(Document& document, const String& markup, unsigned fragmentStart, unsigned fragmentEnd,
    695     const String& baseURL, ParserContentPolicy parserContentPolicy)
    696 {
    697     // FIXME: Need to handle the case where the markup already contains these markers.
    698 
    699     StringBuilder taggedMarkup;
    700     taggedMarkup.append(markup.left(fragmentStart));
    701     MarkupAccumulator::appendComment(taggedMarkup, fragmentMarkerTag);
    702     taggedMarkup.append(markup.substring(fragmentStart, fragmentEnd - fragmentStart));
    703     MarkupAccumulator::appendComment(taggedMarkup, fragmentMarkerTag);
    704     taggedMarkup.append(markup.substring(fragmentEnd));
    705 
    706     RefPtr<DocumentFragment> taggedFragment = createFragmentFromMarkup(document, taggedMarkup.toString(), baseURL, parserContentPolicy);
    707     RefPtr<Document> taggedDocument = Document::create();
    708     taggedDocument->setContextFeatures(document.contextFeatures());
    709 
    710     // FIXME: It's not clear what this code is trying to do. It puts nodes as direct children of a
    711     // Document that are not normally allowed by using the parser machinery.
    712     taggedDocument->parserTakeAllChildrenFrom(*taggedFragment);
    713 
    714     RefPtr<Node> nodeBeforeContext;
    715     RefPtr<Node> nodeAfterContext;
    716     if (!findNodesSurroundingContext(taggedDocument.get(), nodeBeforeContext, nodeAfterContext))
    717         return 0;
    718 
    719     RefPtr<Range> range = Range::create(*taggedDocument.get(),
    720         positionAfterNode(nodeBeforeContext.get()).parentAnchoredEquivalent(),
    721         positionBeforeNode(nodeAfterContext.get()).parentAnchoredEquivalent());
    722 
    723     Node* commonAncestor = range->commonAncestorContainer(ASSERT_NO_EXCEPTION);
    724     Node* specialCommonAncestor = ancestorToRetainStructureAndAppearanceWithNoRenderer(commonAncestor);
    725 
    726     // When there's a special common ancestor outside of the fragment, we must include it as well to
    727     // preserve the structure and appearance of the fragment. For example, if the fragment contains
    728     // TD, we need to include the enclosing TABLE tag as well.
    729     RefPtr<DocumentFragment> fragment = DocumentFragment::create(document);
    730     if (specialCommonAncestor)
    731         fragment->appendChild(specialCommonAncestor);
    732     else
    733         fragment->parserTakeAllChildrenFrom(toContainerNode(*commonAncestor));
    734 
    735     trimFragment(fragment.get(), nodeBeforeContext.get(), nodeAfterContext.get());
    736 
    737     return fragment;
    738 }
    739 
    740 String createMarkup(const Node* node, EChildrenOnly childrenOnly, Vector<Node*>* nodes, EAbsoluteURLs shouldResolveURLs, Vector<QualifiedName>* tagNamesToSkip)
    741 {
    742     if (!node)
    743         return "";
    744 
    745     MarkupAccumulator accumulator(nodes, shouldResolveURLs);
    746     return accumulator.serializeNodes(const_cast<Node*>(node), childrenOnly, tagNamesToSkip);
    747 }
    748 
    749 static void fillContainerFromString(ContainerNode* paragraph, const String& string)
    750 {
    751     Document& document = paragraph->document();
    752 
    753     if (string.isEmpty()) {
    754         paragraph->appendChild(createBlockPlaceholderElement(document));
    755         return;
    756     }
    757 
    758     ASSERT(string.find('\n') == kNotFound);
    759 
    760     Vector<String> tabList;
    761     string.split('\t', true, tabList);
    762     String tabText = emptyString();
    763     bool first = true;
    764     size_t numEntries = tabList.size();
    765     for (size_t i = 0; i < numEntries; ++i) {
    766         const String& s = tabList[i];
    767 
    768         // append the non-tab textual part
    769         if (!s.isEmpty()) {
    770             if (!tabText.isEmpty()) {
    771                 paragraph->appendChild(createTabSpanElement(document, tabText));
    772                 tabText = emptyString();
    773             }
    774             RefPtr<Node> textNode = document.createTextNode(stringWithRebalancedWhitespace(s, first, i + 1 == numEntries));
    775             paragraph->appendChild(textNode.release());
    776         }
    777 
    778         // there is a tab after every entry, except the last entry
    779         // (if the last character is a tab, the list gets an extra empty entry)
    780         if (i + 1 != numEntries)
    781             tabText.append('\t');
    782         else if (!tabText.isEmpty())
    783             paragraph->appendChild(createTabSpanElement(document, tabText));
    784 
    785         first = false;
    786     }
    787 }
    788 
    789 bool isPlainTextMarkup(Node *node)
    790 {
    791     if (!node->isElementNode() || !node->hasTagName(divTag) || toElement(node)->hasAttributes())
    792         return false;
    793 
    794     if (node->childNodeCount() == 1 && (node->firstChild()->isTextNode() || (node->firstChild()->firstChild())))
    795         return true;
    796 
    797     return (node->childNodeCount() == 2 && isTabSpanTextNode(node->firstChild()->firstChild()) && node->firstChild()->nextSibling()->isTextNode());
    798 }
    799 
    800 static bool shouldPreserveNewline(const Range& range)
    801 {
    802     if (Node* node = range.firstNode()) {
    803         if (RenderObject* renderer = node->renderer())
    804             return renderer->style()->preserveNewline();
    805     }
    806 
    807     if (Node* node = range.startPosition().anchorNode()) {
    808         if (RenderObject* renderer = node->renderer())
    809             return renderer->style()->preserveNewline();
    810     }
    811 
    812     return false;
    813 }
    814 
    815 PassRefPtr<DocumentFragment> createFragmentFromText(Range* context, const String& text)
    816 {
    817     if (!context)
    818         return 0;
    819 
    820     Document& document = context->ownerDocument();
    821     RefPtr<DocumentFragment> fragment = document.createDocumentFragment();
    822 
    823     if (text.isEmpty())
    824         return fragment.release();
    825 
    826     String string = text;
    827     string.replace("\r\n", "\n");
    828     string.replace('\r', '\n');
    829 
    830     if (shouldPreserveNewline(*context)) {
    831         fragment->appendChild(document.createTextNode(string));
    832         if (string.endsWith('\n')) {
    833             RefPtr<Element> element = createBreakElement(document);
    834             element->setAttribute(classAttr, AppleInterchangeNewline);
    835             fragment->appendChild(element.release());
    836         }
    837         return fragment.release();
    838     }
    839 
    840     // A string with no newlines gets added inline, rather than being put into a paragraph.
    841     if (string.find('\n') == kNotFound) {
    842         fillContainerFromString(fragment.get(), string);
    843         return fragment.release();
    844     }
    845 
    846     // Break string into paragraphs. Extra line breaks turn into empty paragraphs.
    847     Node* blockNode = enclosingBlock(context->firstNode());
    848     Element* block = toElement(blockNode);
    849     bool useClonesOfEnclosingBlock = blockNode
    850         && blockNode->isElementNode()
    851         && !block->hasTagName(bodyTag)
    852         && !isHTMLHtmlElement(block)
    853         && block != editableRootForPosition(context->startPosition());
    854     bool useLineBreak = enclosingTextFormControl(context->startPosition());
    855 
    856     Vector<String> list;
    857     string.split('\n', true, list); // true gets us empty strings in the list
    858     size_t numLines = list.size();
    859     for (size_t i = 0; i < numLines; ++i) {
    860         const String& s = list[i];
    861 
    862         RefPtr<Element> element;
    863         if (s.isEmpty() && i + 1 == numLines) {
    864             // For last line, use the "magic BR" rather than a P.
    865             element = createBreakElement(document);
    866             element->setAttribute(classAttr, AppleInterchangeNewline);
    867         } else if (useLineBreak) {
    868             element = createBreakElement(document);
    869             fillContainerFromString(fragment.get(), s);
    870         } else {
    871             if (useClonesOfEnclosingBlock)
    872                 element = block->cloneElementWithoutChildren();
    873             else
    874                 element = createDefaultParagraphElement(document);
    875             fillContainerFromString(element.get(), s);
    876         }
    877         fragment->appendChild(element.release());
    878     }
    879     return fragment.release();
    880 }
    881 
    882 PassRefPtr<DocumentFragment> createFragmentFromNodes(Document *document, const Vector<Node*>& nodes)
    883 {
    884     if (!document)
    885         return 0;
    886 
    887     RefPtr<DocumentFragment> fragment = document->createDocumentFragment();
    888 
    889     size_t size = nodes.size();
    890     for (size_t i = 0; i < size; ++i) {
    891         RefPtr<Element> element = createDefaultParagraphElement(*document);
    892         element->appendChild(nodes[i]);
    893         fragment->appendChild(element.release());
    894     }
    895 
    896     return fragment.release();
    897 }
    898 
    899 String createFullMarkup(const Node* node)
    900 {
    901     if (!node)
    902         return String();
    903 
    904     Frame* frame = node->document().frame();
    905     if (!frame)
    906         return String();
    907 
    908     // FIXME: This is never "for interchange". Is that right?
    909     String markupString = createMarkup(node, IncludeNode, 0);
    910     Node::NodeType nodeType = node->nodeType();
    911     if (nodeType != Node::DOCUMENT_NODE && nodeType != Node::DOCUMENT_TYPE_NODE)
    912         markupString = frame->documentTypeString() + markupString;
    913 
    914     return markupString;
    915 }
    916 
    917 String createFullMarkup(const Range* range)
    918 {
    919     if (!range)
    920         return String();
    921 
    922     Node* node = range->startContainer();
    923     if (!node)
    924         return String();
    925 
    926     Frame* frame = node->document().frame();
    927     if (!frame)
    928         return String();
    929 
    930     // FIXME: This is always "for interchange". Is that right? See the previous method.
    931     return frame->documentTypeString() + createMarkup(range, 0, AnnotateForInterchange);
    932 }
    933 
    934 String urlToMarkup(const KURL& url, const String& title)
    935 {
    936     StringBuilder markup;
    937     markup.append("<a href=\"");
    938     markup.append(url.string());
    939     markup.append("\">");
    940     MarkupAccumulator::appendCharactersReplacingEntities(markup, title, 0, title.length(), EntityMaskInPCDATA);
    941     markup.append("</a>");
    942     return markup.toString();
    943 }
    944 
    945 PassRefPtr<DocumentFragment> createFragmentForInnerOuterHTML(const String& markup, Element* contextElement, ParserContentPolicy parserContentPolicy, const char* method, ExceptionState& exceptionState)
    946 {
    947     Document& document = contextElement->hasTagName(templateTag) ? contextElement->document().ensureTemplateDocument() : contextElement->document();
    948     RefPtr<DocumentFragment> fragment = DocumentFragment::create(document);
    949 
    950     if (document.isHTMLDocument()) {
    951         fragment->parseHTML(markup, contextElement, parserContentPolicy);
    952         return fragment;
    953     }
    954 
    955     bool wasValid = fragment->parseXML(markup, contextElement, parserContentPolicy);
    956     if (!wasValid) {
    957         exceptionState.throwDOMException(SyntaxError, "The provided markup is invalid XML, and therefore cannot be inserted into an XML document.");
    958         return 0;
    959     }
    960     return fragment.release();
    961 }
    962 
    963 PassRefPtr<DocumentFragment> createFragmentForTransformToFragment(const String& sourceString, const String& sourceMIMEType, Document& outputDoc)
    964 {
    965     RefPtr<DocumentFragment> fragment = outputDoc.createDocumentFragment();
    966 
    967     if (sourceMIMEType == "text/html") {
    968         // As far as I can tell, there isn't a spec for how transformToFragment is supposed to work.
    969         // Based on the documentation I can find, it looks like we want to start parsing the fragment in the InBody insertion mode.
    970         // Unfortunately, that's an implementation detail of the parser.
    971         // We achieve that effect here by passing in a fake body element as context for the fragment.
    972         RefPtr<HTMLBodyElement> fakeBody = HTMLBodyElement::create(outputDoc);
    973         fragment->parseHTML(sourceString, fakeBody.get());
    974     } else if (sourceMIMEType == "text/plain") {
    975         fragment->parserAppendChild(Text::create(outputDoc, sourceString));
    976     } else {
    977         bool successfulParse = fragment->parseXML(sourceString, 0);
    978         if (!successfulParse)
    979             return 0;
    980     }
    981 
    982     // FIXME: Do we need to mess with URLs here?
    983 
    984     return fragment.release();
    985 }
    986 
    987 static inline void removeElementPreservingChildren(PassRefPtr<DocumentFragment> fragment, HTMLElement* element)
    988 {
    989     RefPtr<Node> nextChild;
    990     for (RefPtr<Node> child = element->firstChild(); child; child = nextChild) {
    991         nextChild = child->nextSibling();
    992         element->removeChild(child.get());
    993         fragment->insertBefore(child, element);
    994     }
    995     fragment->removeChild(element);
    996 }
    997 
    998 PassRefPtr<DocumentFragment> createContextualFragment(const String& markup, HTMLElement* element, ParserContentPolicy parserContentPolicy, ExceptionState& exceptionState)
    999 {
   1000     ASSERT(element);
   1001     if (element->ieForbidsInsertHTML() || element->hasLocalName(colTag) || element->hasLocalName(colgroupTag) || element->hasLocalName(framesetTag)
   1002         || element->hasLocalName(headTag) || element->hasLocalName(styleTag) || element->hasLocalName(titleTag)) {
   1003         exceptionState.throwDOMException(NotSupportedError, "The range's container is '" + element->localName() + "', which is not supported.");
   1004         return 0;
   1005     }
   1006 
   1007     RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(markup, element, parserContentPolicy, "createContextualFragment", exceptionState);
   1008     if (!fragment)
   1009         return 0;
   1010 
   1011     // We need to pop <html> and <body> elements and remove <head> to
   1012     // accommodate folks passing complete HTML documents to make the
   1013     // child of an element.
   1014 
   1015     RefPtr<Node> nextNode;
   1016     for (RefPtr<Node> node = fragment->firstChild(); node; node = nextNode) {
   1017         nextNode = node->nextSibling();
   1018         if (isHTMLHtmlElement(node.get()) || node->hasTagName(headTag) || node->hasTagName(bodyTag)) {
   1019             HTMLElement* element = toHTMLElement(node);
   1020             if (Node* firstChild = element->firstChild())
   1021                 nextNode = firstChild;
   1022             removeElementPreservingChildren(fragment, element);
   1023         }
   1024     }
   1025     return fragment.release();
   1026 }
   1027 
   1028 void replaceChildrenWithFragment(ContainerNode* container, PassRefPtr<DocumentFragment> fragment, ExceptionState& exceptionState)
   1029 {
   1030     ASSERT(container);
   1031     RefPtr<ContainerNode> containerNode(container);
   1032 
   1033     ChildListMutationScope mutation(*containerNode);
   1034 
   1035     if (!fragment->firstChild()) {
   1036         containerNode->removeChildren();
   1037         return;
   1038     }
   1039 
   1040     if (containerNode->hasOneTextChild() && fragment->hasOneTextChild()) {
   1041         toText(containerNode->firstChild())->setData(toText(fragment->firstChild())->data());
   1042         return;
   1043     }
   1044 
   1045     if (containerNode->hasOneChild()) {
   1046         containerNode->replaceChild(fragment, containerNode->firstChild(), exceptionState);
   1047         return;
   1048     }
   1049 
   1050     containerNode->removeChildren();
   1051     containerNode->appendChild(fragment, exceptionState);
   1052 }
   1053 
   1054 void replaceChildrenWithText(ContainerNode* container, const String& text, ExceptionState& exceptionState)
   1055 {
   1056     ASSERT(container);
   1057     RefPtr<ContainerNode> containerNode(container);
   1058 
   1059     ChildListMutationScope mutation(*containerNode);
   1060 
   1061     if (containerNode->hasOneTextChild()) {
   1062         toText(containerNode->firstChild())->setData(text);
   1063         return;
   1064     }
   1065 
   1066     RefPtr<Text> textNode = Text::create(containerNode->document(), text);
   1067 
   1068     if (containerNode->hasOneChild()) {
   1069         containerNode->replaceChild(textNode.release(), containerNode->firstChild(), exceptionState);
   1070         return;
   1071     }
   1072 
   1073     containerNode->removeChildren();
   1074     containerNode->appendChild(textNode.release(), exceptionState);
   1075 }
   1076 
   1077 void mergeWithNextTextNode(PassRefPtr<Node> node, ExceptionState& exceptionState)
   1078 {
   1079     ASSERT(node && node->isTextNode());
   1080     Node* next = node->nextSibling();
   1081     if (!next || !next->isTextNode())
   1082         return;
   1083 
   1084     RefPtr<Text> textNode = toText(node.get());
   1085     RefPtr<Text> textNext = toText(next);
   1086     textNode->appendData(textNext->data());
   1087     if (textNext->parentNode()) // Might have been removed by mutation event.
   1088         textNext->remove(exceptionState);
   1089 }
   1090 
   1091 }
   1092