Changeset 26474 in webkit


Ignore:
Timestamp:
Oct 12, 2007 7:41:35 AM (17 years ago)
Author:
oliver
Message:

WebCore:

Reviewed by Oliver.

Rewrote both versions of createMarkup to build based on
Vector<UChar> instead of String. Also other miscellaneous
speedups (mainly content strings are now encoded in a way that
doesn't take a function call per character, and switch is avoided).

This also causes a functional change - we no longer escape '>' since this was unnecessary and it's faster
to avoid testing for it. See updated test results.

  • editing/markup.cpp: (WebCore::appendString): (WebCore::appendAttributeValue): (WebCore::escapeContentText): (WebCore::appendEscapedContent): (WebCore::appendDeprecatedString): (WebCore::appendQuotedURLAttributeValue): (WebCore::stringValueForRange): (WebCore::ucharRange): (WebCore::appendUCharRange): (WebCore::appendNamespace): (WebCore::appendStartMarkup): (WebCore::getStartMarkup): (WebCore::appendEndMarkup): (WebCore::getEndMarkup): (WebCore::appendMarkup): (WebCore::joinMarkups): (WebCore::createMarkup):
  • editing/markup.h:
  • page/mac/WebCoreFrameBridge.mm: (-[WebCoreFrameBridge markupStringFromNode:nodes:]): (-[WebCoreFrameBridge markupStringFromRange:nodes:]):

LayoutTests:

Reviewed by Oliver.

We no longer entity-escape the '>' character in content or attribute values since this is unnecessary.

  • fast/dom/dom-parse-serialize-expected.txt:
  • fast/dom/serialize-attribute.xhtml:
  • fast/xsl/xslt-processor-expected.txt:
Location:
trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r26469 r26474  
     12007-10-02  Maciej Stachowiak  <mjs@apple.com>
     2
     3        Reviewed by Oliver.
     4
     5        - test updates for "file:///Volumes/Data/mjs/Work/src/Safari/OpenSource/LayoutTests/fast/dom/serialize-attribute.xhtml"
     6        http://bugs.webkit.org/show_bug.cgi?id=15339
     7
     8        We no longer entity-escape the '>' character in content or attribute values since this is unnecessary.
     9       
     10        * fast/dom/dom-parse-serialize-expected.txt:
     11        * fast/dom/serialize-attribute.xhtml:
     12        * fast/xsl/xslt-processor-expected.txt:
     13
    1142007-10-02  Nicholas Shanks  <webkit@nickshanks.com>
    215
  • trunk/LayoutTests/fast/dom/serialize-attribute.xhtml

    r18484 r26474  
    1212    serialized = (new XMLSerializer()).serializeToString(document.getElementById("testDiv\"'&<>"));
    1313    if (serialized == "<div xmlns=\"http://www.w3.org/1999/xhtml\" id=\"testDiv&quot;'&amp;&lt;&gt;\"/>" ||
    14         serialized == "<div xmlns=\"http://www.w3.org/1999/xhtml\" id=\"testDiv&quot;'&amp;&lt;&gt;\"></div>")
     14        serialized == "<div xmlns=\"http://www.w3.org/1999/xhtml\" id=\"testDiv&quot;'&amp;&lt;&gt;\"></div>" ||
     15        serialized == "<div xmlns=\"http://www.w3.org/1999/xhtml\" id=\"testDiv&quot;'&amp;&lt;>\"/>" ||
     16        serialized == "<div xmlns=\"http://www.w3.org/1999/xhtml\" id=\"testDiv&quot;'&amp;&lt;>\"></div>")
    1517      document.getElementById("result").textContent = "SUCCESS";
    1618    else
  • trunk/LayoutTests/fast/xsl/xslt-processor-expected.txt

    r21687 r26474  
    110.1 original xml:
    2 <?xml-stylesheet type="text/xsl" href="xslt-text.xsl"?><TEST>SOURCE XML: &lt;&lt;&lt;&amp;тест&amp;&gt;&gt;&gt;</TEST>
     2<?xml-stylesheet type="text/xsl" href="xslt-text.xsl"?><TEST>SOURCE XML: &lt;&lt;&lt;&amp;тест&amp;>>></TEST>
    330.2 xsl1:
    44<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    55
    66<xsl:output method="text" encoding="KOI8-R"/>
    7 <xsl:template match="TEST">CHARACTERS IN XSLT: &lt;&lt;&lt;&amp;тест&amp;&gt;&gt;&gt;
     7<xsl:template match="TEST">CHARACTERS IN XSLT: &lt;&lt;&lt;&amp;тест&amp;>>>
    88<xsl:apply-templates/><xsl:text>
    99</xsl:text></xsl:template>
     
    38381.1 Import two different stylesheets:
    3939<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head><body>
    40               CHARACTERS IN XSLT: ééééééééééé <br><br>SOURCE XML: &lt;&lt;&lt;&amp;тест&amp;&gt;&gt;&gt;
     40              CHARACTERS IN XSLT: ééééééééééé <br><br>SOURCE XML: &lt;&lt;&lt;&amp;тест&amp;>>>
    4141</body></html>
    42421.2 Import same stylesheet twice:
     
    4444<head><title></title></head>
    4545<body>
    46 <pre>CHARACTERS IN XSLT: &lt;&lt;&lt;&amp;тест&amp;&gt;&gt;&gt;
    47 SOURCE XML: &lt;&lt;&lt;&amp;тест&amp;&gt;&gt;&gt;
     46<pre>CHARACTERS IN XSLT: &lt;&lt;&lt;&amp;тест&amp;>>>
     47SOURCE XML: &lt;&lt;&lt;&amp;тест&amp;>>>
    4848</pre>
    4949</body>
  • trunk/WebCore/ChangeLog

    r26471 r26474  
     12007-10-02  Maciej Stachowiak  <mjs@apple.com>
     2
     3        Reviewed by Oliver.
     4
     5        - Use Vector<UChar> instead of DeprecatedString for innerHTML, for 35% speedup on CK DOM test
     6        http://bugs.webkit.org/show_bug.cgi?id=15339
     7
     8        Rewrote both versions of createMarkup to build based on
     9        Vector<UChar> instead of String. Also other miscellaneous
     10        speedups (mainly content strings are now encoded in a way that
     11        doesn't take a function call per character, and switch is avoided).
     12       
     13        This also causes a functional change - we no longer escape '>' since this was unnecessary and it's faster
     14        to avoid testing for it. See updated test results.
     15       
     16        * editing/markup.cpp:
     17        (WebCore::appendString):
     18        (WebCore::appendAttributeValue):
     19        (WebCore::escapeContentText):
     20        (WebCore::appendEscapedContent):
     21        (WebCore::appendDeprecatedString):
     22        (WebCore::appendQuotedURLAttributeValue):
     23        (WebCore::stringValueForRange):
     24        (WebCore::ucharRange):
     25        (WebCore::appendUCharRange):
     26        (WebCore::appendNamespace):
     27        (WebCore::appendStartMarkup):
     28        (WebCore::getStartMarkup):
     29        (WebCore::appendEndMarkup):
     30        (WebCore::getEndMarkup):
     31        (WebCore::appendMarkup):
     32        (WebCore::joinMarkups):
     33        (WebCore::createMarkup):
     34        * editing/markup.h:
     35        * page/mac/WebCoreFrameBridge.mm:
     36        (-[WebCoreFrameBridge markupStringFromNode:nodes:]):
     37        (-[WebCoreFrameBridge markupStringFromRange:nodes:]):
     38
    1392007-10-02  Maciej Stachowiak  <mjs@apple.com>
    240
  • trunk/WebCore/WebCore.xcodeproj/project.pbxproj

    r26459 r26474  
    1320313203                        isa = PBXProject;
    1320413204                        buildConfigurationList = 149C284308902B11008A9EFC /* Build configuration list for PBXProject "WebCore" */;
     13205                        compatibilityVersion = "Xcode 2.4";
    1320513206                        hasScannedForEncodings = 1;
    1320613207                        knownRegions = (
  • trunk/WebCore/editing/markup.cpp

    r26470 r26474  
    8787};
    8888
    89 static DeprecatedString escapeTextForMarkup(const String& in, bool isAttributeValue)
    90 {
    91     DeprecatedString s = "";
    92 
    93     unsigned len = in.length();
     89static inline void appendString(Vector<UChar>& result, const String& str)
     90{
     91    result.append(str.characters(), str.length());
     92}
     93   
     94static void appendAttributeValue(Vector<UChar>& result, const String& attr)
     95{
     96    const UChar* uchars = attr.characters();
     97    unsigned len = attr.length();
     98    unsigned lastCopiedFrom = 0;
     99
     100    static const String ampEntity("&amp;");
     101    static const String ltEntity("&lt;");
     102    static const String quotEntity("&quot;");
     103   
    94104    for (unsigned i = 0; i < len; ++i) {
    95         switch (in[i]) {
     105        UChar c = uchars[i];
     106        switch (c) {
    96107            case '&':
    97                 s += "&amp;";
     108                result.append(uchars + lastCopiedFrom, i - lastCopiedFrom);
     109                appendString(result, ampEntity);
     110                lastCopiedFrom = i + 1;
    98111                break;
    99112            case '<':
    100                 s += "&lt;";
    101                 break;
    102             case '>':
    103                 s += "&gt;";
     113                result.append(uchars + lastCopiedFrom, i - lastCopiedFrom);
     114                appendString(result, ltEntity);
     115                lastCopiedFrom = i + 1;
    104116                break;
    105117            case '"':
    106                 if (isAttributeValue) {
    107                     s += "&quot;";
    108                     break;
    109                 }
    110                 // fall through
    111             default:
    112                 s += DeprecatedChar(in[i]);
    113         }
    114     }
     118                result.append(uchars + lastCopiedFrom, i - lastCopiedFrom);
     119                appendString(result, quotEntity);
     120                lastCopiedFrom = i + 1;
     121        }
     122    }
     123   
     124    result.append(uchars + lastCopiedFrom, len - lastCopiedFrom);
     125}
     126   
     127static DeprecatedString escapeContentText(const String& in)
     128{
     129    DeprecatedString s = "";
     130
     131    unsigned len = in.length();
     132    unsigned lastCopiedFrom = 0;
     133
     134    const UChar* uchars = in.characters();
     135    const DeprecatedChar* dchars = reinterpret_cast<const DeprecatedChar*>(uchars);
     136
     137    for (unsigned i = 0; i < len; ++i) {
     138        UChar c = uchars[i];
     139        if (c == '&' | c == '<') {
     140            s.append(dchars + lastCopiedFrom, i - lastCopiedFrom);
     141            if (c == '&')
     142                s += "&amp;";
     143            else
     144                s += "&lt;";
     145            lastCopiedFrom = i + 1;
     146        }
     147    }
     148
     149    s.append(dchars + lastCopiedFrom, len - lastCopiedFrom);
    115150
    116151    return s;
    117152}
    118    
    119 static String urlAttributeToQuotedString(String urlString)
    120 {
    121     UChar quoteChar = '"';
     153
     154   
     155static void appendEscapedContent(Vector<UChar>& result, pair<const UChar*, size_t> range)
     156{
     157    const UChar* uchars = range.first;
     158    unsigned len = range.second;
     159    unsigned lastCopiedFrom = 0;
     160   
     161    static const String ampEntity("&amp;");
     162    static const String ltEntity("&lt;");
     163   
     164    for (unsigned i = 0; i < len; ++i) {
     165        UChar c = uchars[i];
     166        if (c == '&' | c == '<') {
     167            result.append(uchars + lastCopiedFrom, i - lastCopiedFrom);
     168            if (c == '&')
     169                appendString(result, ampEntity);
     170            else
     171                appendString(result, ltEntity);
     172            lastCopiedFrom = i + 1;
     173        }
     174    }
     175   
     176    result.append(uchars + lastCopiedFrom, len - lastCopiedFrom);
     177}   
     178
     179static inline void appendDeprecatedString(Vector<UChar>& result, const DeprecatedString& str)
     180{
     181    result.append(reinterpret_cast<const UChar*>(str.unicode()), str.length());
     182}   
     183   
     184static void appendQuotedURLAttributeValue(Vector<UChar>& result, String urlString)
     185{
     186    UChar quoteChar = '\"';
    122187    if (urlString.stripWhiteSpace().startsWith("javascript:", false)) {
    123188        // minimal escaping for javascript urls
    124         if (urlString.contains('"')) {
     189        if (urlString.contains('\"')) {
    125190            if (urlString.contains('\''))
    126                 urlString.replace('"', "&quot;");
     191                urlString.replace('\"', "&quot;");
    127192            else
    128193                quoteChar = '\'';
    129194        }
    130     } else
    131         // FIXME this does not fully match other browsers. Firefox escapes spaces and other special characters.
    132         urlString = escapeTextForMarkup(urlString.deprecatedString(), true);
    133 
    134     String res;
    135     res.append(quoteChar);
    136     res.append(urlString);
    137     res.append(quoteChar);
    138     return res;
    139 }
    140 
     195        result.append(quoteChar);
     196        appendString(result, urlString);
     197        result.append(quoteChar);
     198        return;
     199    }
     200
     201    // FIXME this does not fully match other browsers. Firefox escapes spaces and other special characters.
     202    result.append(quoteChar);
     203    appendAttributeValue(result, urlString);
     204    result.append(quoteChar);   
     205}
     206   
    141207static String stringValueForRange(const Node *node, const Range *range)
    142208{
     209    if (!range)
     210        return node->nodeValue();
     211
    143212    String str = node->nodeValue().copy();
     213    ExceptionCode ec;
     214    if (node == range->endContainer(ec))
     215        str.truncate(range->endOffset(ec));
     216    if (node == range->startContainer(ec))
     217        str.remove(0, range->startOffset(ec));
     218    return str;
     219}
     220
     221static inline pair<const UChar*, size_t> ucharRange(const Node *node, const Range *range)
     222{
     223    String str = node->nodeValue();
     224    const UChar* characters = str.characters();
     225    size_t length = str.length();
     226
    144227    if (range) {
    145228        ExceptionCode ec;
    146229        if (node == range->endContainer(ec))
    147             str.truncate(range->endOffset(ec));
    148         if (node == range->startContainer(ec))
    149             str.remove(0, range->startOffset(ec));
    150     }
    151     return str;
    152 }
    153 
     230            length = range->endOffset(ec);
     231        if (node == range->startContainer(ec)) {
     232            size_t start = range->startOffset(ec);
     233            characters += start;
     234            length -= start;
     235        }
     236    }
     237   
     238    return make_pair(characters, length);
     239}
     240   
     241static inline void appendUCharRange(Vector<UChar>& result, const pair<const UChar*, size_t> range)
     242{
     243    result.append(range.first, range.second);
     244}
     245   
    154246static String renderedText(const Node* node, const Range* range)
    155247{
     
    228320}
    229321
    230 static String addNamespace(const AtomicString& prefix, const AtomicString& ns, HashMap<AtomicStringImpl*, AtomicStringImpl*>& namespaces)
     322static void appendNamespace(Vector<UChar>& result, const AtomicString& prefix, const AtomicString& ns, HashMap<AtomicStringImpl*, AtomicStringImpl*>& namespaces)
    231323{
    232324    if (ns.isEmpty())
    233         return "";
    234    
     325        return;
     326       
    235327    // Use emptyAtoms's impl() for both null and empty strings since the HashMap can't handle 0 as a key
    236328    AtomicStringImpl* pre = prefix.isEmpty() ? emptyAtom.impl() : prefix.impl();
     
    238330    if (foundNS != ns.impl()) {
    239331        namespaces.set(pre, ns.impl());
    240         return " xmlns" + (!prefix.isEmpty() ? ":" + prefix : "") + "=\"" + escapeTextForMarkup(ns, true) + "\"";
    241     }
    242    
    243     return "";
    244 }
    245 
    246 static DeprecatedString startMarkup(const Node *node, const Range *range, EAnnotateForInterchange annotate, bool convertBlocksToInlines = false, HashMap<AtomicStringImpl*, AtomicStringImpl*>* namespaces = 0)
     332        static const String xmlns("xmlns");
     333        result.append(' ');
     334        appendString(result, xmlns);
     335        if (!prefix.isEmpty()) {
     336            result.append(':');
     337            appendString(result, prefix);
     338        }
     339
     340        result.append('=');
     341        result.append('"');
     342        appendAttributeValue(result, ns);
     343        result.append('"');
     344    }
     345}
     346   
     347static void appendStartMarkup(Vector<UChar>& result, const Node *node, const Range *range, EAnnotateForInterchange annotate, bool convertBlocksToInlines = false, HashMap<AtomicStringImpl*, AtomicStringImpl*>* namespaces = 0)
    247348{
    248349    bool documentIsHTML = node->document()->isHTMLDocument();
     
    251352            if (Node* parent = node->parentNode()) {
    252353                if (parent->hasTagName(listingTag)
    253                         || parent->hasTagName(scriptTag)
    254                         || parent->hasTagName(styleTag)
    255                         || parent->hasTagName(textareaTag)
    256                         || parent->hasTagName(xmpTag))
    257                     return stringValueForRange(node, range).deprecatedString();
    258             }
    259             bool useRenderedText = annotate && !enclosingNodeWithTag(const_cast<Node*>(node), selectTag);
    260             DeprecatedString markup = escapeTextForMarkup(useRenderedText ? renderedText(node, range) : stringValueForRange(node, range), false);
    261             return annotate ? convertHTMLTextToInterchangeFormat(markup, static_cast<const Text*>(node)) : markup;
     354                    || parent->hasTagName(scriptTag)
     355                    || parent->hasTagName(styleTag)
     356                    || parent->hasTagName(textareaTag)
     357                    || parent->hasTagName(xmpTag)) {
     358                    appendUCharRange(result, ucharRange(node, range));
     359                    break;
     360                }
     361            }
     362            if (!annotate) {
     363                appendEscapedContent(result, ucharRange(node, range));
     364                break;
     365            }
     366           
     367            bool useRenderedText = !enclosingNodeWithTag(const_cast<Node*>(node), selectTag);
     368            DeprecatedString markup = escapeContentText(useRenderedText ? renderedText(node, range) : stringValueForRange(node, range));
     369            if (annotate)
     370                markup = convertHTMLTextToInterchangeFormat(markup, static_cast<const Text*>(node));
     371            appendDeprecatedString(result, markup);
     372            break;
    262373        }
    263374        case Node::COMMENT_NODE:
    264             return static_cast<const Comment*>(node)->toString().deprecatedString();
     375            appendString(result, static_cast<const Comment*>(node)->toString());
     376            break;
    265377        case Node::DOCUMENT_NODE: {
     378            // FIXME: I think the comment below (and therefore this code) is wrong now
    266379            // Documents do not normally contain a docType as a child node, force it to print here instead.
    267380            const DocumentType* docType = static_cast<const Document*>(node)->doctype();
    268381            if (docType)
    269                 return docType->toString().deprecatedString();
    270             return "";
     382                appendString(result, docType->toString());
     383            break;
    271384        }
    272385        case Node::DOCUMENT_FRAGMENT_NODE:
    273             return "";
     386            break;
    274387        case Node::DOCUMENT_TYPE_NODE:
    275             return static_cast<const DocumentType*>(node)->toString().deprecatedString();
     388            appendString(result, static_cast<const DocumentType*>(node)->toString());
     389            break;
    276390        case Node::PROCESSING_INSTRUCTION_NODE:
    277             return static_cast<const ProcessingInstruction*>(node)->toString().deprecatedString();
     391            appendString(result, static_cast<const ProcessingInstruction*>(node)->toString());
     392            break;
    278393        case Node::ELEMENT_NODE: {
    279             DeprecatedString markup = DeprecatedChar('<');
     394            result.append('<');
    280395            const Element* el = static_cast<const Element*>(node);
    281             convertBlocksToInlines &= isBlock(const_cast<Node*>(node));
    282             markup += el->nodeNamePreservingCase().deprecatedString();
     396            bool convert = convertBlocksToInlines & isBlock(const_cast<Node*>(node));
     397            appendString(result, el->nodeNamePreservingCase());
    283398            NamedAttrMap *attrs = el->attributes();
    284399            unsigned length = attrs->length();
    285400            if (!documentIsHTML && namespaces && shouldAddNamespaceElem(el))
    286                 markup += addNamespace(el->prefix(), el->namespaceURI(), *namespaces).deprecatedString();
     401                appendNamespace(result, el->prefix(), el->namespaceURI(), *namespaces);
    287402
    288403            for (unsigned int i = 0; i < length; i++) {
    289404                Attribute *attr = attrs->attributeItem(i);
    290405                // We'll handle the style attribute separately, below.
    291                 if (attr->name() == styleAttr && el->isHTMLElement() && (annotate || convertBlocksToInlines))
     406                if (attr->name() == styleAttr && el->isHTMLElement() && (annotate || convert))
    292407                    continue;
     408                result.append(' ');
     409
    293410                if (documentIsHTML)
    294                     markup += " " + attr->name().localName().deprecatedString();
     411                    appendString(result, attr->name().localName());
    295412                else
    296                     markup += " " + attr->name().toString().deprecatedString();
     413                    appendString(result, attr->name().toString());
     414
     415                result.append('=');
     416
    297417                if (el->isURLAttribute(attr))
    298                     markup += "=" + urlAttributeToQuotedString(attr->value()).deprecatedString();
    299                 else
    300                     markup += "=\"" + escapeTextForMarkup(attr->value(), true) + "\"";
     418                    appendQuotedURLAttributeValue(result, attr->value());
     419                else {
     420                    result.append('\"');
     421                    appendAttributeValue(result, attr->value());
     422                    result.append('\"');
     423                }
     424
    301425                if (!documentIsHTML && namespaces && shouldAddNamespaceAttr(attr, *namespaces))
    302                     markup += addNamespace(attr->prefix(), attr->namespaceURI(), *namespaces).deprecatedString();
     426                    appendNamespace(result, attr->prefix(), attr->namespaceURI(), *namespaces);
    303427            }
    304428           
    305             if (el->isHTMLElement() && (annotate || convertBlocksToInlines)) {
     429            if (el->isHTMLElement() && (annotate || convert)) {
    306430                Element* element = const_cast<Element*>(el);
    307431                RefPtr<CSSMutableStyleDeclaration> style = static_cast<HTMLElement*>(element)->getInlineStyleDecl()->copy();
     
    310434                    style->merge(styleFromMatchedRules.get());
    311435                }
    312                 if (convertBlocksToInlines)
     436                if (convert)
    313437                    style->setProperty(CSS_PROP_DISPLAY, CSS_VAL_INLINE, true);
    314                 if (style->length() > 0)
    315                     markup += " style=\"" + escapeTextForMarkup(style->cssText(), true) + "\"";
     438                if (style->length() > 0) {
     439                    static const String stylePrefix(" style=\"");
     440                    appendString(result, stylePrefix);
     441                    appendAttributeValue(result, style->cssText());
     442                    result.append('\"');
     443                }
    316444            }
    317445           
    318446            if (shouldSelfClose(el)) {
    319447                if (el->isHTMLElement())
    320                     markup += " "; // XHTML 1.0 <-> HTML compatibility.
    321                 markup += "/>";
    322             } else
    323                 markup += ">";
    324            
    325             return markup;
     448                    result.append(' '); // XHTML 1.0 <-> HTML compatibility.
     449                result.append('/');
     450            }
     451            result.append('>');
     452            break;
    326453        }
    327454        case Node::CDATA_SECTION_NODE:
    328             return static_cast<const CDATASection*>(node)->toString().deprecatedString();
     455            appendString(result, static_cast<const CDATASection*>(node)->toString());
     456            break;
    329457        case Node::ATTRIBUTE_NODE:
    330458        case Node::ENTITY_NODE:
     
    332460        case Node::NOTATION_NODE:
    333461        case Node::XPATH_NAMESPACE_NODE:
     462            ASSERT_NOT_REACHED();
    334463            break;
    335464    }
    336     return "";
     465}
     466
     467static String getStartMarkup(const Node *node, const Range *range, EAnnotateForInterchange annotate, bool convertBlocksToInlines = false, HashMap<AtomicStringImpl*, AtomicStringImpl*>* namespaces = 0)
     468{
     469    Vector<UChar> result;
     470    appendStartMarkup(result, node, range, annotate, convertBlocksToInlines, namespaces);
     471    return String::adopt(result);
    337472}
    338473
     
    362497}
    363498
    364 static DeprecatedString endMarkup(const Node *node)
    365 {
    366     if (node->isElementNode() && !shouldSelfClose(node) && (node->hasChildNodes() || !doesHTMLForbidEndTag(node)))
    367         return "</" + static_cast<const Element*>(node)->nodeNamePreservingCase().deprecatedString() + ">";
    368     return "";
    369 }
    370 
    371 static DeprecatedString markup(Node* startNode, bool onlyIncludeChildren, Vector<Node*>* nodes, const HashMap<AtomicStringImpl*, AtomicStringImpl*>* namespaces = 0)
     499static void appendEndMarkup(Vector<UChar>& result, const Node* node)
     500{
     501    if (!node->isElementNode() || shouldSelfClose(node) || (!node->hasChildNodes() && doesHTMLForbidEndTag(node)))
     502        return;
     503
     504    result.append('<');
     505    result.append('/');
     506    appendString(result, static_cast<const Element*>(node)->nodeNamePreservingCase());
     507    result.append('>');
     508}
     509
     510static String getEndMarkup(const Node *node)
     511{
     512    Vector<UChar> result;
     513    appendEndMarkup(result, node);
     514    return String::adopt(result);
     515}
     516
     517static void appendMarkup(Vector<UChar>& result, Node* startNode, bool onlyIncludeChildren, Vector<Node*>* nodes, const HashMap<AtomicStringImpl*, AtomicStringImpl*>* namespaces = 0)
    372518{
    373519    HashMap<AtomicStringImpl*, AtomicStringImpl*> namespaceHash;
     
    375521        namespaceHash = *namespaces;
    376522   
    377     DeprecatedString me = "";
    378523    if (!onlyIncludeChildren) {
    379524        if (nodes)
    380525            nodes->append(startNode);
    381         me += startMarkup(startNode, 0, DoNotAnnotateForInterchange, false, &namespaceHash);
     526       
     527        appendStartMarkup(result,startNode, 0, DoNotAnnotateForInterchange, false, &namespaceHash);
    382528    }
    383529    // print children
    384530    if (!(startNode->document()->isHTMLDocument() && doesHTMLForbidEndTag(startNode)))
    385531        for (Node* current = startNode->firstChild(); current; current = current->nextSibling())
    386             me += markup(current, false, nodes, &namespaceHash);
     532            appendMarkup(result, current, false, nodes, &namespaceHash);
    387533   
    388534    // Print my ending tag
    389535    if (!onlyIncludeChildren)
    390         me += endMarkup(startNode);
    391    
    392     return me;
     536        appendEndMarkup(result, startNode);
    393537}
    394538
     
    461605}
    462606
     607String joinMarkups(const Vector<String> preMarkups, const Vector<String>& postMarkups)
     608{
     609    size_t length = 0;
     610
     611    size_t preCount = preMarkups.size();
     612    for (size_t i = 0; i < preCount; ++i)
     613        length += preMarkups[i].length();
     614
     615    size_t postCount = postMarkups.size();
     616    for (size_t i = 0; i < postCount; ++i)
     617        length += postMarkups[i].length();
     618
     619    Vector<UChar> result;
     620    result.reserveCapacity(length);
     621
     622    for (size_t i = preCount; i > 0; --i)
     623        appendString(result, preMarkups[i - 1]);
     624
     625    for (size_t i = 0; i < postCount; ++i)
     626        appendString(result, postMarkups[i]);
     627
     628    return String::adopt(result);
     629}
     630
    463631// FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForInterchange?
    464632// FIXME: At least, annotation and style info should probably not be included in range.markupString()
    465 DeprecatedString createMarkup(const Range* range, Vector<Node*>* nodes, EAnnotateForInterchange annotate, bool convertBlocksToInlines)
    466 {
    467     static const DeprecatedString interchangeNewlineString = DeprecatedString("<br class=\"") + AppleInterchangeNewline + "\">";
     633String createMarkup(const Range* range, Vector<Node*>* nodes, EAnnotateForInterchange annotate, bool convertBlocksToInlines)
     634{
     635    static const String interchangeNewlineString = String("<br class=\"") + AppleInterchangeNewline + "\">";
    468636
    469637    if (!range || range->isDetached())
     
    494662    document->updateLayoutIgnorePendingStylesheets();
    495663
    496     DeprecatedStringList markups;
     664    Vector<String> markups;
     665    Vector<String> preMarkups;
    497666    Node* pastEnd = updatedRange->pastEndNode();
    498667    Node* lastClosed = 0;
     
    534703        // Add the node to the markup.
    535704        if (addMarkupForNode) {
    536             markups.append(startMarkup(n, updatedRange.get(), annotate));
     705            markups.append(getStartMarkup(n, updatedRange.get(), annotate));
    537706            if (nodes)
    538707                nodes->append(n);
     
    542711            // Node has no children, or we are skipping it's descendants, add its close tag now.
    543712            if (addMarkupForNode) {
    544                 markups.append(endMarkup(n));
     713                markups.append(getEndMarkup(n));
    545714                lastClosed = n;
    546715            }
     
    555724                            break;
    556725                        // Not at the end of the range, close ancestors up to sibling of next node.
    557                         markups.append(endMarkup(ancestor));
     726                        markups.append(getEndMarkup(ancestor));
    558727                        lastClosed = ancestor;
    559728                        ancestorsToClose.removeLast();
     
    571740                        // or b) ancestors that we never encountered during a pre-order traversal starting at startNode:
    572741                        ASSERT(startNode->isDescendantOf(parent));
    573                         markups.prepend(startMarkup(parent, updatedRange.get(), annotate));
    574                         markups.append(endMarkup(parent));
     742                        preMarkups.append(getStartMarkup(parent, updatedRange.get(), annotate));
     743                        markups.append(getEndMarkup(parent));
    575744                        if (nodes)
    576745                            nodes->append(parent);
     
    634803               
    635804                if (style->length()) {
    636                     markups.prepend("<div style=\"" + escapeTextForMarkup(style->cssText(), true) + "\">");
    637                     markups.append("</div>");
     805                    Vector<UChar> openTag;
     806                    static const String divStyle("<div style=\"");
     807                    appendString(openTag, divStyle);
     808                    appendAttributeValue(openTag, style->cssText());
     809                    openTag.append('\"');
     810                    openTag.append('>');
     811                    preMarkups.append(String::adopt(openTag));
     812
     813                    static const String divCloseTag("</div>");
     814                    markups.append(divCloseTag);
    638815                }
    639816            } else {
    640                 markups.prepend(startMarkup(ancestor, updatedRange.get(), annotate, convertBlocksToInlines));
    641                 markups.append(endMarkup(ancestor));
     817                preMarkups.append(getStartMarkup(ancestor, updatedRange.get(), annotate, convertBlocksToInlines));
     818                markups.append(getEndMarkup(ancestor));
    642819            }
    643820            if (nodes)
     
    668845
    669846        if (style->length() > 0) {
    670             DeprecatedString openTag = DeprecatedString("<span class=\"") + AppleStyleSpanClass + "\" style=\"" + escapeTextForMarkup(style->cssText(), true) + "\">";
    671             markups.prepend(openTag);
    672             markups.append("</span>");
     847            Vector<UChar> openTag;
     848            const String spanClassStyle = String("<span class=\"" AppleStyleSpanClass "\" style=\"");
     849            appendString(openTag, spanClassStyle);
     850            appendAttributeValue(openTag, style->cssText());
     851            openTag.append('\"');
     852            openTag.append('>');
     853            preMarkups.append(String::adopt(openTag));
     854           
     855            static const String spanCloseTag("</span>");
     856            markups.append(spanCloseTag);
    673857        }
    674858    }
     
    685869        for (Node *ancestor = lastClosed->parentNode(); ancestor; ancestor = ancestor->parentNode()) {
    686870            if (isMailBlockquote(ancestor)) {
    687                 markups.prepend(startMarkup(ancestor, updatedRange.get(), annotate));
    688                 markups.append(endMarkup(ancestor));
     871                preMarkups.append(getStartMarkup(ancestor, updatedRange.get(), annotate));
     872                markups.append(getEndMarkup(ancestor));
    689873            }
    690874        }
     
    694878        deleteButton->enable();
    695879
    696     return markups.join("");
     880    return joinMarkups(preMarkups, markups);
    697881}
    698882
     
    711895}
    712896
    713 DeprecatedString createMarkup(const Node* node, EChildrenOnly includeChildren,
    714     Vector<Node*>* nodes, EAnnotateForInterchange annotate)
    715 {
    716     ASSERT(annotate == DoNotAnnotateForInterchange); // annotation not yet implemented for this code path
     897String createMarkup(const Node* node, EChildrenOnly includeChildren, Vector<Node*>* nodes)
     898{
     899    Vector<UChar> result;
    717900
    718901    if (!node)
     
    730913    }
    731914
    732     DeprecatedString result(markup(const_cast<Node*>(node), includeChildren, nodes));
     915    appendMarkup(result, const_cast<Node*>(node), includeChildren, nodes);
    733916
    734917    if (deleteButton)
    735918        deleteButton->enable();
    736919
    737     return result;
     920    return String::adopt(result);
    738921}
    739922
  • trunk/WebCore/editing/markup.h

    r20542 r26474  
    4545    PassRefPtr<DocumentFragment> createFragmentFromNodes(Document*, const Vector<Node*>&);
    4646
    47     DeprecatedString createMarkup(const Range*,
     47    String createMarkup(const Range*,
    4848        Vector<Node*>* = 0, EAnnotateForInterchange = DoNotAnnotateForInterchange, bool convertBlocksToInlines = false);
    49     DeprecatedString createMarkup(const Node*, EChildrenOnly = IncludeNode,
    50         Vector<Node*>* = 0, EAnnotateForInterchange = DoNotAnnotateForInterchange);
     49    String createMarkup(const Node*, EChildrenOnly = IncludeNode, Vector<Node*>* = 0);
    5150
    5251}
  • trunk/WebCore/page/mac/WebCoreFrameBridge.mm

    r25547 r26474  
    344344    // FIXME: This is never "for interchange". Is that right? See the next method.
    345345    Vector<Node*> nodeList;
    346     NSString *markupString = createMarkup([node _node], IncludeNode, nodes ? &nodeList : 0).getNSString();
     346    NSString *markupString = createMarkup([node _node], IncludeNode, nodes ? &nodeList : 0);
    347347    if (nodes)
    348348        *nodes = [self nodesFromList:&nodeList];
     
    355355    // FIXME: This is always "for interchange". Is that right? See the previous method.
    356356    Vector<Node*> nodeList;
    357     NSString *markupString = createMarkup([range _range], nodes ? &nodeList : 0, AnnotateForInterchange).getNSString();
     357    NSString *markupString = createMarkup([range _range], nodes ? &nodeList : 0, AnnotateForInterchange);
    358358    if (nodes)
    359359        *nodes = [self nodesFromList:&nodeList];
Note: See TracChangeset for help on using the changeset viewer.