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/ExceptionCode.h"
     44 #include "core/dom/NodeTraversal.h"
     45 #include "core/dom/Range.h"
     46 #include "core/editing/Editor.h"
     47 #include "core/editing/MarkupAccumulator.h"
     48 #include "core/editing/TextIterator.h"
     49 #include "core/editing/VisibleSelection.h"
     50 #include "core/editing/VisibleUnits.h"
     51 #include "core/editing/htmlediting.h"
     52 #include "core/html/HTMLBodyElement.h"
     53 #include "core/html/HTMLElement.h"
     54 #include "core/html/HTMLHtmlElement.h"
     55 #include "core/html/HTMLTableElement.h"
     56 #include "core/html/HTMLTextFormControlElement.h"
     57 #include "core/page/Frame.h"
     58 #include "core/rendering/RenderObject.h"
     59 #include "weborigin/KURL.h"
     60 #include "wtf/StdLibExtras.h"
     61 #include "wtf/text/StringBuilder.h"
     62 
     63 using namespace std;
     64 
     65 namespace WebCore {
     66 
     67 using namespace HTMLNames;
     68 
     69 static bool propertyMissingOrEqualToNone(StylePropertySet*, CSSPropertyID);
     70 
     71 class AttributeChange {
     72 public:
     73     AttributeChange()
     74         : m_name(nullAtom, nullAtom, nullAtom)
     75     {
     76     }
     77 
     78     AttributeChange(PassRefPtr<Element> element, const QualifiedName& name, const String& value)
     79         : m_element(element), m_name(name), m_value(value)
     80     {
     81     }
     82 
     83     void apply()
     84     {
     85         m_element->setAttribute(m_name, m_value);
     86     }
     87 
     88 private:
     89     RefPtr<Element> m_element;
     90     QualifiedName m_name;
     91     String m_value;
     92 };
     93 
     94 static void completeURLs(DocumentFragment* fragment, const String& baseURL)
     95 {
     96     Vector<AttributeChange> changes;
     97 
     98     KURL parsedBaseURL(ParsedURLString, baseURL);
     99 
    100     for (Element* element = ElementTraversal::firstWithin(fragment); element; element = ElementTraversal::next(element, fragment)) {
    101         if (!element->hasAttributes())
    102             continue;
    103         unsigned length = element->attributeCount();
    104         for (unsigned i = 0; i < length; i++) {
    105             const Attribute* attribute = element->attributeItem(i);
    106             if (element->isURLAttribute(*attribute) && !attribute->value().isEmpty())
    107                 changes.append(AttributeChange(element, attribute->name(), KURL(parsedBaseURL, attribute->value()).string()));
    108         }
    109     }
    110 
    111     size_t numChanges = changes.size();
    112     for (size_t i = 0; i < numChanges; ++i)
    113         changes[i].apply();
    114 }
    115 
    116 class StyledMarkupAccumulator : public MarkupAccumulator {
    117 public:
    118     enum RangeFullySelectsNode { DoesFullySelectNode, DoesNotFullySelectNode };
    119 
    120     StyledMarkupAccumulator(Vector<Node*>* nodes, EAbsoluteURLs, EAnnotateForInterchange, const Range*, Node* highestNodeToBeSerialized = 0);
    121     Node* serializeNodes(Node* startNode, Node* pastEnd);
    122     virtual void appendString(const String& s) { return MarkupAccumulator::appendString(s); }
    123     void wrapWithNode(Node*, bool convertBlocksToInlines = false, RangeFullySelectsNode = DoesFullySelectNode);
    124     void wrapWithStyleNode(StylePropertySet*, Document*, bool isBlock = false);
    125     String takeResults();
    126 
    127 private:
    128     void appendStyleNodeOpenTag(StringBuilder&, StylePropertySet*, Document*, bool isBlock = false);
    129     const String& styleNodeCloseTag(bool isBlock = false);
    130     virtual void appendText(StringBuilder& out, Text*);
    131     String renderedText(const Node*, const Range*);
    132     String stringValueForRange(const Node*, const Range*);
    133     void appendElement(StringBuilder& out, Element*, bool addDisplayInline, RangeFullySelectsNode);
    134     void appendElement(StringBuilder& out, Element* element, Namespaces*) { appendElement(out, element, false, DoesFullySelectNode); }
    135 
    136     enum NodeTraversalMode { EmitString, DoNotEmitString };
    137     Node* traverseNodesForSerialization(Node* startNode, Node* pastEnd, NodeTraversalMode);
    138 
    139     bool shouldAnnotate() { return m_shouldAnnotate == AnnotateForInterchange; }
    140     bool shouldApplyWrappingStyle(Node* node) const
    141     {
    142         return m_highestNodeToBeSerialized && m_highestNodeToBeSerialized->parentNode() == node->parentNode()
    143             && m_wrappingStyle && m_wrappingStyle->style();
    144     }
    145 
    146     Vector<String> m_reversedPrecedingMarkup;
    147     const EAnnotateForInterchange m_shouldAnnotate;
    148     Node* m_highestNodeToBeSerialized;
    149     RefPtr<EditingStyle> m_wrappingStyle;
    150 };
    151 
    152 inline StyledMarkupAccumulator::StyledMarkupAccumulator(Vector<Node*>* nodes, EAbsoluteURLs shouldResolveURLs, EAnnotateForInterchange shouldAnnotate,
    153     const Range* range, Node* highestNodeToBeSerialized)
    154     : MarkupAccumulator(nodes, shouldResolveURLs, range)
    155     , m_shouldAnnotate(shouldAnnotate)
    156     , m_highestNodeToBeSerialized(highestNodeToBeSerialized)
    157 {
    158 }
    159 
    160 void StyledMarkupAccumulator::wrapWithNode(Node* node, bool convertBlocksToInlines, RangeFullySelectsNode rangeFullySelectsNode)
    161 {
    162     StringBuilder markup;
    163     if (node->isElementNode())
    164         appendElement(markup, toElement(node), convertBlocksToInlines && isBlock(const_cast<Node*>(node)), rangeFullySelectsNode);
    165     else
    166         appendStartMarkup(markup, node, 0);
    167     m_reversedPrecedingMarkup.append(markup.toString());
    168     appendEndTag(node);
    169     if (m_nodes)
    170         m_nodes->append(node);
    171 }
    172 
    173 void StyledMarkupAccumulator::wrapWithStyleNode(StylePropertySet* style, Document* document, bool isBlock)
    174 {
    175     StringBuilder openTag;
    176     appendStyleNodeOpenTag(openTag, style, document, isBlock);
    177     m_reversedPrecedingMarkup.append(openTag.toString());
    178     appendString(styleNodeCloseTag(isBlock));
    179 }
    180 
    181 void StyledMarkupAccumulator::appendStyleNodeOpenTag(StringBuilder& out, StylePropertySet* style, Document* document, bool isBlock)
    182 {
    183     // wrappingStyleForSerialization should have removed -webkit-text-decorations-in-effect
    184     ASSERT(propertyMissingOrEqualToNone(style, CSSPropertyWebkitTextDecorationsInEffect));
    185     if (isBlock)
    186         out.appendLiteral("<div style=\"");
    187     else
    188         out.appendLiteral("<span style=\"");
    189     appendAttributeValue(out, style->asText(), document->isHTMLDocument());
    190     out.append('\"');
    191     out.append('>');
    192 }
    193 
    194 const String& StyledMarkupAccumulator::styleNodeCloseTag(bool isBlock)
    195 {
    196     DEFINE_STATIC_LOCAL(const String, divClose, ("</div>"));
    197     DEFINE_STATIC_LOCAL(const String, styleSpanClose, ("</span>"));
    198     return isBlock ? divClose : styleSpanClose;
    199 }
    200 
    201 String StyledMarkupAccumulator::takeResults()
    202 {
    203     StringBuilder result;
    204     result.reserveCapacity(totalLength(m_reversedPrecedingMarkup) + length());
    205 
    206     for (size_t i = m_reversedPrecedingMarkup.size(); i > 0; --i)
    207         result.append(m_reversedPrecedingMarkup[i - 1]);
    208 
    209     concatenateMarkup(result);
    210 
    211     // We remove '\0' characters because they are not visibly rendered to the user.
    212     return result.toString().replace(0, "");
    213 }
    214 
    215 void StyledMarkupAccumulator::appendText(StringBuilder& out, Text* text)
    216 {
    217     const bool parentIsTextarea = text->parentElement() && text->parentElement()->tagQName() == textareaTag;
    218     const bool wrappingSpan = shouldApplyWrappingStyle(text) && !parentIsTextarea;
    219     if (wrappingSpan) {
    220         RefPtr<EditingStyle> wrappingStyle = m_wrappingStyle->copy();
    221         // FIXME: <rdar://problem/5371536> Style rules that match pasted content can change it's appearance
    222         // Make sure spans are inline style in paste side e.g. span { display: block }.
    223         wrappingStyle->forceInline();
    224         // FIXME: Should this be included in forceInline?
    225         wrappingStyle->style()->setProperty(CSSPropertyFloat, CSSValueNone);
    226 
    227         appendStyleNodeOpenTag(out, wrappingStyle->style(), text->document());
    228     }
    229 
    230     if (!shouldAnnotate() || parentIsTextarea)
    231         MarkupAccumulator::appendText(out, text);
    232     else {
    233         const bool useRenderedText = !enclosingNodeWithTag(firstPositionInNode(text), selectTag);
    234         String content = useRenderedText ? renderedText(text, m_range) : stringValueForRange(text, m_range);
    235         StringBuilder buffer;
    236         appendCharactersReplacingEntities(buffer, content, 0, content.length(), EntityMaskInPCDATA);
    237         out.append(convertHTMLTextToInterchangeFormat(buffer.toString(), text));
    238     }
    239 
    240     if (wrappingSpan)
    241         out.append(styleNodeCloseTag());
    242 }
    243 
    244 String StyledMarkupAccumulator::renderedText(const Node* node, const Range* range)
    245 {
    246     if (!node->isTextNode())
    247         return String();
    248 
    249     const Text* textNode = static_cast<const Text*>(node);
    250     unsigned startOffset = 0;
    251     unsigned endOffset = textNode->length();
    252 
    253     if (range && node == range->startContainer())
    254         startOffset = range->startOffset();
    255     if (range && node == range->endContainer())
    256         endOffset = range->endOffset();
    257 
    258     Position start = createLegacyEditingPosition(const_cast<Node*>(node), startOffset);
    259     Position end = createLegacyEditingPosition(const_cast<Node*>(node), endOffset);
    260     return plainText(Range::create(node->document(), start, end).get());
    261 }
    262 
    263 String StyledMarkupAccumulator::stringValueForRange(const Node* node, const Range* range)
    264 {
    265     if (!range)
    266         return node->nodeValue();
    267 
    268     String str = node->nodeValue();
    269     if (node == range->endContainer())
    270         str.truncate(range->endOffset());
    271     if (node == range->startContainer())
    272         str.remove(0, range->startOffset());
    273     return str;
    274 }
    275 
    276 void StyledMarkupAccumulator::appendElement(StringBuilder& out, Element* element, bool addDisplayInline, RangeFullySelectsNode rangeFullySelectsNode)
    277 {
    278     const bool documentIsHTML = element->document()->isHTMLDocument();
    279     appendOpenTag(out, element, 0);
    280 
    281     const unsigned length = element->hasAttributes() ? element->attributeCount() : 0;
    282     const bool shouldAnnotateOrForceInline = element->isHTMLElement() && (shouldAnnotate() || addDisplayInline);
    283     const bool shouldOverrideStyleAttr = shouldAnnotateOrForceInline || shouldApplyWrappingStyle(element);
    284     for (unsigned i = 0; i < length; ++i) {
    285         const Attribute* attribute = element->attributeItem(i);
    286         // We'll handle the style attribute separately, below.
    287         if (attribute->name() == styleAttr && shouldOverrideStyleAttr)
    288             continue;
    289         appendAttribute(out, element, *attribute, 0);
    290     }
    291 
    292     if (shouldOverrideStyleAttr) {
    293         RefPtr<EditingStyle> newInlineStyle;
    294 
    295         if (shouldApplyWrappingStyle(element)) {
    296             newInlineStyle = m_wrappingStyle->copy();
    297             newInlineStyle->removePropertiesInElementDefaultStyle(element);
    298             newInlineStyle->removeStyleConflictingWithStyleOfNode(element);
    299         } else
    300             newInlineStyle = EditingStyle::create();
    301 
    302         if (element->isStyledElement() && element->inlineStyle())
    303             newInlineStyle->overrideWithStyle(element->inlineStyle());
    304 
    305         if (shouldAnnotateOrForceInline) {
    306             if (shouldAnnotate())
    307                 newInlineStyle->mergeStyleFromRulesForSerialization(toHTMLElement(element));
    308 
    309             if (addDisplayInline)
    310                 newInlineStyle->forceInline();
    311 
    312             // 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
    313             // only the ones that affect it and the nodes within it.
    314             if (rangeFullySelectsNode == DoesNotFullySelectNode && newInlineStyle->style())
    315                 newInlineStyle->style()->removeProperty(CSSPropertyFloat);
    316         }
    317 
    318         if (!newInlineStyle->isEmpty()) {
    319             out.appendLiteral(" style=\"");
    320             appendAttributeValue(out, newInlineStyle->style()->asText(), documentIsHTML);
    321             out.append('\"');
    322         }
    323     }
    324 
    325     appendCloseTag(out, element);
    326 }
    327 
    328 Node* StyledMarkupAccumulator::serializeNodes(Node* startNode, Node* pastEnd)
    329 {
    330     if (!m_highestNodeToBeSerialized) {
    331         Node* lastClosed = traverseNodesForSerialization(startNode, pastEnd, DoNotEmitString);
    332         m_highestNodeToBeSerialized = lastClosed;
    333     }
    334 
    335     if (m_highestNodeToBeSerialized && m_highestNodeToBeSerialized->parentNode())
    336         m_wrappingStyle = EditingStyle::wrappingStyleForSerialization(m_highestNodeToBeSerialized->parentNode(), shouldAnnotate());
    337 
    338     return traverseNodesForSerialization(startNode, pastEnd, EmitString);
    339 }
    340 
    341 Node* StyledMarkupAccumulator::traverseNodesForSerialization(Node* startNode, Node* pastEnd, NodeTraversalMode traversalMode)
    342 {
    343     const bool shouldEmit = traversalMode == EmitString;
    344     Vector<Node*> ancestorsToClose;
    345     Node* next;
    346     Node* lastClosed = 0;
    347     for (Node* n = startNode; n != pastEnd; n = next) {
    348         // According to <rdar://problem/5730668>, it is possible for n to blow
    349         // past pastEnd and become null here. This shouldn't be possible.
    350         // This null check will prevent crashes (but create too much markup)
    351         // and the ASSERT will hopefully lead us to understanding the problem.
    352         ASSERT(n);
    353         if (!n)
    354             break;
    355 
    356         next = NodeTraversal::next(n);
    357         bool openedTag = false;
    358 
    359         if (isBlock(n) && canHaveChildrenForEditing(n) && next == pastEnd)
    360             // Don't write out empty block containers that aren't fully selected.
    361             continue;
    362 
    363         if (!n->renderer() && !enclosingNodeWithTag(firstPositionInOrBeforeNode(n), selectTag)) {
    364             next = NodeTraversal::nextSkippingChildren(n);
    365             // Don't skip over pastEnd.
    366             if (pastEnd && pastEnd->isDescendantOf(n))
    367                 next = pastEnd;
    368         } else {
    369             // Add the node to the markup if we're not skipping the descendants
    370             if (shouldEmit)
    371                 appendStartTag(n);
    372 
    373             // If node has no children, close the tag now.
    374             if (!n->childNodeCount()) {
    375                 if (shouldEmit)
    376                     appendEndTag(n);
    377                 lastClosed = n;
    378             } else {
    379                 openedTag = true;
    380                 ancestorsToClose.append(n);
    381             }
    382         }
    383 
    384         // 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.
    385         // FIXME: What happens if we just inserted open tag and reached the end?
    386         if (!openedTag && (!n->nextSibling() || next == pastEnd)) {
    387             // Close up the ancestors.
    388             while (!ancestorsToClose.isEmpty()) {
    389                 Node* ancestor = ancestorsToClose.last();
    390                 if (next != pastEnd && next->isDescendantOf(ancestor))
    391                     break;
    392                 // Not at the end of the range, close ancestors up to sibling of next node.
    393                 if (shouldEmit)
    394                     appendEndTag(ancestor);
    395                 lastClosed = ancestor;
    396                 ancestorsToClose.removeLast();
    397             }
    398 
    399             // Surround the currently accumulated markup with markup for ancestors we never opened as we leave the subtree(s) rooted at those ancestors.
    400             ContainerNode* nextParent = next ? next->parentNode() : 0;
    401             if (next != pastEnd && n != nextParent) {
    402                 Node* lastAncestorClosedOrSelf = n->isDescendantOf(lastClosed) ? lastClosed : n;
    403                 for (ContainerNode* parent = lastAncestorClosedOrSelf->parentNode(); parent && parent != nextParent; parent = parent->parentNode()) {
    404                     // All ancestors that aren't in the ancestorsToClose list should either be a) unrendered:
    405                     if (!parent->renderer())
    406                         continue;
    407                     // or b) ancestors that we never encountered during a pre-order traversal starting at startNode:
    408                     ASSERT(startNode->isDescendantOf(parent));
    409                     if (shouldEmit)
    410                         wrapWithNode(parent);
    411                     lastClosed = parent;
    412                 }
    413             }
    414         }
    415     }
    416 
    417     return lastClosed;
    418 }
    419 
    420 static bool isHTMLBlockElement(const Node* node)
    421 {
    422     return node->hasTagName(tdTag)
    423         || node->hasTagName(thTag)
    424         || isNonTableCellHTMLBlockElement(node);
    425 }
    426 
    427 static Node* ancestorToRetainStructureAndAppearanceForBlock(Node* commonAncestorBlock)
    428 {
    429     if (!commonAncestorBlock)
    430         return 0;
    431 
    432     if (commonAncestorBlock->hasTagName(tbodyTag) || commonAncestorBlock->hasTagName(trTag)) {
    433         ContainerNode* table = commonAncestorBlock->parentNode();
    434         while (table && !isHTMLTableElement(table))
    435             table = table->parentNode();
    436 
    437         return table;
    438     }
    439 
    440     if (isNonTableCellHTMLBlockElement(commonAncestorBlock))
    441         return commonAncestorBlock;
    442 
    443     return 0;
    444 }
    445 
    446 static inline Node* ancestorToRetainStructureAndAppearance(Node* commonAncestor)
    447 {
    448     return ancestorToRetainStructureAndAppearanceForBlock(enclosingBlock(commonAncestor));
    449 }
    450 
    451 static inline Node* ancestorToRetainStructureAndAppearanceWithNoRenderer(Node* commonAncestor)
    452 {
    453     Node* commonAncestorBlock = enclosingNodeOfType(firstPositionInOrBeforeNode(commonAncestor), isHTMLBlockElement);
    454     return ancestorToRetainStructureAndAppearanceForBlock(commonAncestorBlock);
    455 }
    456 
    457 static bool propertyMissingOrEqualToNone(StylePropertySet* style, CSSPropertyID propertyID)
    458 {
    459     if (!style)
    460         return false;
    461     RefPtr<CSSValue> value = style->getPropertyCSSValue(propertyID);
    462     if (!value)
    463         return true;
    464     if (!value->isPrimitiveValue())
    465         return false;
    466     return toCSSPrimitiveValue(value.get())->getValueID() == CSSValueNone;
    467 }
    468 
    469 static bool needInterchangeNewlineAfter(const VisiblePosition& v)
    470 {
    471     VisiblePosition next = v.next();
    472     Node* upstreamNode = next.deepEquivalent().upstream().deprecatedNode();
    473     Node* downstreamNode = v.deepEquivalent().downstream().deprecatedNode();
    474     // Add an interchange newline if a paragraph break is selected and a br won't already be added to the markup to represent it.
    475     return isEndOfParagraph(v) && isStartOfParagraph(next) && !(upstreamNode->hasTagName(brTag) && upstreamNode == downstreamNode);
    476 }
    477 
    478 static PassRefPtr<EditingStyle> styleFromMatchedRulesAndInlineDecl(const Node* node)
    479 {
    480     if (!node->isHTMLElement())
    481         return 0;
    482 
    483     // FIXME: Having to const_cast here is ugly, but it is quite a bit of work to untangle
    484     // the non-const-ness of styleFromMatchedRulesForElement.
    485     HTMLElement* element = const_cast<HTMLElement*>(static_cast<const HTMLElement*>(node));
    486     RefPtr<EditingStyle> style = EditingStyle::create(element->inlineStyle());
    487     style->mergeStyleFromRules(element);
    488     return style.release();
    489 }
    490 
    491 static bool isElementPresentational(const Node* node)
    492 {
    493     return node->hasTagName(uTag) || node->hasTagName(sTag) || node->hasTagName(strikeTag)
    494         || node->hasTagName(iTag) || node->hasTagName(emTag) || node->hasTagName(bTag) || node->hasTagName(strongTag);
    495 }
    496 
    497 static Node* highestAncestorToWrapMarkup(const Range* range, EAnnotateForInterchange shouldAnnotate, Node* constrainingAncestor)
    498 {
    499     Node* commonAncestor = range->commonAncestorContainer(IGNORE_EXCEPTION);
    500     ASSERT(commonAncestor);
    501     Node* specialCommonAncestor = 0;
    502     if (shouldAnnotate == AnnotateForInterchange) {
    503         // Include ancestors that aren't completely inside the range but are required to retain
    504         // the structure and appearance of the copied markup.
    505         specialCommonAncestor = ancestorToRetainStructureAndAppearance(commonAncestor);
    506 
    507         if (Node* parentListNode = enclosingNodeOfType(firstPositionInOrBeforeNode(range->firstNode()), isListItem)) {
    508             if (WebCore::areRangesEqual(VisibleSelection::selectionFromContentsOfNode(parentListNode).toNormalizedRange().get(), range)) {
    509                 specialCommonAncestor = parentListNode->parentNode();
    510                 while (specialCommonAncestor && !isListElement(specialCommonAncestor))
    511                     specialCommonAncestor = specialCommonAncestor->parentNode();
    512             }
    513         }
    514 
    515         // Retain the Mail quote level by including all ancestor mail block quotes.
    516         if (Node* highestMailBlockquote = highestEnclosingNodeOfType(firstPositionInOrBeforeNode(range->firstNode()), isMailBlockquote, CanCrossEditingBoundary))
    517             specialCommonAncestor = highestMailBlockquote;
    518     }
    519 
    520     Node* checkAncestor = specialCommonAncestor ? specialCommonAncestor : commonAncestor;
    521     if (checkAncestor->renderer()) {
    522         Node* newSpecialCommonAncestor = highestEnclosingNodeOfType(firstPositionInNode(checkAncestor), &isElementPresentational, CanCrossEditingBoundary, constrainingAncestor);
    523         if (newSpecialCommonAncestor)
    524             specialCommonAncestor = newSpecialCommonAncestor;
    525     }
    526 
    527     // If a single tab is selected, commonAncestor will be a text node inside a tab span.
    528     // If two or more tabs are selected, commonAncestor will be the tab span.
    529     // In either case, if there is a specialCommonAncestor already, it will necessarily be above
    530     // any tab span that needs to be included.
    531     if (!specialCommonAncestor && isTabSpanTextNode(commonAncestor))
    532         specialCommonAncestor = commonAncestor->parentNode();
    533     if (!specialCommonAncestor && isTabSpanNode(commonAncestor))
    534         specialCommonAncestor = commonAncestor;
    535 
    536     if (Node *enclosingAnchor = enclosingNodeWithTag(firstPositionInNode(specialCommonAncestor ? specialCommonAncestor : commonAncestor), aTag))
    537         specialCommonAncestor = enclosingAnchor;
    538 
    539     return specialCommonAncestor;
    540 }
    541 
    542 // FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForInterchange?
    543 // FIXME: At least, annotation and style info should probably not be included in range.markupString()
    544 static String createMarkupInternal(Document* document, const Range* range, const Range* updatedRange, Vector<Node*>* nodes,
    545     EAnnotateForInterchange shouldAnnotate, bool convertBlocksToInlines, EAbsoluteURLs shouldResolveURLs, Node* constrainingAncestor)
    546 {
    547     ASSERT(document);
    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     if (!document)
    637         return emptyString();
    638 
    639     const Range* updatedRange = range;
    640 
    641     return createMarkupInternal(document, range, updatedRange, nodes, shouldAnnotate, convertBlocksToInlines, shouldResolveURLs, constrainingAncestor);
    642 }
    643 
    644 PassRefPtr<DocumentFragment> createFragmentFromMarkup(Document* document, const String& markup, const String& baseURL, ParserContentPolicy parserContentPolicy)
    645 {
    646     // We use a fake body element here to trick the HTML parser to using the InBody insertion mode.
    647     RefPtr<HTMLBodyElement> fakeBody = HTMLBodyElement::create(document);
    648     RefPtr<DocumentFragment> fragment = DocumentFragment::create(document);
    649 
    650     fragment->parseHTML(markup, fakeBody.get(), parserContentPolicy);
    651 
    652     if (!baseURL.isEmpty() && baseURL != blankURL() && baseURL != document->baseURL())
    653         completeURLs(fragment.get(), baseURL);
    654 
    655     return fragment.release();
    656 }
    657 
    658 static const char fragmentMarkerTag[] = "webkit-fragment-marker";
    659 
    660 static bool findNodesSurroundingContext(Document* document, RefPtr<Node>& nodeBeforeContext, RefPtr<Node>& nodeAfterContext)
    661 {
    662     for (Node* node = document->firstChild(); node; node = NodeTraversal::next(node)) {
    663         if (node->nodeType() == Node::COMMENT_NODE && static_cast<CharacterData*>(node)->data() == fragmentMarkerTag) {
    664             if (!nodeBeforeContext)
    665                 nodeBeforeContext = node;
    666             else {
    667                 nodeAfterContext = node;
    668                 return true;
    669             }
    670         }
    671     }
    672     return false;
    673 }
    674 
    675 static void trimFragment(DocumentFragment* fragment, Node* nodeBeforeContext, Node* nodeAfterContext)
    676 {
    677     RefPtr<Node> next;
    678     for (RefPtr<Node> node = fragment->firstChild(); node; node = next) {
    679         if (nodeBeforeContext->isDescendantOf(node.get())) {
    680             next = NodeTraversal::next(node.get());
    681             continue;
    682         }
    683         next = NodeTraversal::nextSkippingChildren(node.get());
    684         ASSERT(!node->contains(nodeAfterContext));
    685         node->parentNode()->removeChild(node.get(), ASSERT_NO_EXCEPTION);
    686         if (nodeBeforeContext == node)
    687             break;
    688     }
    689 
    690     ASSERT(nodeAfterContext->parentNode());
    691     for (RefPtr<Node> node = nodeAfterContext; node; node = next) {
    692         next = NodeTraversal::nextSkippingChildren(node.get());
    693         node->parentNode()->removeChild(node.get(), ASSERT_NO_EXCEPTION);
    694     }
    695 }
    696 
    697 PassRefPtr<DocumentFragment> createFragmentFromMarkupWithContext(Document* document, const String& markup, unsigned fragmentStart, unsigned fragmentEnd,
    698     const String& baseURL, ParserContentPolicy parserContentPolicy)
    699 {
    700     // FIXME: Need to handle the case where the markup already contains these markers.
    701 
    702     StringBuilder taggedMarkup;
    703     taggedMarkup.append(markup.left(fragmentStart));
    704     MarkupAccumulator::appendComment(taggedMarkup, fragmentMarkerTag);
    705     taggedMarkup.append(markup.substring(fragmentStart, fragmentEnd - fragmentStart));
    706     MarkupAccumulator::appendComment(taggedMarkup, fragmentMarkerTag);
    707     taggedMarkup.append(markup.substring(fragmentEnd));
    708 
    709     RefPtr<DocumentFragment> taggedFragment = createFragmentFromMarkup(document, taggedMarkup.toString(), baseURL, parserContentPolicy);
    710     RefPtr<Document> taggedDocument = Document::create();
    711     taggedDocument->setContextFeatures(document->contextFeatures());
    712     taggedDocument->takeAllChildrenFrom(taggedFragment.get());
    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, ASSERT_NO_EXCEPTION);
    732     else
    733         fragment->takeAllChildrenFrom(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), ASSERT_NO_EXCEPTION);
    755         return;
    756     }
    757 
    758     ASSERT(string.find('\n') == notFound);
    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), ASSERT_NO_EXCEPTION);
    772                 tabText = emptyString();
    773             }
    774             RefPtr<Node> textNode = document->createTextNode(stringWithRebalancedWhitespace(s, first, i + 1 == numEntries));
    775             paragraph->appendChild(textNode.release(), ASSERT_NO_EXCEPTION);
    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), ASSERT_NO_EXCEPTION);
    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), ASSERT_NO_EXCEPTION);
    832         if (string.endsWith('\n')) {
    833             RefPtr<Element> element = createBreakElement(document);
    834             element->setAttribute(classAttr, AppleInterchangeNewline);
    835             fragment->appendChild(element.release(), ASSERT_NO_EXCEPTION);
    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') == notFound) {
    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(), ASSERT_NO_EXCEPTION);
    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], ASSERT_NO_EXCEPTION);
    893         fragment->appendChild(element.release(), ASSERT_NO_EXCEPTION);
    894     }
    895 
    896     return fragment.release();
    897 }
    898 
    899 String createFullMarkup(const Node* node)
    900 {
    901     if (!node)
    902         return String();
    903 
    904     Document* document = node->document();
    905     if (!document)
    906         return String();
    907 
    908     Frame* frame = document->frame();
    909     if (!frame)
    910         return String();
    911 
    912     // FIXME: This is never "for interchange". Is that right?
    913     String markupString = createMarkup(node, IncludeNode, 0);
    914     Node::NodeType nodeType = node->nodeType();
    915     if (nodeType != Node::DOCUMENT_NODE && nodeType != Node::DOCUMENT_TYPE_NODE)
    916         markupString = frame->documentTypeString() + markupString;
    917 
    918     return markupString;
    919 }
    920 
    921 String createFullMarkup(const Range* range)
    922 {
    923     if (!range)
    924         return String();
    925 
    926     Node* node = range->startContainer();
    927     if (!node)
    928         return String();
    929 
    930     Document* document = node->document();
    931     if (!document)
    932         return String();
    933 
    934     Frame* frame = document->frame();
    935     if (!frame)
    936         return String();
    937 
    938     // FIXME: This is always "for interchange". Is that right? See the previous method.
    939     return frame->documentTypeString() + createMarkup(range, 0, AnnotateForInterchange);
    940 }
    941 
    942 String urlToMarkup(const KURL& url, const String& title)
    943 {
    944     StringBuilder markup;
    945     markup.append("<a href=\"");
    946     markup.append(url.string());
    947     markup.append("\">");
    948     MarkupAccumulator::appendCharactersReplacingEntities(markup, title, 0, title.length(), EntityMaskInPCDATA);
    949     markup.append("</a>");
    950     return markup.toString();
    951 }
    952 
    953 PassRefPtr<DocumentFragment> createFragmentForInnerOuterHTML(const String& markup, Element* contextElement, ParserContentPolicy parserContentPolicy, ExceptionState& es)
    954 {
    955     Document* document = contextElement->hasTagName(templateTag) ? contextElement->document()->ensureTemplateDocument() : contextElement->document();
    956     RefPtr<DocumentFragment> fragment = DocumentFragment::create(document);
    957 
    958     if (document->isHTMLDocument()) {
    959         fragment->parseHTML(markup, contextElement, parserContentPolicy);
    960         return fragment;
    961     }
    962 
    963     bool wasValid = fragment->parseXML(markup, contextElement, parserContentPolicy);
    964     if (!wasValid) {
    965         es.throwDOMException(SyntaxError);
    966         return 0;
    967     }
    968     return fragment.release();
    969 }
    970 
    971 PassRefPtr<DocumentFragment> createFragmentForTransformToFragment(const String& sourceString, const String& sourceMIMEType, Document* outputDoc)
    972 {
    973     RefPtr<DocumentFragment> fragment = outputDoc->createDocumentFragment();
    974 
    975     if (sourceMIMEType == "text/html") {
    976         // As far as I can tell, there isn't a spec for how transformToFragment is supposed to work.
    977         // Based on the documentation I can find, it looks like we want to start parsing the fragment in the InBody insertion mode.
    978         // Unfortunately, that's an implementation detail of the parser.
    979         // We achieve that effect here by passing in a fake body element as context for the fragment.
    980         RefPtr<HTMLBodyElement> fakeBody = HTMLBodyElement::create(outputDoc);
    981         fragment->parseHTML(sourceString, fakeBody.get());
    982     } else if (sourceMIMEType == "text/plain")
    983         fragment->parserAppendChild(Text::create(outputDoc, sourceString));
    984     else {
    985         bool successfulParse = fragment->parseXML(sourceString, 0);
    986         if (!successfulParse)
    987             return 0;
    988     }
    989 
    990     // FIXME: Do we need to mess with URLs here?
    991 
    992     return fragment.release();
    993 }
    994 
    995 static inline void removeElementPreservingChildren(PassRefPtr<DocumentFragment> fragment, HTMLElement* element)
    996 {
    997     RefPtr<Node> nextChild;
    998     for (RefPtr<Node> child = element->firstChild(); child; child = nextChild) {
    999         nextChild = child->nextSibling();
   1000         element->removeChild(child.get(), ASSERT_NO_EXCEPTION);
   1001         fragment->insertBefore(child, element, ASSERT_NO_EXCEPTION);
   1002     }
   1003     fragment->removeChild(element, ASSERT_NO_EXCEPTION);
   1004 }
   1005 
   1006 PassRefPtr<DocumentFragment> createContextualFragment(const String& markup, HTMLElement* element, ParserContentPolicy parserContentPolicy, ExceptionState& es)
   1007 {
   1008     ASSERT(element);
   1009     if (element->ieForbidsInsertHTML()) {
   1010         es.throwDOMException(NotSupportedError);
   1011         return 0;
   1012     }
   1013 
   1014     if (element->hasLocalName(colTag) || element->hasLocalName(colgroupTag) || element->hasLocalName(framesetTag)
   1015         || element->hasLocalName(headTag) || element->hasLocalName(styleTag) || element->hasLocalName(titleTag)) {
   1016         es.throwDOMException(NotSupportedError);
   1017         return 0;
   1018     }
   1019 
   1020     RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(markup, element, parserContentPolicy, es);
   1021     if (!fragment)
   1022         return 0;
   1023 
   1024     // We need to pop <html> and <body> elements and remove <head> to
   1025     // accommodate folks passing complete HTML documents to make the
   1026     // child of an element.
   1027 
   1028     RefPtr<Node> nextNode;
   1029     for (RefPtr<Node> node = fragment->firstChild(); node; node = nextNode) {
   1030         nextNode = node->nextSibling();
   1031         if (isHTMLHtmlElement(node.get()) || node->hasTagName(headTag) || node->hasTagName(bodyTag)) {
   1032             HTMLElement* element = toHTMLElement(node.get());
   1033             if (Node* firstChild = element->firstChild())
   1034                 nextNode = firstChild;
   1035             removeElementPreservingChildren(fragment, element);
   1036         }
   1037     }
   1038     return fragment.release();
   1039 }
   1040 
   1041 static inline bool hasOneChild(ContainerNode* node)
   1042 {
   1043     Node* firstChild = node->firstChild();
   1044     return firstChild && !firstChild->nextSibling();
   1045 }
   1046 
   1047 static inline bool hasOneTextChild(ContainerNode* node)
   1048 {
   1049     return hasOneChild(node) && node->firstChild()->isTextNode();
   1050 }
   1051 
   1052 void replaceChildrenWithFragment(ContainerNode* container, PassRefPtr<DocumentFragment> fragment, ExceptionState& es)
   1053 {
   1054     RefPtr<ContainerNode> containerNode(container);
   1055 
   1056     ChildListMutationScope mutation(containerNode.get());
   1057 
   1058     if (!fragment->firstChild()) {
   1059         containerNode->removeChildren();
   1060         return;
   1061     }
   1062 
   1063     if (hasOneTextChild(containerNode.get()) && hasOneTextChild(fragment.get())) {
   1064         toText(containerNode->firstChild())->setData(toText(fragment->firstChild())->data());
   1065         return;
   1066     }
   1067 
   1068     if (hasOneChild(containerNode.get())) {
   1069         containerNode->replaceChild(fragment, containerNode->firstChild(), es);
   1070         return;
   1071     }
   1072 
   1073     containerNode->removeChildren();
   1074     containerNode->appendChild(fragment, es);
   1075 }
   1076 
   1077 void replaceChildrenWithText(ContainerNode* container, const String& text, ExceptionState& es)
   1078 {
   1079     RefPtr<ContainerNode> containerNode(container);
   1080 
   1081     ChildListMutationScope mutation(containerNode.get());
   1082 
   1083     if (hasOneTextChild(containerNode.get())) {
   1084         toText(containerNode->firstChild())->setData(text);
   1085         return;
   1086     }
   1087 
   1088     RefPtr<Text> textNode = Text::create(containerNode->document(), text);
   1089 
   1090     if (hasOneChild(containerNode.get())) {
   1091         containerNode->replaceChild(textNode.release(), containerNode->firstChild(), es);
   1092         return;
   1093     }
   1094 
   1095     containerNode->removeChildren();
   1096     containerNode->appendChild(textNode.release(), es);
   1097 }
   1098 
   1099 }
   1100