Home | History | Annotate | Download | only in editing
      1 /*
      2  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "markup.h"
     28 
     29 #include "CDATASection.h"
     30 #include "CSSComputedStyleDeclaration.h"
     31 #include "CSSMutableStyleDeclaration.h"
     32 #include "CSSPrimitiveValue.h"
     33 #include "CSSProperty.h"
     34 #include "CSSPropertyNames.h"
     35 #include "CSSRule.h"
     36 #include "CSSRuleList.h"
     37 #include "CSSStyleRule.h"
     38 #include "CSSStyleSelector.h"
     39 #include "CSSValue.h"
     40 #include "CSSValueKeywords.h"
     41 #include "DeleteButtonController.h"
     42 #include "DocumentFragment.h"
     43 #include "DocumentType.h"
     44 #include "Editor.h"
     45 #include "Frame.h"
     46 #include "HTMLBodyElement.h"
     47 #include "HTMLElement.h"
     48 #include "HTMLNames.h"
     49 #include "KURL.h"
     50 #include "MarkupAccumulator.h"
     51 #include "Range.h"
     52 #include "TextIterator.h"
     53 #include "VisibleSelection.h"
     54 #include "XMLNSNames.h"
     55 #include "htmlediting.h"
     56 #include "visible_units.h"
     57 #include <wtf/StdLibExtras.h>
     58 #include <wtf/unicode/CharacterNames.h>
     59 
     60 using namespace std;
     61 
     62 namespace WebCore {
     63 
     64 using namespace HTMLNames;
     65 
     66 static bool propertyMissingOrEqualToNone(CSSStyleDeclaration*, int propertyID);
     67 
     68 class AttributeChange {
     69 public:
     70     AttributeChange()
     71         : m_name(nullAtom, nullAtom, nullAtom)
     72     {
     73     }
     74 
     75     AttributeChange(PassRefPtr<Element> element, const QualifiedName& name, const String& value)
     76         : m_element(element), m_name(name), m_value(value)
     77     {
     78     }
     79 
     80     void apply()
     81     {
     82         m_element->setAttribute(m_name, m_value);
     83     }
     84 
     85 private:
     86     RefPtr<Element> m_element;
     87     QualifiedName m_name;
     88     String m_value;
     89 };
     90 
     91 static void completeURLs(Node* node, const String& baseURL)
     92 {
     93     Vector<AttributeChange> changes;
     94 
     95     KURL parsedBaseURL(ParsedURLString, baseURL);
     96 
     97     Node* end = node->traverseNextSibling();
     98     for (Node* n = node; n != end; n = n->traverseNextNode()) {
     99         if (n->isElementNode()) {
    100             Element* e = static_cast<Element*>(n);
    101             NamedNodeMap* attributes = e->attributes();
    102             unsigned length = attributes->length();
    103             for (unsigned i = 0; i < length; i++) {
    104                 Attribute* attribute = attributes->attributeItem(i);
    105                 if (e->isURLAttribute(attribute))
    106                     changes.append(AttributeChange(e, attribute->name(), KURL(parsedBaseURL, attribute->value()).string()));
    107             }
    108         }
    109     }
    110 
    111     size_t numChanges = changes.size();
    112     for (size_t i = 0; i < numChanges; ++i)
    113         changes[i].apply();
    114 }
    115 
    116 class StyledMarkupAccumulator : public MarkupAccumulator {
    117 public:
    118     enum RangeFullySelectsNode { DoesFullySelectNode, DoesNotFullySelectNode };
    119 
    120     StyledMarkupAccumulator(Vector<Node*>* nodes, EAbsoluteURLs shouldResolveURLs, EAnnotateForInterchange shouldAnnotate, const Range* range)
    121     : MarkupAccumulator(nodes, shouldResolveURLs, range)
    122     , m_shouldAnnotate(shouldAnnotate)
    123     {
    124     }
    125 
    126     Node* serializeNodes(Node* startNode, Node* pastEnd);
    127     virtual void appendString(const String& s) { return MarkupAccumulator::appendString(s); }
    128     void wrapWithNode(Node*, bool convertBlocksToInlines = false, RangeFullySelectsNode = DoesFullySelectNode);
    129     void wrapWithStyleNode(CSSStyleDeclaration*, Document*, bool isBlock = false);
    130     String takeResults();
    131 
    132 private:
    133     virtual void appendText(Vector<UChar>& out, Text*);
    134     String renderedText(const Node*, const Range*);
    135     String stringValueForRange(const Node*, const Range*);
    136     void removeExteriorStyles(CSSMutableStyleDeclaration*);
    137     void appendElement(Vector<UChar>& out, Element* element, bool addDisplayInline, RangeFullySelectsNode);
    138     void appendElement(Vector<UChar>& out, Element* element, Namespaces*) { appendElement(out, element, false, DoesFullySelectNode); }
    139 
    140     bool shouldAnnotate() { return m_shouldAnnotate == AnnotateForInterchange; }
    141 
    142     Vector<String> m_reversedPrecedingMarkup;
    143     const EAnnotateForInterchange m_shouldAnnotate;
    144 };
    145 
    146 void StyledMarkupAccumulator::wrapWithNode(Node* node, bool convertBlocksToInlines, RangeFullySelectsNode rangeFullySelectsNode)
    147 {
    148     Vector<UChar> markup;
    149     if (node->isElementNode())
    150         appendElement(markup, static_cast<Element*>(node), convertBlocksToInlines && isBlock(const_cast<Node*>(node)), rangeFullySelectsNode);
    151     else
    152         appendStartMarkup(markup, node, 0);
    153     m_reversedPrecedingMarkup.append(String::adopt(markup));
    154     appendEndTag(node);
    155     if (m_nodes)
    156         m_nodes->append(node);
    157 }
    158 
    159 void StyledMarkupAccumulator::wrapWithStyleNode(CSSStyleDeclaration* style, Document* document, bool isBlock)
    160 {
    161     // All text-decoration-related elements should have been treated as special ancestors
    162     // If we ever hit this ASSERT, we should export StyleChange in ApplyStyleCommand and use it here
    163     ASSERT(propertyMissingOrEqualToNone(style, CSSPropertyTextDecoration) && propertyMissingOrEqualToNone(style, CSSPropertyWebkitTextDecorationsInEffect));
    164     DEFINE_STATIC_LOCAL(const String, divStyle, ("<div style=\""));
    165     DEFINE_STATIC_LOCAL(const String, divClose, ("</div>"));
    166     DEFINE_STATIC_LOCAL(const String, styleSpanOpen, ("<span class=\"" AppleStyleSpanClass "\" style=\""));
    167     DEFINE_STATIC_LOCAL(const String, styleSpanClose, ("</span>"));
    168     Vector<UChar> openTag;
    169     append(openTag, isBlock ? divStyle : styleSpanOpen);
    170     appendAttributeValue(openTag, style->cssText(), document->isHTMLDocument());
    171     openTag.append('\"');
    172     openTag.append('>');
    173     m_reversedPrecedingMarkup.append(String::adopt(openTag));
    174     appendString(isBlock ? divClose : styleSpanClose);
    175 }
    176 
    177 String StyledMarkupAccumulator::takeResults()
    178 {
    179     Vector<UChar> result;
    180     result.reserveInitialCapacity(totalLength(m_reversedPrecedingMarkup) + length());
    181 
    182     for (size_t i = m_reversedPrecedingMarkup.size(); i > 0; --i)
    183         append(result, m_reversedPrecedingMarkup[i - 1]);
    184 
    185     concatenateMarkup(result);
    186 
    187     // We remove '\0' characters because they are not visibly rendered to the user.
    188     return String::adopt(result).replace(0, "");
    189 }
    190 
    191 void StyledMarkupAccumulator::appendText(Vector<UChar>& out, Text* text)
    192 {
    193     if (!shouldAnnotate() || (text->parentElement() && text->parentElement()->tagQName() == textareaTag)) {
    194         MarkupAccumulator::appendText(out, text);
    195         return;
    196     }
    197 
    198     bool useRenderedText = !enclosingNodeWithTag(firstPositionInNode(text), selectTag);
    199     String content = useRenderedText ? renderedText(text, m_range) : stringValueForRange(text, m_range);
    200     Vector<UChar> buffer;
    201     appendCharactersReplacingEntities(buffer, content.characters(), content.length(), EntityMaskInPCDATA);
    202     append(out, convertHTMLTextToInterchangeFormat(String::adopt(buffer), text));
    203 }
    204 
    205 String StyledMarkupAccumulator::renderedText(const Node* node, const Range* range)
    206 {
    207     if (!node->isTextNode())
    208         return String();
    209 
    210     ExceptionCode ec;
    211     const Text* textNode = static_cast<const Text*>(node);
    212     unsigned startOffset = 0;
    213     unsigned endOffset = textNode->length();
    214 
    215     if (range && node == range->startContainer(ec))
    216         startOffset = range->startOffset(ec);
    217     if (range && node == range->endContainer(ec))
    218         endOffset = range->endOffset(ec);
    219 
    220     Position start(const_cast<Node*>(node), startOffset);
    221     Position end(const_cast<Node*>(node), endOffset);
    222     return plainText(Range::create(node->document(), start, end).get());
    223 }
    224 
    225 String StyledMarkupAccumulator::stringValueForRange(const Node* node, const Range* range)
    226 {
    227     if (!range)
    228         return node->nodeValue();
    229 
    230     String str = node->nodeValue();
    231     ExceptionCode ec;
    232     if (node == range->endContainer(ec))
    233         str.truncate(range->endOffset(ec));
    234     if (node == range->startContainer(ec))
    235         str.remove(0, range->startOffset(ec));
    236     return str;
    237 }
    238 
    239 static PassRefPtr<CSSMutableStyleDeclaration> styleFromMatchedRulesForElement(Element* element, bool authorOnly = true)
    240 {
    241     RefPtr<CSSMutableStyleDeclaration> style = CSSMutableStyleDeclaration::create();
    242     RefPtr<CSSRuleList> matchedRules = element->document()->styleSelector()->styleRulesForElement(element, authorOnly);
    243     if (matchedRules) {
    244         for (unsigned i = 0; i < matchedRules->length(); i++) {
    245             if (matchedRules->item(i)->type() == CSSRule::STYLE_RULE) {
    246                 RefPtr<CSSMutableStyleDeclaration> s = static_cast<CSSStyleRule*>(matchedRules->item(i))->style();
    247                 style->merge(s.get(), true);
    248             }
    249         }
    250     }
    251 
    252     return style.release();
    253 }
    254 
    255 void StyledMarkupAccumulator::appendElement(Vector<UChar>& out, Element* element, bool addDisplayInline, RangeFullySelectsNode rangeFullySelectsNode)
    256 {
    257     bool documentIsHTML = element->document()->isHTMLDocument();
    258     appendOpenTag(out, element, 0);
    259 
    260     NamedNodeMap* attributes = element->attributes();
    261     unsigned length = attributes->length();
    262     for (unsigned int i = 0; i < length; i++) {
    263         Attribute* attribute = attributes->attributeItem(i);
    264         // We'll handle the style attribute separately, below.
    265         if (attribute->name() == styleAttr && element->isHTMLElement() && (shouldAnnotate() || addDisplayInline))
    266             continue;
    267         appendAttribute(out, element, *attribute, 0);
    268     }
    269 
    270     if (element->isHTMLElement() && (shouldAnnotate() || addDisplayInline)) {
    271         RefPtr<CSSMutableStyleDeclaration> style = toHTMLElement(element)->getInlineStyleDecl()->copy();
    272         if (shouldAnnotate()) {
    273             RefPtr<CSSMutableStyleDeclaration> styleFromMatchedRules = styleFromMatchedRulesForElement(const_cast<Element*>(element));
    274             // Styles from the inline style declaration, held in the variable "style", take precedence
    275             // over those from matched rules.
    276             styleFromMatchedRules->merge(style.get());
    277             style = styleFromMatchedRules;
    278 
    279             RefPtr<CSSComputedStyleDeclaration> computedStyleForElement = computedStyle(element);
    280             RefPtr<CSSMutableStyleDeclaration> fromComputedStyle = CSSMutableStyleDeclaration::create();
    281 
    282             {
    283                 CSSMutableStyleDeclaration::const_iterator end = style->end();
    284                 for (CSSMutableStyleDeclaration::const_iterator it = style->begin(); it != end; ++it) {
    285                     const CSSProperty& property = *it;
    286                     CSSValue* value = property.value();
    287                     // The property value, if it's a percentage, may not reflect the actual computed value.
    288                     // For example: style="height: 1%; overflow: visible;" in quirksmode
    289                     // FIXME: There are others like this, see <rdar://problem/5195123> Slashdot copy/paste fidelity problem
    290                     if (value->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE)
    291                         if (static_cast<CSSPrimitiveValue*>(value)->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE)
    292                             if (RefPtr<CSSValue> computedPropertyValue = computedStyleForElement->getPropertyCSSValue(property.id()))
    293                                 fromComputedStyle->addParsedProperty(CSSProperty(property.id(), computedPropertyValue));
    294                 }
    295             }
    296             style->merge(fromComputedStyle.get());
    297         }
    298         if (addDisplayInline)
    299             style->setProperty(CSSPropertyDisplay, CSSValueInline, true);
    300         // 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
    301         // only the ones that affect it and the nodes within it.
    302         if (rangeFullySelectsNode == DoesNotFullySelectNode)
    303             removeExteriorStyles(style.get());
    304         if (style->length() > 0) {
    305             DEFINE_STATIC_LOCAL(const String, stylePrefix, (" style=\""));
    306             append(out, stylePrefix);
    307             appendAttributeValue(out, style->cssText(), documentIsHTML);
    308             out.append('\"');
    309         }
    310     }
    311 
    312     appendCloseTag(out, element);
    313 }
    314 
    315 void StyledMarkupAccumulator::removeExteriorStyles(CSSMutableStyleDeclaration* style)
    316 {
    317     style->removeProperty(CSSPropertyFloat);
    318 }
    319 
    320 Node* StyledMarkupAccumulator::serializeNodes(Node* startNode, Node* pastEnd)
    321 {
    322     Vector<Node*> ancestorsToClose;
    323     Node* next;
    324     Node* lastClosed = 0;
    325     for (Node* n = startNode; n != pastEnd; n = next) {
    326         // According to <rdar://problem/5730668>, it is possible for n to blow
    327         // past pastEnd and become null here. This shouldn't be possible.
    328         // This null check will prevent crashes (but create too much markup)
    329         // and the ASSERT will hopefully lead us to understanding the problem.
    330         ASSERT(n);
    331         if (!n)
    332             break;
    333 
    334         next = n->traverseNextNode();
    335         bool openedTag = false;
    336 
    337         if (isBlock(n) && canHaveChildrenForEditing(n) && next == pastEnd)
    338             // Don't write out empty block containers that aren't fully selected.
    339             continue;
    340 
    341         if (!n->renderer() && !enclosingNodeWithTag(firstPositionInOrBeforeNode(n), selectTag)) {
    342             next = n->traverseNextSibling();
    343             // Don't skip over pastEnd.
    344             if (pastEnd && pastEnd->isDescendantOf(n))
    345                 next = pastEnd;
    346         } else {
    347             // Add the node to the markup if we're not skipping the descendants
    348             appendStartTag(n);
    349 
    350             // If node has no children, close the tag now.
    351             if (!n->childNodeCount()) {
    352                 appendEndTag(n);
    353                 lastClosed = n;
    354             } else {
    355                 openedTag = true;
    356                 ancestorsToClose.append(n);
    357             }
    358         }
    359 
    360         // 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.
    361         // FIXME: What happens if we just inserted open tag and reached the end?
    362         if (!openedTag && (!n->nextSibling() || next == pastEnd)) {
    363             // Close up the ancestors.
    364             while (!ancestorsToClose.isEmpty()) {
    365                 Node* ancestor = ancestorsToClose.last();
    366                 if (next != pastEnd && next->isDescendantOf(ancestor))
    367                     break;
    368                 // Not at the end of the range, close ancestors up to sibling of next node.
    369                 appendEndTag(ancestor);
    370                 lastClosed = ancestor;
    371                 ancestorsToClose.removeLast();
    372             }
    373 
    374             // Surround the currently accumulated markup with markup for ancestors we never opened as we leave the subtree(s) rooted at those ancestors.
    375             ContainerNode* nextParent = next ? next->parentNode() : 0;
    376             if (next != pastEnd && n != nextParent) {
    377                 Node* lastAncestorClosedOrSelf = n->isDescendantOf(lastClosed) ? lastClosed : n;
    378                 for (ContainerNode* parent = lastAncestorClosedOrSelf->parentNode(); parent && parent != nextParent; parent = parent->parentNode()) {
    379                     // All ancestors that aren't in the ancestorsToClose list should either be a) unrendered:
    380                     if (!parent->renderer())
    381                         continue;
    382                     // or b) ancestors that we never encountered during a pre-order traversal starting at startNode:
    383                     ASSERT(startNode->isDescendantOf(parent));
    384                     wrapWithNode(parent);
    385                     lastClosed = parent;
    386                 }
    387             }
    388         }
    389     }
    390 
    391     return lastClosed;
    392 }
    393 
    394 static Node* ancestorToRetainStructureAndAppearance(Node* commonAncestor)
    395 {
    396     Node* commonAncestorBlock = enclosingBlock(commonAncestor);
    397 
    398     if (!commonAncestorBlock)
    399         return 0;
    400 
    401     if (commonAncestorBlock->hasTagName(tbodyTag) || commonAncestorBlock->hasTagName(trTag)) {
    402         ContainerNode* table = commonAncestorBlock->parentNode();
    403         while (table && !table->hasTagName(tableTag))
    404             table = table->parentNode();
    405 
    406         return table;
    407     }
    408 
    409     if (commonAncestorBlock->hasTagName(listingTag)
    410         || commonAncestorBlock->hasTagName(olTag)
    411         || commonAncestorBlock->hasTagName(preTag)
    412         || commonAncestorBlock->hasTagName(tableTag)
    413         || commonAncestorBlock->hasTagName(ulTag)
    414         || commonAncestorBlock->hasTagName(xmpTag)
    415         || commonAncestorBlock->hasTagName(h1Tag)
    416         || commonAncestorBlock->hasTagName(h2Tag)
    417         || commonAncestorBlock->hasTagName(h3Tag)
    418         || commonAncestorBlock->hasTagName(h4Tag)
    419         || commonAncestorBlock->hasTagName(h5Tag))
    420         return commonAncestorBlock;
    421 
    422     return 0;
    423 }
    424 
    425 static bool propertyMissingOrEqualToNone(CSSStyleDeclaration* style, int propertyID)
    426 {
    427     if (!style)
    428         return false;
    429     RefPtr<CSSValue> value = style->getPropertyCSSValue(propertyID);
    430     if (!value)
    431         return true;
    432     if (!value->isPrimitiveValue())
    433         return false;
    434     return static_cast<CSSPrimitiveValue*>(value.get())->getIdent() == CSSValueNone;
    435 }
    436 
    437 static bool needInterchangeNewlineAfter(const VisiblePosition& v)
    438 {
    439     VisiblePosition next = v.next();
    440     Node* upstreamNode = next.deepEquivalent().upstream().deprecatedNode();
    441     Node* downstreamNode = v.deepEquivalent().downstream().deprecatedNode();
    442     // Add an interchange newline if a paragraph break is selected and a br won't already be added to the markup to represent it.
    443     return isEndOfParagraph(v) && isStartOfParagraph(next) && !(upstreamNode->hasTagName(brTag) && upstreamNode == downstreamNode);
    444 }
    445 
    446 static PassRefPtr<CSSMutableStyleDeclaration> styleFromMatchedRulesAndInlineDecl(const Node* node)
    447 {
    448     if (!node->isHTMLElement())
    449         return 0;
    450 
    451     // FIXME: Having to const_cast here is ugly, but it is quite a bit of work to untangle
    452     // the non-const-ness of styleFromMatchedRulesForElement.
    453     HTMLElement* element = const_cast<HTMLElement*>(static_cast<const HTMLElement*>(node));
    454     RefPtr<CSSMutableStyleDeclaration> style = styleFromMatchedRulesForElement(element);
    455     RefPtr<CSSMutableStyleDeclaration> inlineStyleDecl = element->getInlineStyleDecl();
    456     style->merge(inlineStyleDecl.get());
    457     return style.release();
    458 }
    459 
    460 static bool isElementPresentational(const Node* node)
    461 {
    462     if (node->hasTagName(uTag) || node->hasTagName(sTag) || node->hasTagName(strikeTag)
    463         || node->hasTagName(iTag) || node->hasTagName(emTag) || node->hasTagName(bTag) || node->hasTagName(strongTag))
    464         return true;
    465     RefPtr<CSSMutableStyleDeclaration> style = styleFromMatchedRulesAndInlineDecl(node);
    466     if (!style)
    467         return false;
    468     return !propertyMissingOrEqualToNone(style.get(), CSSPropertyTextDecoration);
    469 }
    470 
    471 static bool shouldIncludeWrapperForFullySelectedRoot(Node* fullySelectedRoot, CSSMutableStyleDeclaration* style)
    472 {
    473     if (fullySelectedRoot->isElementNode() && static_cast<Element*>(fullySelectedRoot)->hasAttribute(backgroundAttr))
    474         return true;
    475 
    476     return style->getPropertyCSSValue(CSSPropertyBackgroundImage) || style->getPropertyCSSValue(CSSPropertyBackgroundColor);
    477 }
    478 
    479 static Node* highestAncestorToWrapMarkup(const Range* range, Node* fullySelectedRoot, EAnnotateForInterchange shouldAnnotate)
    480 {
    481     ExceptionCode ec;
    482     Node* commonAncestor = range->commonAncestorContainer(ec);
    483     ASSERT(commonAncestor);
    484     Node* specialCommonAncestor = 0;
    485     if (shouldAnnotate == AnnotateForInterchange) {
    486         // Include ancestors that aren't completely inside the range but are required to retain
    487         // the structure and appearance of the copied markup.
    488         specialCommonAncestor = ancestorToRetainStructureAndAppearance(commonAncestor);
    489 
    490         // Retain the Mail quote level by including all ancestor mail block quotes.
    491         if (Node* highestMailBlockquote = highestEnclosingNodeOfType(firstPositionInOrBeforeNode(range->firstNode()), isMailBlockquote, CanCrossEditingBoundary))
    492             specialCommonAncestor = highestMailBlockquote;
    493     }
    494 
    495     Node* checkAncestor = specialCommonAncestor ? specialCommonAncestor : commonAncestor;
    496     if (checkAncestor->renderer()) {
    497         Node* newSpecialCommonAncestor = highestEnclosingNodeOfType(firstPositionInNode(checkAncestor), &isElementPresentational);
    498         if (newSpecialCommonAncestor)
    499             specialCommonAncestor = newSpecialCommonAncestor;
    500     }
    501 
    502     // If a single tab is selected, commonAncestor will be a text node inside a tab span.
    503     // If two or more tabs are selected, commonAncestor will be the tab span.
    504     // In either case, if there is a specialCommonAncestor already, it will necessarily be above
    505     // any tab span that needs to be included.
    506     if (!specialCommonAncestor && isTabSpanTextNode(commonAncestor))
    507         specialCommonAncestor = commonAncestor->parentNode();
    508     if (!specialCommonAncestor && isTabSpanNode(commonAncestor))
    509         specialCommonAncestor = commonAncestor;
    510 
    511     if (Node *enclosingAnchor = enclosingNodeWithTag(firstPositionInNode(specialCommonAncestor ? specialCommonAncestor : commonAncestor), aTag))
    512         specialCommonAncestor = enclosingAnchor;
    513 
    514     if (shouldAnnotate == AnnotateForInterchange && fullySelectedRoot) {
    515         RefPtr<CSSMutableStyleDeclaration> fullySelectedRootStyle = styleFromMatchedRulesAndInlineDecl(fullySelectedRoot);
    516         if (shouldIncludeWrapperForFullySelectedRoot(fullySelectedRoot, fullySelectedRootStyle.get()))
    517             specialCommonAncestor = fullySelectedRoot;
    518     }
    519     return specialCommonAncestor;
    520 }
    521 
    522 // FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForInterchange?
    523 // FIXME: At least, annotation and style info should probably not be included in range.markupString()
    524 String createMarkup(const Range* range, Vector<Node*>* nodes, EAnnotateForInterchange shouldAnnotate, bool convertBlocksToInlines, EAbsoluteURLs shouldResolveURLs)
    525 {
    526     DEFINE_STATIC_LOCAL(const String, interchangeNewlineString, ("<br class=\"" AppleInterchangeNewline "\">"));
    527 
    528     if (!range)
    529         return "";
    530 
    531     Document* document = range->ownerDocument();
    532     if (!document)
    533         return "";
    534 
    535     // Disable the delete button so it's elements are not serialized into the markup,
    536     // but make sure neither endpoint is inside the delete user interface.
    537     Frame* frame = document->frame();
    538     DeleteButtonController* deleteButton = frame ? frame->editor()->deleteButtonController() : 0;
    539     RefPtr<Range> updatedRange = avoidIntersectionWithNode(range, deleteButton ? deleteButton->containerElement() : 0);
    540     if (!updatedRange)
    541         return "";
    542 
    543     if (deleteButton)
    544         deleteButton->disable();
    545 
    546     ExceptionCode ec = 0;
    547     bool collapsed = updatedRange->collapsed(ec);
    548     ASSERT(!ec);
    549     if (collapsed)
    550         return "";
    551     Node* commonAncestor = updatedRange->commonAncestorContainer(ec);
    552     ASSERT(!ec);
    553     if (!commonAncestor)
    554         return "";
    555 
    556     document->updateLayoutIgnorePendingStylesheets();
    557 
    558     StyledMarkupAccumulator accumulator(nodes, shouldResolveURLs, shouldAnnotate, updatedRange.get());
    559     Node* pastEnd = updatedRange->pastLastNode();
    560 
    561     Node* startNode = updatedRange->firstNode();
    562     VisiblePosition visibleStart(updatedRange->startPosition(), VP_DEFAULT_AFFINITY);
    563     VisiblePosition visibleEnd(updatedRange->endPosition(), VP_DEFAULT_AFFINITY);
    564     if (shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAfter(visibleStart)) {
    565         if (visibleStart == visibleEnd.previous()) {
    566             if (deleteButton)
    567                 deleteButton->enable();
    568             return interchangeNewlineString;
    569         }
    570 
    571         accumulator.appendString(interchangeNewlineString);
    572         startNode = visibleStart.next().deepEquivalent().deprecatedNode();
    573 
    574         ExceptionCode ec = 0;
    575         if (pastEnd && Range::compareBoundaryPoints(startNode, 0, pastEnd, 0, ec) >= 0) {
    576             ASSERT(!ec);
    577             if (deleteButton)
    578                 deleteButton->enable();
    579             return interchangeNewlineString;
    580         }
    581         ASSERT(!ec);
    582     }
    583 
    584     Node* body = enclosingNodeWithTag(firstPositionInNode(commonAncestor), bodyTag);
    585     Node* fullySelectedRoot = 0;
    586     // FIXME: Do this for all fully selected blocks, not just the body.
    587     if (body && areRangesEqual(VisibleSelection::selectionFromContentsOfNode(body).toNormalizedRange().get(), range))
    588         fullySelectedRoot = body;
    589 
    590     Node* specialCommonAncestor = highestAncestorToWrapMarkup(updatedRange.get(), fullySelectedRoot, shouldAnnotate);
    591 
    592     Node* lastClosed = accumulator.serializeNodes(startNode, pastEnd);
    593 
    594     if (specialCommonAncestor && lastClosed) {
    595         // Also include all of the ancestors of lastClosed up to this special ancestor.
    596         for (ContainerNode* ancestor = lastClosed->parentNode(); ancestor; ancestor = ancestor->parentNode()) {
    597             if (ancestor == fullySelectedRoot && !convertBlocksToInlines) {
    598                 RefPtr<CSSMutableStyleDeclaration> fullySelectedRootStyle = styleFromMatchedRulesAndInlineDecl(fullySelectedRoot);
    599 
    600                 // Bring the background attribute over, but not as an attribute because a background attribute on a div
    601                 // appears to have no effect.
    602                 if (!fullySelectedRootStyle->getPropertyCSSValue(CSSPropertyBackgroundImage) && static_cast<Element*>(fullySelectedRoot)->hasAttribute(backgroundAttr))
    603                     fullySelectedRootStyle->setProperty(CSSPropertyBackgroundImage, "url('" + static_cast<Element*>(fullySelectedRoot)->getAttribute(backgroundAttr) + "')");
    604 
    605                 if (fullySelectedRootStyle->length()) {
    606                     // Reset the CSS properties to avoid an assertion error in addStyleMarkup().
    607                     // This assertion is caused at least when we select all text of a <body> element whose
    608                     // 'text-decoration' property is "inherit", and copy it.
    609                     if (!propertyMissingOrEqualToNone(fullySelectedRootStyle.get(), CSSPropertyTextDecoration))
    610                         fullySelectedRootStyle->setProperty(CSSPropertyTextDecoration, CSSValueNone);
    611                     if (!propertyMissingOrEqualToNone(fullySelectedRootStyle.get(), CSSPropertyWebkitTextDecorationsInEffect))
    612                         fullySelectedRootStyle->setProperty(CSSPropertyWebkitTextDecorationsInEffect, CSSValueNone);
    613                     accumulator.wrapWithStyleNode(fullySelectedRootStyle.get(), document, true);
    614                 }
    615             } else {
    616                 // Since this node and all the other ancestors are not in the selection we want to set RangeFullySelectsNode to DoesNotFullySelectNode
    617                 // so that styles that affect the exterior of the node are not included.
    618                 accumulator.wrapWithNode(ancestor, convertBlocksToInlines, StyledMarkupAccumulator::DoesNotFullySelectNode);
    619             }
    620             if (nodes)
    621                 nodes->append(ancestor);
    622 
    623             lastClosed = ancestor;
    624 
    625             if (ancestor == specialCommonAncestor)
    626                 break;
    627         }
    628     }
    629 
    630     // Add a wrapper span with the styles that all of the nodes in the markup inherit.
    631     ContainerNode* parentOfLastClosed = lastClosed ? lastClosed->parentNode() : 0;
    632     if (parentOfLastClosed && parentOfLastClosed->renderer()) {
    633         RefPtr<EditingStyle> style = EditingStyle::create(parentOfLastClosed);
    634 
    635         // Styles that Mail blockquotes contribute should only be placed on the Mail blockquote, to help
    636         // us differentiate those styles from ones that the user has applied.  This helps us
    637         // get the color of content pasted into blockquotes right.
    638         style->removeStyleAddedByNode(enclosingNodeOfType(firstPositionInNode(parentOfLastClosed), isMailBlockquote, CanCrossEditingBoundary));
    639 
    640         // Document default styles will be added on another wrapper span.
    641         if (document && document->documentElement())
    642             style->prepareToApplyAt(firstPositionInNode(document->documentElement()));
    643 
    644         // Since we are converting blocks to inlines, remove any inherited block properties that are in the style.
    645         // This cuts out meaningless properties and prevents properties from magically affecting blocks later
    646         // if the style is cloned for a new block element during a future editing operation.
    647         if (convertBlocksToInlines)
    648             style->removeBlockProperties();
    649 
    650         if (!style->isEmpty())
    651             accumulator.wrapWithStyleNode(style->style(), document);
    652     }
    653 
    654     if (lastClosed && lastClosed != document->documentElement()) {
    655         // Add a style span with the document's default styles.  We add these in a separate
    656         // span so that at paste time we can differentiate between document defaults and user
    657         // applied styles.
    658         RefPtr<EditingStyle> defaultStyle = EditingStyle::create(document->documentElement());
    659         if (!defaultStyle->isEmpty())
    660             accumulator.wrapWithStyleNode(defaultStyle->style(), document);
    661     }
    662 
    663     // FIXME: The interchange newline should be placed in the block that it's in, not after all of the content, unconditionally.
    664     if (shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAfter(visibleEnd.previous()))
    665         accumulator.appendString(interchangeNewlineString);
    666 
    667     if (deleteButton)
    668         deleteButton->enable();
    669 
    670     return accumulator.takeResults();
    671 }
    672 
    673 PassRefPtr<DocumentFragment> createFragmentFromMarkup(Document* document, const String& markup, const String& baseURL, FragmentScriptingPermission scriptingPermission)
    674 {
    675     // We use a fake body element here to trick the HTML parser to using the
    676     // InBody insertion mode.  Really, all this code is wrong and need to be
    677     // changed not to use deprecatedCreateContextualFragment.
    678     RefPtr<HTMLBodyElement> fakeBody = HTMLBodyElement::create(document);
    679     // FIXME: This should not use deprecatedCreateContextualFragment
    680     RefPtr<DocumentFragment> fragment = fakeBody->deprecatedCreateContextualFragment(markup, scriptingPermission);
    681 
    682     if (fragment && !baseURL.isEmpty() && baseURL != blankURL() && baseURL != document->baseURL())
    683         completeURLs(fragment.get(), baseURL);
    684 
    685     return fragment.release();
    686 }
    687 
    688 String createMarkup(const Node* node, EChildrenOnly childrenOnly, Vector<Node*>* nodes, EAbsoluteURLs shouldResolveURLs)
    689 {
    690     if (!node)
    691         return "";
    692 
    693     HTMLElement* deleteButtonContainerElement = 0;
    694     if (Frame* frame = node->document()->frame()) {
    695         deleteButtonContainerElement = frame->editor()->deleteButtonController()->containerElement();
    696         if (node->isDescendantOf(deleteButtonContainerElement))
    697             return "";
    698     }
    699 
    700     MarkupAccumulator accumulator(nodes, shouldResolveURLs);
    701     return accumulator.serializeNodes(const_cast<Node*>(node), deleteButtonContainerElement, childrenOnly);
    702 }
    703 
    704 static void fillContainerFromString(ContainerNode* paragraph, const String& string)
    705 {
    706     Document* document = paragraph->document();
    707 
    708     ExceptionCode ec = 0;
    709     if (string.isEmpty()) {
    710         paragraph->appendChild(createBlockPlaceholderElement(document), ec);
    711         ASSERT(!ec);
    712         return;
    713     }
    714 
    715     ASSERT(string.find('\n') == notFound);
    716 
    717     Vector<String> tabList;
    718     string.split('\t', true, tabList);
    719     String tabText = "";
    720     bool first = true;
    721     size_t numEntries = tabList.size();
    722     for (size_t i = 0; i < numEntries; ++i) {
    723         const String& s = tabList[i];
    724 
    725         // append the non-tab textual part
    726         if (!s.isEmpty()) {
    727             if (!tabText.isEmpty()) {
    728                 paragraph->appendChild(createTabSpanElement(document, tabText), ec);
    729                 ASSERT(!ec);
    730                 tabText = "";
    731             }
    732             RefPtr<Node> textNode = document->createTextNode(stringWithRebalancedWhitespace(s, first, i + 1 == numEntries));
    733             paragraph->appendChild(textNode.release(), ec);
    734             ASSERT(!ec);
    735         }
    736 
    737         // there is a tab after every entry, except the last entry
    738         // (if the last character is a tab, the list gets an extra empty entry)
    739         if (i + 1 != numEntries)
    740             tabText.append('\t');
    741         else if (!tabText.isEmpty()) {
    742             paragraph->appendChild(createTabSpanElement(document, tabText), ec);
    743             ASSERT(!ec);
    744         }
    745 
    746         first = false;
    747     }
    748 }
    749 
    750 bool isPlainTextMarkup(Node *node)
    751 {
    752     if (!node->isElementNode() || !node->hasTagName(divTag) || static_cast<Element*>(node)->attributes()->length())
    753         return false;
    754 
    755     if (node->childNodeCount() == 1 && (node->firstChild()->isTextNode() || (node->firstChild()->firstChild())))
    756         return true;
    757 
    758     return (node->childNodeCount() == 2 && isTabSpanTextNode(node->firstChild()->firstChild()) && node->firstChild()->nextSibling()->isTextNode());
    759 }
    760 
    761 PassRefPtr<DocumentFragment> createFragmentFromText(Range* context, const String& text)
    762 {
    763     if (!context)
    764         return 0;
    765 
    766     Node* styleNode = context->firstNode();
    767     if (!styleNode) {
    768         styleNode = context->startPosition().deprecatedNode();
    769         if (!styleNode)
    770             return 0;
    771     }
    772 
    773     Document* document = styleNode->document();
    774     RefPtr<DocumentFragment> fragment = document->createDocumentFragment();
    775 
    776     if (text.isEmpty())
    777         return fragment.release();
    778 
    779     String string = text;
    780     string.replace("\r\n", "\n");
    781     string.replace('\r', '\n');
    782 
    783     ExceptionCode ec = 0;
    784     RenderObject* renderer = styleNode->renderer();
    785     if (renderer && renderer->style()->preserveNewline()) {
    786         fragment->appendChild(document->createTextNode(string), ec);
    787         ASSERT(!ec);
    788         if (string.endsWith("\n")) {
    789             RefPtr<Element> element = createBreakElement(document);
    790             element->setAttribute(classAttr, AppleInterchangeNewline);
    791             fragment->appendChild(element.release(), ec);
    792             ASSERT(!ec);
    793         }
    794         return fragment.release();
    795     }
    796 
    797     // A string with no newlines gets added inline, rather than being put into a paragraph.
    798     if (string.find('\n') == notFound) {
    799         fillContainerFromString(fragment.get(), string);
    800         return fragment.release();
    801     }
    802 
    803     // Break string into paragraphs. Extra line breaks turn into empty paragraphs.
    804     Node* blockNode = enclosingBlock(context->firstNode());
    805     Element* block = static_cast<Element*>(blockNode);
    806     bool useClonesOfEnclosingBlock = blockNode
    807         && blockNode->isElementNode()
    808         && !block->hasTagName(bodyTag)
    809         && !block->hasTagName(htmlTag)
    810         && block != editableRootForPosition(context->startPosition());
    811 
    812     Vector<String> list;
    813     string.split('\n', true, list); // true gets us empty strings in the list
    814     size_t numLines = list.size();
    815     for (size_t i = 0; i < numLines; ++i) {
    816         const String& s = list[i];
    817 
    818         RefPtr<Element> element;
    819         if (s.isEmpty() && i + 1 == numLines) {
    820             // For last line, use the "magic BR" rather than a P.
    821             element = createBreakElement(document);
    822             element->setAttribute(classAttr, AppleInterchangeNewline);
    823         } else {
    824             if (useClonesOfEnclosingBlock)
    825                 element = block->cloneElementWithoutChildren();
    826             else
    827                 element = createDefaultParagraphElement(document);
    828             fillContainerFromString(element.get(), s);
    829         }
    830         fragment->appendChild(element.release(), ec);
    831         ASSERT(!ec);
    832     }
    833     return fragment.release();
    834 }
    835 
    836 PassRefPtr<DocumentFragment> createFragmentFromNodes(Document *document, const Vector<Node*>& nodes)
    837 {
    838     if (!document)
    839         return 0;
    840 
    841     // disable the delete button so it's elements are not serialized into the markup
    842     if (document->frame())
    843         document->frame()->editor()->deleteButtonController()->disable();
    844 
    845     RefPtr<DocumentFragment> fragment = document->createDocumentFragment();
    846 
    847     ExceptionCode ec = 0;
    848     size_t size = nodes.size();
    849     for (size_t i = 0; i < size; ++i) {
    850         RefPtr<Element> element = createDefaultParagraphElement(document);
    851         element->appendChild(nodes[i], ec);
    852         ASSERT(!ec);
    853         fragment->appendChild(element.release(), ec);
    854         ASSERT(!ec);
    855     }
    856 
    857     if (document->frame())
    858         document->frame()->editor()->deleteButtonController()->enable();
    859 
    860     return fragment.release();
    861 }
    862 
    863 String createFullMarkup(const Node* node)
    864 {
    865     if (!node)
    866         return String();
    867 
    868     Document* document = node->document();
    869     if (!document)
    870         return String();
    871 
    872     Frame* frame = document->frame();
    873     if (!frame)
    874         return String();
    875 
    876     // FIXME: This is never "for interchange". Is that right?
    877     String markupString = createMarkup(node, IncludeNode, 0);
    878     Node::NodeType nodeType = node->nodeType();
    879     if (nodeType != Node::DOCUMENT_NODE && nodeType != Node::DOCUMENT_TYPE_NODE)
    880         markupString = frame->documentTypeString() + markupString;
    881 
    882     return markupString;
    883 }
    884 
    885 String createFullMarkup(const Range* range)
    886 {
    887     if (!range)
    888         return String();
    889 
    890     Node* node = range->startContainer();
    891     if (!node)
    892         return String();
    893 
    894     Document* document = node->document();
    895     if (!document)
    896         return String();
    897 
    898     Frame* frame = document->frame();
    899     if (!frame)
    900         return String();
    901 
    902     // FIXME: This is always "for interchange". Is that right? See the previous method.
    903     return frame->documentTypeString() + createMarkup(range, 0, AnnotateForInterchange);
    904 }
    905 
    906 String urlToMarkup(const KURL& url, const String& title)
    907 {
    908     Vector<UChar> markup;
    909     append(markup, "<a href=\"");
    910     append(markup, url.string());
    911     append(markup, "\">");
    912     appendCharactersReplacingEntities(markup, title.characters(), title.length(), EntityMaskInPCDATA);
    913     append(markup, "</a>");
    914     return String::adopt(markup);
    915 }
    916 
    917 }
    918