Changeset 261437 in webkit


Ignore:
Timestamp:
May 9, 2020 9:04:01 AM (4 years ago)
Author:
Darin Adler
Message:

Streamline MarkupAccumulator to improve efficiency a bit
https://bugs.webkit.org/show_bug.cgi?id=211656

Reviewed by Anders Carlsson.

Source/JavaScriptCore:

  • b3/air/AirFixPartialRegisterStalls.h: Fix spelling of "explicitly".

Source/WebCore:

  • editing/MarkupAccumulator.cpp:

(WebCore::MarkupAccumulator::appendCharactersReplacingEntities): Corrected early
exit so it returns any time the length is 0. For some reason the code before
wouldn't do the early return when offset is non-zero, which is unnecessary.
(WebCore::MarkupAccumulator::appendString): Deleted.
(WebCore::MarkupAccumulator::appendStringView): Deleted.
(WebCore::MarkupAccumulator::appendEndTag): Use variadic append to cut down
on memory allocations.
(WebCore::MarkupAccumulator::totalLength): Deleted.
(WebCore::MarkupAccumulator::concatenateMarkup): Deleted.
(WebCore::MarkupAccumulator::takeMarkup): Added.
(WebCore::MarkupAccumulator::appendQuotedURLAttributeValue): Use variadic
append to cut down on memory allocations. Also use char instead of UChar so
the string building code doesn't have to do an 8/16 bit check.
(WebCore::shouldAddNamespaceElement): Prepend a literal, don't bother to
make a String just to append to another String. Also made this a
non-member function.
(WebCore::shouldAddNamespaceAttribute): Made this a non-member function.
(WebCore::MarkupAccumulator::appendNamespace): Fix hash table usage
to use add instead of get followed by set to avoid double hashing.
Use variadic append to cut down on memory allocation.
(WebCore::MarkupAccumulator::appendText): Tweaked style to make this a
one-line function.
(WebCore::appendComment): Deleted.
(WebCore::appendXMLDeclaration): Made this a non-member function.
Use variadic append to cut down on memory allocation.
(WebCore::appendDocumentType): Made this a non-member function.
Use variadic append to cut down on memory allocation.
(WebCore::MarkupAccumulator::appendCDATASection): Deleted.
(WebCore::MarkupAccumulator::appendNonElementNode): Moved the bodies of
appendComment, appendProcessingInstruction, and appendCDATASection in
here since they can all be one-line variadic append calls.

  • editing/MarkupAccumulator.h:

(WebCore::MarkupAccumulator::length const): Changed the return type
of length to be unsigned since that's what StringBuilder returns.
Made isAllASCII call StringBuilder::isAllASCII. Replaced appendString
and appendStringView with variadic append. Removed many functions
that no longer need to be member functions. Made appendAttributeValue
a static member function. Made appendNamespace private. Made
m_serializationSyntax const.

  • editing/markup.cpp:

(WebCore::StyledMarkupAccumulator::wrapWithStyleNode): Use append
instead of appenString.
(WebCore::StyledMarkupAccumulator::isAllASCII const): Added. Before
the code would only check the StringBuilder, but we also need to
check m_reversedPrecedingMarkup.
(WebCore::StyledMarkupAccumulator::takeResults): Use CheckedUint32
since StringBuilder's reserveCapacity function takes unsigned, not
size_t. The old code, using totalLength, would just pass a size_t
and let it get chopped off, which didn't do any harm, but it seems
strange to compute a 64-bit value just to chop off the lower 32
bits. An alternative is to compute the 32-bit value and just let
it overflow. Use a modern for loop by defining a ReverseView
template rather than writing a confusing backwards loop. Use the
new takeMarkup instead of concatenateMarkup.
(WebCore::StyledMarkupAccumulator::appendText): Tweak coding
style a little bit.
(WebCore::StyledMarkupAccumulator::appendStartTag): Ditto.
(WebCore::StyledMarkupAccumulator::appendNodeToPreserveMSOList):
Use variadic append to cut down on memory allocations.
(WebCore::propertyMissingOrEqualToNone): Tweak coding style a bit.
(WebCore::serializePreservingVisualAppearanceInternal): Use
append instead of appendString.
(WebCore::shouldPreserveMSOLists): Take a StringView instead of a
String to eliminate unnecessary memory allocation in call to substring.
(WebCore::sanitizedMarkupForFragmentInDocument): Use makeString
instead of StringBuilder to cut down on memory allocation.

  • html/HTMLFormElement.cpp:

(WebCore::HTMLFormElement::resetDefaultButton): Fix spelling error
in the word "explicitly".

  • mathml/MathMLOperatorDictionary.cpp:

(WebCore::MathMLOperatorDictionary::search): Ditto.

  • page/PageSerializer.cpp:

(WebCore::PageSerializer::SerializerMarkupAccumulator::SerializerMarkupAccumulator):
Use variadic append instead of appendString to cut down on
memory allocations.

  • rendering/svg/SVGInlineTextBox.cpp:

(WebCore::SVGInlineTextBox::paint): Fix spelling error in the word
"explicitly".

Source/WTF:

  • wtf/text/StringBuilder.cpp:

(WTF::StringBuilder::isAllASCII const): Added.

  • wtf/text/StringBuilder.h: Added isAllASCII.

Tools:

  • TestWebKitAPI/Tests/WTF/StringImpl.cpp:

(TestWebKitAPI::TEST): Fix spellling error in the word "explicitly".

Location:
trunk
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r261430 r261437  
     12020-05-08  Darin Adler  <darin@apple.com>
     2
     3        Streamline MarkupAccumulator to improve efficiency a bit
     4        https://bugs.webkit.org/show_bug.cgi?id=211656
     5
     6        Reviewed by Anders Carlsson.
     7
     8        * b3/air/AirFixPartialRegisterStalls.h: Fix spelling of "explicitly".
     9
    1102020-05-08  Alexey Shvayka  <shvaikalesh@gmail.com>
    211
  • trunk/Source/JavaScriptCore/b3/air/AirFixPartialRegisterStalls.h

    r206525 r261437  
    3636// Some instructions update only part of a register, they can only be scheduled after
    3737// the previous definition is computed. This problem can be avoided by the compiler
    38 // by explicitely resetting the entire register before executing the instruction with
     38// by explicitly resetting the entire register before executing the instruction with
    3939// partial update.
    4040//
  • trunk/Source/WTF/ChangeLog

    r261436 r261437  
     12020-05-08  Darin Adler  <darin@apple.com>
     2
     3        Streamline MarkupAccumulator to improve efficiency a bit
     4        https://bugs.webkit.org/show_bug.cgi?id=211656
     5
     6        Reviewed by Anders Carlsson.
     7
     8        * wtf/text/StringBuilder.cpp:
     9        (WTF::StringBuilder::isAllASCII const): Added.
     10        * wtf/text/StringBuilder.h: Added isAllASCII.
     11
    1122020-05-09  David Quesada  <david_quesada@apple.com>
    213
  • trunk/Source/WTF/wtf/text/StringBuilder.cpp

    r254087 r261437  
    457457}
    458458
     459bool StringBuilder::isAllASCII() const
     460{
     461    auto length = this->length();
     462    if (!length)
     463        return true;
     464    if (m_is8Bit)
     465        return charactersAreAllASCII(characters8(), length);
     466    return charactersAreAllASCII(characters16(), length);
     467}
     468
    459469} // namespace WTF
  • trunk/Source/WTF/wtf/text/StringBuilder.h

    r254087 r261437  
    326326   
    327327    bool is8Bit() const { return m_is8Bit; }
     328    WTF_EXPORT_PRIVATE bool isAllASCII() const;
    328329
    329330    void clear()
  • trunk/Source/WebCore/ChangeLog

    r261434 r261437  
     12020-05-08  Darin Adler  <darin@apple.com>
     2
     3        Streamline MarkupAccumulator to improve efficiency a bit
     4        https://bugs.webkit.org/show_bug.cgi?id=211656
     5
     6        Reviewed by Anders Carlsson.
     7
     8        * editing/MarkupAccumulator.cpp:
     9        (WebCore::MarkupAccumulator::appendCharactersReplacingEntities): Corrected early
     10        exit so it returns any time the length is 0. For some reason the code before
     11        wouldn't do the early return when offset is non-zero, which is unnecessary.
     12        (WebCore::MarkupAccumulator::appendString): Deleted.
     13        (WebCore::MarkupAccumulator::appendStringView): Deleted.
     14        (WebCore::MarkupAccumulator::appendEndTag): Use variadic append to cut down
     15        on memory allocations.
     16        (WebCore::MarkupAccumulator::totalLength): Deleted.
     17        (WebCore::MarkupAccumulator::concatenateMarkup): Deleted.
     18        (WebCore::MarkupAccumulator::takeMarkup): Added.
     19        (WebCore::MarkupAccumulator::appendQuotedURLAttributeValue): Use variadic
     20        append to cut down on memory allocations. Also use char instead of UChar so
     21        the string building code doesn't have to do an 8/16 bit check.
     22        (WebCore::shouldAddNamespaceElement): Prepend a literal, don't bother to
     23        make a String just to append to another String. Also made this a
     24        non-member function.
     25        (WebCore::shouldAddNamespaceAttribute): Made this a non-member function.
     26        (WebCore::MarkupAccumulator::appendNamespace): Fix hash table usage
     27        to use add instead of get followed by set to avoid double hashing.
     28        Use variadic append to cut down on memory allocation.
     29        (WebCore::MarkupAccumulator::appendText): Tweaked style to make this a
     30        one-line function.
     31        (WebCore::appendComment): Deleted.
     32        (WebCore::appendXMLDeclaration): Made this a non-member function.
     33        Use variadic append to cut down on memory allocation.
     34        (WebCore::appendDocumentType): Made this a non-member function.
     35        Use variadic append to cut down on memory allocation.
     36        (WebCore::MarkupAccumulator::appendCDATASection): Deleted.
     37        (WebCore::MarkupAccumulator::appendNonElementNode): Moved the bodies of
     38        appendComment, appendProcessingInstruction, and appendCDATASection in
     39        here since they can all be one-line variadic append calls.
     40
     41        * editing/MarkupAccumulator.h:
     42        (WebCore::MarkupAccumulator::length const): Changed the return type
     43        of length to be unsigned since that's what StringBuilder returns.
     44        Made isAllASCII call StringBuilder::isAllASCII. Replaced appendString
     45        and appendStringView with variadic append. Removed many functions
     46        that no longer need to be member functions. Made appendAttributeValue
     47        a static member function. Made appendNamespace private. Made
     48        m_serializationSyntax const.
     49
     50        * editing/markup.cpp:
     51        (WebCore::StyledMarkupAccumulator::wrapWithStyleNode): Use append
     52        instead of appenString.
     53        (WebCore::StyledMarkupAccumulator::isAllASCII const): Added. Before
     54        the code would only check the StringBuilder, but we also need to
     55        check m_reversedPrecedingMarkup.
     56        (WebCore::StyledMarkupAccumulator::takeResults): Use CheckedUint32
     57        since StringBuilder's reserveCapacity function takes unsigned, not
     58        size_t. The old code, using totalLength, would just pass a size_t
     59        and let it get chopped off, which didn't do any harm, but it seems
     60        strange to compute a 64-bit value just to chop off the lower 32
     61        bits. An alternative is to compute the 32-bit value and just let
     62        it overflow. Use a modern for loop by defining a ReverseView
     63        template rather than writing a confusing backwards loop. Use the
     64        new takeMarkup instead of concatenateMarkup.
     65        (WebCore::StyledMarkupAccumulator::appendText): Tweak coding
     66        style a little bit.
     67        (WebCore::StyledMarkupAccumulator::appendStartTag): Ditto.
     68        (WebCore::StyledMarkupAccumulator::appendNodeToPreserveMSOList):
     69        Use variadic append to cut down on memory allocations.
     70        (WebCore::propertyMissingOrEqualToNone): Tweak coding style a bit.
     71        (WebCore::serializePreservingVisualAppearanceInternal): Use
     72        append instead of appendString.
     73        (WebCore::shouldPreserveMSOLists): Take a StringView instead of a
     74        String to eliminate unnecessary memory allocation in call to substring.
     75        (WebCore::sanitizedMarkupForFragmentInDocument): Use makeString
     76        instead of StringBuilder to cut down on memory allocation.
     77
     78        * html/HTMLFormElement.cpp:
     79        (WebCore::HTMLFormElement::resetDefaultButton): Fix spelling error
     80        in the word "explicitly".
     81        * mathml/MathMLOperatorDictionary.cpp:
     82        (WebCore::MathMLOperatorDictionary::search): Ditto.
     83
     84        * page/PageSerializer.cpp:
     85        (WebCore::PageSerializer::SerializerMarkupAccumulator::SerializerMarkupAccumulator):
     86        Use variadic append instead of appendString to cut down on
     87        memory allocations.
     88
     89        * rendering/svg/SVGInlineTextBox.cpp:
     90        (WebCore::SVGInlineTextBox::paint): Fix spelling error in the word
     91        "explicitly".
     92
    1932020-05-09  Jack Lee  <shihchieh_lee@apple.com>
    294
  • trunk/Source/WebCore/editing/MarkupAccumulator.cpp

    r253988 r261437  
    161161void MarkupAccumulator::appendCharactersReplacingEntities(StringBuilder& result, const String& source, unsigned offset, unsigned length, EntityMask entityMask)
    162162{
    163     if (!(offset + length))
    164         return;
    165 
    166163    ASSERT(offset + length <= source.length());
     164
     165    if (!length)
     166        return;
    167167
    168168    if (source.is8Bit())
     
    236236}
    237237
    238 void MarkupAccumulator::appendString(const String& string)
    239 {
    240     m_markup.append(string);
    241 }
    242 
    243 void MarkupAccumulator::appendStringView(StringView view)
    244 {
    245     m_markup.append(view);
    246 }
    247 
    248238void MarkupAccumulator::startAppendingNode(const Node& node, Namespaces* namespaces)
    249239{
     
    261251    if (shouldSelfClose(element, m_serializationSyntax) || (!element.hasChildNodes() && elementCannotHaveEndTag(element)))
    262252        return;
    263     result.append('<');
    264     result.append('/');
    265     result.append(element.nodeNamePreservingCase());
    266     result.append('>');
    267 }
    268 
    269 size_t MarkupAccumulator::totalLength(const Vector<String>& strings)
    270 {
    271     size_t length = 0;
    272     for (auto& string : strings)
    273         length += string.length();
    274     return length;
    275 }
    276 
    277 void MarkupAccumulator::concatenateMarkup(StringBuilder& result)
    278 {
    279     result.append(m_markup);
     253    result.append("</", element.nodeNamePreservingCase(), '>');
     254}
     255
     256StringBuilder MarkupAccumulator::takeMarkup()
     257{
     258    return std::exchange(m_markup, { });
    280259}
    281260
     
    294273    ASSERT(element.isURLAttribute(attribute));
    295274    String resolvedURLString = resolveURLIfNeeded(element, attribute.value());
    296     UChar quoteChar = '"';
     275    char quoteChar = '"';
    297276    if (WTF::protocolIsJavaScript(resolvedURLString)) {
    298277        // minimal escaping for javascript urls
     
    303282                quoteChar = '\'';
    304283        }
    305         result.append(quoteChar);
    306         result.append(resolvedURLString);
    307         result.append(quoteChar);
     284        result.append(quoteChar, resolvedURLString, quoteChar);
    308285        return;
    309286    }
     
    315292}
    316293
    317 bool MarkupAccumulator::shouldAddNamespaceElement(const Element& element)
     294static bool shouldAddNamespaceElement(const Element& element)
    318295{
    319296    // Don't add namespace attribute if it is already defined for this elem.
    320     const AtomString& prefix = element.prefix();
     297    auto& prefix = element.prefix();
    321298    if (prefix.isEmpty())
    322299        return !element.hasAttribute(xmlnsAtom());
    323 
    324     static NeverDestroyed<String> xmlnsWithColon(MAKE_STATIC_STRING_IMPL("xmlns:"));
    325     return !element.hasAttribute(xmlnsWithColon.get() + prefix);
    326 }
    327 
    328 bool MarkupAccumulator::shouldAddNamespaceAttribute(const Attribute& attribute, Namespaces& namespaces)
     300    return !element.hasAttribute("xmlns:" + prefix);
     301}
     302
     303static bool shouldAddNamespaceAttribute(const Attribute& attribute, Namespaces& namespaces)
    329304{
    330305    namespaces.checkConsistency();
     
    357332    }
    358333
    359     // Use emptyAtom()s's impl() for both null and empty strings since the HashMap can't handle 0 as a key
    360     AtomStringImpl* pre = prefix.isEmpty() ? emptyAtom().impl() : prefix.impl();
    361     AtomStringImpl* foundNS = namespaces.get(pre);
    362     if (foundNS != namespaceURI.impl()) {
    363         namespaces.set(pre, namespaceURI.impl());
    364         // Add namespace to prefix pair so we can do constraint checking later.
    365         if (inXMLFragmentSerialization() && !prefix.isEmpty())
    366             namespaces.set(namespaceURI.impl(), pre);
    367         // Make sure xml prefix and namespace are always known to uphold the constraints listed at http://www.w3.org/TR/xml-names11/#xmlReserved.
    368         if (namespaceURI.impl() == XMLNames::xmlNamespaceURI->impl())
     334    // Use emptyAtom()s's impl() for null strings since this HashMap can't handle nullptr as a key
     335    auto addResult = namespaces.add(prefix.isNull() ? emptyAtom().impl() : prefix.impl(), namespaceURI.impl());
     336    if (!addResult.isNewEntry) {
     337        if (addResult.iterator->value == namespaceURI.impl())
    369338            return;
    370         result.append(' ', xmlnsAtom());
    371         if (!prefix.isEmpty())
    372             result.append(':', prefix);
    373 
    374         result.append('=');
    375         result.append('"');
    376         appendAttributeValue(result, namespaceURI, false);
    377         result.append('"');
    378     }
     339        addResult.iterator->value = namespaceURI.impl();
     340    }
     341
     342    // Add namespace to prefix pair so we can do constraint checking later.
     343    if (inXMLFragmentSerialization() && !prefix.isEmpty())
     344        namespaces.set(namespaceURI.impl(), prefix.impl());
     345
     346    // Make sure xml prefix and namespace are always known to uphold the constraints listed at http://www.w3.org/TR/xml-names11/#xmlReserved.
     347    if (namespaceURI == XMLNames::xmlNamespaceURI)
     348        return;
     349
     350    result.append(' ', xmlnsAtom(), prefix.isEmpty() ? "" : ":", prefix, "=\"");
     351    appendAttributeValue(result, namespaceURI, false);
     352    result.append('"');
    379353}
    380354
     
    395369void MarkupAccumulator::appendText(StringBuilder& result, const Text& text)
    396370{
    397     const String& textData = text.data();
    398     appendCharactersReplacingEntities(result, textData, 0, textData.length(), entityMaskForText(text));
    399 }
    400 
    401 static void appendComment(StringBuilder& result, const String& comment)
    402 {
    403     // FIXME: Comment content is not escaped, but XMLSerializer (and possibly other callers) should raise an exception if it includes "-->".
    404     result.appendLiteral("<!--");
    405     result.append(comment);
    406     result.appendLiteral("-->");
    407 }
    408 
    409 void MarkupAccumulator::appendXMLDeclaration(StringBuilder& result, const Document& document)
     371    appendCharactersReplacingEntities(result, text.data(), 0, text.length(), entityMaskForText(text));
     372}
     373
     374static void appendXMLDeclaration(StringBuilder& result, const Document& document)
    410375{
    411376    if (!document.hasXMLDeclaration())
    412377        return;
    413378
    414     result.appendLiteral("<?xml version=\"");
    415     result.append(document.xmlVersion());
    416     const String& encoding = document.xmlEncoding();
    417     if (!encoding.isEmpty()) {
    418         result.appendLiteral("\" encoding=\"");
    419         result.append(encoding);
    420     }
    421     if (document.xmlStandaloneStatus() != Document::StandaloneStatus::Unspecified) {
    422         result.appendLiteral("\" standalone=\"");
    423         if (document.xmlStandalone())
    424             result.appendLiteral("yes");
    425         else
    426             result.appendLiteral("no");
    427     }
    428 
    429     result.appendLiteral("\"?>");
    430 }
    431 
    432 void MarkupAccumulator::appendDocumentType(StringBuilder& result, const DocumentType& documentType)
     379    auto encoding = document.xmlEncoding();
     380    bool isStandaloneSpecified = document.xmlStandaloneStatus() != Document::StandaloneStatus::Unspecified;
     381
     382    result.append("<?xml version=\"",
     383        document.xmlVersion(),
     384        encoding.isEmpty() ? "" : "\" encoding=\"",
     385        encoding,
     386        isStandaloneSpecified ? (document.xmlStandalone() ? "\" standalone=\"yes" : "\" standalone=\"no") : "",
     387        "\"?>");
     388}
     389
     390static void appendDocumentType(StringBuilder& result, const DocumentType& documentType)
    433391{
    434392    if (documentType.name().isEmpty())
    435393        return;
    436394
    437     result.appendLiteral("<!DOCTYPE ");
    438     result.append(documentType.name());
    439     if (!documentType.publicId().isEmpty()) {
    440         result.appendLiteral(" PUBLIC \"");
    441         result.append(documentType.publicId());
    442         result.append('"');
    443         if (!documentType.systemId().isEmpty()) {
    444             result.append(' ');
    445             result.append('"');
    446             result.append(documentType.systemId());
    447             result.append('"');
    448         }
    449     } else if (!documentType.systemId().isEmpty()) {
    450         result.appendLiteral(" SYSTEM \"");
    451         result.append(documentType.systemId());
    452         result.append('"');
    453     }
    454     result.append('>');
    455 }
    456 
    457 void MarkupAccumulator::appendProcessingInstruction(StringBuilder& result, const String& target, const String& data)
    458 {
    459     // FIXME: PI data is not escaped, but XMLSerializer (and possibly other callers) this should raise an exception if it includes "?>".
    460     result.append('<');
    461     result.append('?');
    462     result.append(target);
    463     result.append(' ');
    464     result.append(data);
    465     result.append('?');
    466     result.append('>');
     395    result.append(
     396        "<!DOCTYPE ",
     397        documentType.name(),
     398        documentType.publicId().isEmpty() ? "" : " PUBLIC \"",
     399        documentType.publicId(),
     400        documentType.publicId().isEmpty() ? "" : "\"",
     401        documentType.systemId().isEmpty() ? "" : (documentType.publicId().isEmpty() ? " SYSTEM \"" : " \""),
     402        documentType.systemId(),
     403        documentType.systemId().isEmpty() ? ">" : "\">"
     404    );
    467405}
    468406
     
    598536}
    599537
    600 void MarkupAccumulator::appendCDATASection(StringBuilder& result, const String& section)
    601 {
    602     // FIXME: CDATA content is not escaped, but XMLSerializer (and possibly other callers) should raise an exception if it includes "]]>".
    603     result.appendLiteral("<![CDATA[");
    604     result.append(section);
    605     result.appendLiteral("]]>");
    606 }
    607 
    608538void MarkupAccumulator::appendNonElementNode(StringBuilder& result, const Node& node, Namespaces* namespaces)
    609539{
     
    616546        break;
    617547    case Node::COMMENT_NODE:
    618         appendComment(result, downcast<Comment>(node).data());
     548        // FIXME: Comment content is not escaped, but that may be OK because XMLSerializer (and possibly other callers) should raise an exception if it includes "-->".
     549        result.append("<!--", downcast<Comment>(node).data(), "-->");
    619550        break;
    620551    case Node::DOCUMENT_NODE:
     
    627558        break;
    628559    case Node::PROCESSING_INSTRUCTION_NODE:
    629         appendProcessingInstruction(result, downcast<ProcessingInstruction>(node).target(), downcast<ProcessingInstruction>(node).data());
     560        // FIXME: PI data is not escaped, but XMLSerializer (and possibly other callers) this should raise an exception if it includes "?>".
     561        result.append("<?", downcast<ProcessingInstruction>(node).target(), ' ', downcast<ProcessingInstruction>(node).data(), "?>");
    630562        break;
    631563    case Node::ELEMENT_NODE:
     
    633565        break;
    634566    case Node::CDATA_SECTION_NODE:
    635         appendCDATASection(result, downcast<CDATASection>(node).data());
     567        // FIXME: CDATA content is not escaped, but XMLSerializer (and possibly other callers) should raise an exception if it includes "]]>".
     568        result.append("<![CDATA[", downcast<CDATASection>(node).data(), "]]>");
    636569        break;
    637570    case Node::ATTRIBUTE_NODE:
  • trunk/Source/WebCore/editing/MarkupAccumulator.h

    r261395 r261437  
    6868
    6969protected:
    70     static size_t totalLength(const Vector<String>&);
    71     size_t length() const { return m_markup.length(); }
    72     bool isAllASCII() const { return m_markup.toStringPreserveCapacity().isAllASCII(); }
     70    unsigned length() const { return m_markup.length(); }
     71    bool isAllASCII() const { return m_markup.isAllASCII(); }
    7372
    74     void concatenateMarkup(StringBuilder&);
     73    StringBuilder takeMarkup();
    7574
    76     void appendString(const String&);
    77     void appendStringView(StringView);
     75    template<typename ...StringTypes> void append(StringTypes&&... strings) { m_markup.append(std::forward<StringTypes>(strings)...); }
    7876
    7977    void startAppendingNode(const Node&, Namespaces* = nullptr);
    80     void endAppendingNode(const Node& node)
    81     {
    82         if (is<Element>(node))
    83             appendEndTag(m_markup, downcast<Element>(node));
    84     }
     78    void endAppendingNode(const Node&);
    8579
    8680    virtual void appendStartTag(StringBuilder&, const Element&, Namespaces*);
     
    9387
    9488    void appendNonElementNode(StringBuilder&, const Node&, Namespaces*);
    95     void appendEndMarkup(StringBuilder&, const Element&);
    9689
    97     void appendAttributeValue(StringBuilder&, const String&, bool isSerializingHTML);
    98     void appendNamespace(StringBuilder&, const AtomString& prefix, const AtomString& namespaceURI, Namespaces&, bool allowEmptyDefaultNS = false);
    99     void appendXMLDeclaration(StringBuilder&, const Document&);
    100     void appendDocumentType(StringBuilder&, const DocumentType&);
    101     void appendProcessingInstruction(StringBuilder&, const String& target, const String& data);
     90    static void appendAttributeValue(StringBuilder&, const String&, bool isSerializingHTML);
    10291    void appendAttribute(StringBuilder&, const Element&, const Attribute&, Namespaces*);
    103     void appendCDATASection(StringBuilder&, const String&);
    10492
    105     bool shouldAddNamespaceElement(const Element&);
    106     bool shouldAddNamespaceAttribute(const Attribute&, Namespaces&);
    10793    EntityMask entityMaskForText(const Text&) const;
    10894
     
    11096
    11197private:
     98    void appendNamespace(StringBuilder&, const AtomString& prefix, const AtomString& namespaceURI, Namespaces&, bool allowEmptyDefaultNS = false);
    11299    String resolveURLIfNeeded(const Element&, const String&) const;
    113100    void appendQuotedURLAttributeValue(StringBuilder&, const Element&, const Attribute&);
     
    119106    StringBuilder m_markup;
    120107    const ResolveURLs m_resolveURLs;
    121     SerializationSyntax m_serializationSyntax;
     108    const SerializationSyntax m_serializationSyntax;
    122109    unsigned m_prefixLevel { 0 };
    123110};
    124111
     112inline void MarkupAccumulator::endAppendingNode(const Node& node)
     113{
     114    if (is<Element>(node))
     115        appendEndTag(m_markup, downcast<Element>(node));
     116}
     117
    125118} // namespace WebCore
  • trunk/Source/WebCore/editing/markup.cpp

    r261395 r261437  
    8787using namespace HTMLNames;
    8888
    89 static bool propertyMissingOrEqualToNone(StyleProperties*, CSSPropertyID);
     89static bool propertyMissingOrEqualToNone(const StyleProperties*, CSSPropertyID);
    9090
    9191class AttributeChange {
     
    232232    bool needClearingDiv() const { return m_needClearingDiv; }
    233233
    234     using MarkupAccumulator::appendString;
     234    using MarkupAccumulator::append;
    235235
    236236    ContainerNode* parentNode(Node& node)
     
    243243    void prependMetaCharsetUTF8TagIfNonASCIICharactersArePresent()
    244244    {
    245         if (isAllASCII())
    246             return;
    247 
    248         m_reversedPrecedingMarkup.append("<meta charset=\"UTF-8\">"_s);
     245        if (!isAllASCII())
     246            m_reversedPrecedingMarkup.append("<meta charset=\"UTF-8\">"_s);
    249247    }
    250248
    251249private:
     250    bool isAllASCII() const;
    252251    void appendStyleNodeOpenTag(StringBuilder&, StyleProperties*, Document&, bool isBlock = false);
    253252    const String& styleNodeCloseTag(bool isBlock = false);
     
    365364    appendStyleNodeOpenTag(openTag, style, document, isBlock);
    366365    m_reversedPrecedingMarkup.append(openTag.toString());
    367     appendString(styleNodeCloseTag(isBlock));
     366    append(styleNodeCloseTag(isBlock));
    368367}
    369368
     
    387386}
    388387
     388bool StyledMarkupAccumulator::isAllASCII() const
     389{
     390    for (auto& preceding : m_reversedPrecedingMarkup) {
     391        if (!preceding.isAllASCII())
     392            return false;
     393    }
     394    return MarkupAccumulator::isAllASCII();
     395}
     396
     397// Stopgap until C++20 adds std::ranges::reverse_view.
     398template<typename Collection> struct ReverseView {
     399    Collection& collection;
     400    decltype(collection.rbegin()) begin() const { return collection.rbegin(); }
     401    decltype(collection.rend()) end() const { return collection.rend(); }
     402    decltype(collection.size()) size() const { return collection.size(); }
     403    ReverseView(Collection& collection)
     404        : collection(collection)
     405    {
     406    }
     407};
     408
    389409String StyledMarkupAccumulator::takeResults()
    390410{
     411    CheckedUint32 length = this->length();
     412    for (auto& string : m_reversedPrecedingMarkup)
     413        length += string.length();
    391414    StringBuilder result;
    392     result.reserveCapacity(totalLength(m_reversedPrecedingMarkup) + length());
    393 
    394     for (size_t i = m_reversedPrecedingMarkup.size(); i > 0; --i)
    395         result.append(m_reversedPrecedingMarkup[i - 1]);
    396 
    397     concatenateMarkup(result);
    398 
    399     // We remove '\0' characters because they are not visibly rendered to the user.
     415    result.reserveCapacity(length.unsafeGet());
     416    for (auto& string : ReverseView { m_reversedPrecedingMarkup })
     417        result.append(string);
     418    result.append(takeMarkup());
     419    // Remove '\0' characters because they are not visibly rendered to the user.
    400420    return result.toString().replaceWithLiteral('\0', "");
    401421}
     
    406426    const bool wrappingSpan = shouldApplyWrappingStyle(text) && !parentIsTextarea;
    407427    if (wrappingSpan) {
    408         RefPtr<EditingStyle> wrappingStyle = m_wrappingStyle->copy();
     428        auto wrappingStyle = m_wrappingStyle->copy();
    409429        // FIXME: <rdar://problem/5371536> Style rules that match pasted content can change it's appearance
    410430        // Make sure spans are inline style in paste side e.g. span { display: block }.
     
    565585            out.appendLiteral(" style=\"");
    566586            appendAttributeValue(out, newInlineStyle->style()->asText(), documentIsHTML);
    567             out.append('\"');
     587            out.append('"');
    568588        }
    569589    }
     
    722742            return false;
    723743
    724         appendString("<head><style class=\"" WebKitMSOListQuirksStyle "\">\n<!--\n");
    725         appendStringView(StringView(textChild.data()).substring(start, msoListDefinitionsEnd - start + 3));
    726         appendString("\n-->\n</style></head>");
     744        append("<head><style class=\"" WebKitMSOListQuirksStyle "\">\n<!--\n",
     745            StringView(textChild.data()).substring(start, msoListDefinitionsEnd - start + 3),
     746            "\n-->\n</style></head>");
    727747
    728748        return true;
     
    755775}
    756776
    757 static bool propertyMissingOrEqualToNone(StyleProperties* style, CSSPropertyID propertyID)
     777static bool propertyMissingOrEqualToNone(const StyleProperties* style, CSSPropertyID propertyID)
    758778{
    759779    if (!style)
    760780        return false;
    761     RefPtr<CSSValue> value = style->getPropertyCSSValue(propertyID);
    762     if (!value)
    763         return true;
    764     if (!is<CSSPrimitiveValue>(*value))
    765         return false;
    766     return downcast<CSSPrimitiveValue>(*value).valueID() == CSSValueNone;
     781    auto value = style->getPropertyCSSValue(propertyID);
     782    return !value || (is<CSSPrimitiveValue>(*value) && downcast<CSSPrimitiveValue>(*value).valueID() == CSSValueNone);
    767783}
    768784
     
    870886            return interchangeNewlineString;
    871887
    872         accumulator.appendString(interchangeNewlineString);
     888        accumulator.append(interchangeNewlineString.get());
    873889        startAdjustedForInterchangeNewline = visibleStart.next().deepEquivalent();
    874890
     
    916932    if (accumulator.needRelativeStyleWrapper() && needsPositionStyleConversion) {
    917933        if (accumulator.needClearingDiv())
    918             accumulator.appendString("<div style=\"clear: both;\"></div>");
     934            accumulator.append("<div style=\"clear: both;\"></div>");
    919935        RefPtr<EditingStyle> positionRelativeStyle = styleFromMatchedRulesAndInlineDecl(*body);
    920936        positionRelativeStyle->style()->setProperty(CSSPropertyPosition, CSSValueRelative);
     
    924940    // FIXME: The interchange newline should be placed in the block that it's in, not after all of the content, unconditionally.
    925941    if (annotate == AnnotateForInterchange::Yes && needInterchangeNewlineAfter(visibleEnd.previous()))
    926         accumulator.appendString(interchangeNewlineString);
     942        accumulator.append(interchangeNewlineString.get());
    927943
    928944#if PLATFORM(COCOA)
     
    931947    accumulator.prependMetaCharsetUTF8TagIfNonASCIICharactersArePresent();
    932948#endif
     949
    933950    return accumulator.takeResults();
    934951}
     
    946963}
    947964
    948 
    949 static bool shouldPreserveMSOLists(const String& markup)
     965static bool shouldPreserveMSOLists(StringView markup)
    950966{
    951967    if (!markup.startsWith("<html xmlns:"))
     
    954970    if (tagClose == notFound)
    955971        return false;
    956     auto htmlTag = markup.substring(0, tagClose);
    957     return htmlTag.contains("xmlns:o=\"urn:schemas-microsoft-com:office:office\"")
    958         && htmlTag.contains("xmlns:w=\"urn:schemas-microsoft-com:office:word\"");
     972    auto tag = markup.substring(0, tagClose);
     973    return tag.contains("xmlns:o=\"urn:schemas-microsoft-com:office:office\"")
     974        && tag.contains("xmlns:w=\"urn:schemas-microsoft-com:office:word\"");
    959975}
    960976
     
    972988        ResolveURLs::YesExcludingLocalFileURLsForPrivacy, SerializeComposedTree::No, AnnotateForInterchange::Yes, ConvertBlocksToInlines::No,  StandardFontFamilySerializationMode::Strip, msoListMode);
    973989
    974     StringBuilder builder;
    975     if (msoListMode == MSOListMode::Preserve) {
    976         builder.appendLiteral("<html xmlns:o=\"urn:schemas-microsoft-com:office:office\"\n"
    977             "xmlns:w=\"urn:schemas-microsoft-com:office:word\"\n"
    978             "xmlns:m=\"http://schemas.microsoft.com/office/2004/12/omml\"\n"
    979             "xmlns=\"http://www.w3.org/TR/REC-html40\">");
    980     }
    981 
    982     builder.append(result);
    983 
    984     if (msoListMode == MSOListMode::Preserve)
    985         builder.appendLiteral("</html>");
    986 
    987     return builder.toString();
     990    if (msoListMode != MSOListMode::Preserve)
     991        return result;
     992
     993    return makeString(
     994        "<html xmlns:o=\"urn:schemas-microsoft-com:office:office\"\n"
     995        "xmlns:w=\"urn:schemas-microsoft-com:office:word\"\n"
     996        "xmlns:m=\"http://schemas.microsoft.com/office/2004/12/omml\"\n"
     997        "xmlns=\"http://www.w3.org/TR/REC-html40\">",
     998        result,
     999        "</html>");
    9881000}
    9891001
  • trunk/Source/WebCore/html/HTMLFormElement.cpp

    r261013 r261437  
    715715        // Computing the default button is not cheap, we don't want to do it unless needed.
    716716        // If there was no default button set, the only style to invalidate is the element
    717         // being added to the form. This is done explicitely in registerFormElement().
     717        // being added to the form. This is done explicitly in registerFormElement().
    718718        return;
    719719    }
  • trunk/Source/WebCore/mathml/MathMLOperatorDictionary.cpp

    r250216 r261437  
    11391139        return WTF::nullopt;
    11401140
    1141     // If we did not find the desired operator form and if it was not set explicitely, we use the first one in the following order: Infix, Prefix, Postfix.
     1141    // If we did not find the desired operator form and if it was not set explicitly, we use the first one in the following order: Infix, Prefix, Postfix.
    11421142    // This is to handle bad MathML markup without explicit <mrow> delimiters like "<mo>(</mo><mi>a</mi><mo>)</mo><mo>(</mo><mi>b</mi><mo>)</mo>" where innerfences should not be considered infix.
    11431143    if (auto* entry = tryBinarySearch<const Entry, UChar32>(dictionary, dictionarySize, character, ExtractChar)) {
  • trunk/Source/WebCore/page/PageSerializer.cpp

    r260709 r261437  
    114114    , m_document(document)
    115115{
    116     // MarkupAccumulator does not serialize the <?xml ... line, so we add it explicitely to ensure the right encoding is specified.
     116    // MarkupAccumulator does not serialize the <?xml ... line, so we add it explicitly to ensure the right encoding is specified.
    117117    if (m_document.isXMLDocument() || m_document.xmlStandalone())
    118         appendString("<?xml version=\"" + m_document.xmlVersion() + "\" encoding=\"" + m_document.charset() + "\"?>");
     118        append("<?xml version=\"", m_document.xmlVersion(), "\" encoding=\"", m_document.charset(), "\"?>");
    119119}
    120120
  • trunk/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp

    r258508 r261437  
    241241        return;
    242242
    243     // Note: We're explicitely not supporting composition & custom underlines and custom highlighters - unlike InlineTextBox.
     243    // Note: We're explicitly not supporting composition & custom underlines and custom highlighters - unlike InlineTextBox.
    244244    // If we ever need that for SVG, it's very easy to refactor and reuse the code.
    245245
  • trunk/Tools/ChangeLog

    r261429 r261437  
     12020-05-08  Darin Adler  <darin@apple.com>
     2
     3        Streamline MarkupAccumulator to improve efficiency a bit
     4        https://bugs.webkit.org/show_bug.cgi?id=211656
     5
     6        Reviewed by Anders Carlsson.
     7
     8        * TestWebKitAPI/Tests/WTF/StringImpl.cpp:
     9        (TestWebKitAPI::TEST): Fix spellling error in the word "explicitly".
     10
    1112020-05-08  David Kilzer  <ddkilzer@apple.com>
    212
  • trunk/Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp

    r255125 r261437  
    4242    ASSERT_TRUE(stringWithTemplate->is8Bit());
    4343
    44     // Constructor taking the size explicitely.
     44    // Constructor taking the size explicitly.
    4545    const char* programmaticStringData = "Explicit Size Literal";
    4646    auto programmaticString = StringImpl::createFromLiteral(programmaticStringData, strlen(programmaticStringData));
Note: See TracChangeset for help on using the changeset viewer.