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