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