⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 277744 in webkit


Ignore:
Timestamp:
May 19, 2021, 12:37:21 PM (5 years ago)
Author:
Darin Adler
Message:

Move CFStringRef and NSString support from StringBuilder into StringConcatenateCF
​https://bugs.webkit.org/show_bug.cgi?id=225839

Reviewed by Sam Weinig.

Source/JavaScriptCore:

  • inspector/ConsoleMessage.cpp:

(Inspector::ConsoleMessage::ConsoleMessage): Use StringBuilder::clear instead of
StringBuilder::resize; no advantage to the latter after calling StringBuilder::toString.

  • runtime/JSONObject.cpp:

(JSC::Stringifier::Holder::appendNextProperty): Update for name change of
StringBuilder::resize to StringBuilder::shrink.

  • runtime/TypeSet.cpp:

(JSC::StructureShape::stringRepresentation): Ditto.

Source/WebCore:

  • Modules/airplay/WebMediaSessionManager.cpp:

(WebCore::mediaProducerStateString): Use StringBuilder exclusively instead of
mixing it with makeString. Also updated for StringBuilder::shrink name.

  • html/HTMLTextFormControlElement.cpp:

(WebCore::stripTrailingNewline): Updated for StringBuilder::shrink name.

  • page/CaptionUserPreferencesMediaAF.cpp:

(WebCore::CaptionUserPreferencesMediaAF::captionsTextColor const): Tweaked
coding style a bit.
(WebCore::appendCSS): Use variadic StringBuilder::append instead of many
separate calls.
(WebCore::CaptionUserPreferencesMediaAF::captionsDefaultFontCSS const):
Tweaked coding style a bit, and use variadic StrinBuilder::append calls
to reduce the number of calls and streamline the code.
(WebCore::CaptionUserPreferencesMediaAF::captionsStyleSheetOverride const):
Ditto. Also removed unnecessary checks that strings are empty before appending.

  • page/scrolling/ScrollingCoordinator.cpp:

(WebCore::ScrollingCoordinator::synchronousScrollingReasonsAsText):
Updated for StringBuilder::shrink name.

  • platform/LayoutUnit.h: Updated for saturatedSum/Difference names.
  • platform/network/cocoa/NetworkStorageSessionCocoa.mm:

(WebCore::NetworkStorageSession::cookiesForSession const): Tweaked codin
style a bit, and use variadic StrinBuilder::append calls to reduce the
number of calls and streamline the code.

  • rendering/RenderCounter.cpp:

(WebCore::planCounter): Updated for saturatedSum name.

  • style/StyleBuilderCustom.h:

(WebCore::Style::BuilderCustom::applyValueCounter): Ditto.

  • svg/SVGPathStringBuilder.cpp:

(WebCore::SVGPathStringBuilder::result): Updated for StringBuilder::shrink name.

  • testing/Internals.cpp:

(WebCore::Internals::pageMediaState): Ditto.

  • xml/XSLTProcessorLibxslt.cpp:

(WebCore::saveResultToString): Ditto.

Source/WebKit:

  • UIProcess/WebsiteData/Cocoa/WebsiteDataStoreCocoa.mm:

(WebKit::WebsiteDataStore::platformSetNetworkParameters): Use makeString instead
of StringBuilder.

Source/WTF:

The new header makes CFStringRef and NSString work with string concatenation,
which means it now works with the variadic StringBuilder::append and makeString,
and still works with the single-argument StringBuilder::append. More efficient
that the old version because it does not allocate a temporary WTF::String for
the 16-bit character path.

Also made many other small improvements to the StringBuilder implementation.

  • WTF.xcodeproj/project.pbxproj: Added StringConcatenateCF.h.
  • wtf/CheckedArithmetic.h: Removed ConditionalCrashOnOverflow, which was only

here for use by StringBuilder, which does not use CheckedArithmetic any more.

  • wtf/PlatformFTW.cmake: Added StringConcatenateCF.h..
  • wtf/PlatformMac.cmake: Ditto.
  • wtf/PlatformWin.cmake: Ditto.
  • wtf/SaturatedArithmetic.h: Moved the contents of this file inside the

WTF namespace.
(WTF::signedAddInt32Overflows): Renamed this function. The type here is
important, and we are not doing anything to prevent type conversion or
create ambiguity, so it's good to be explicit in the function name.
(WTF::saturatedSum<int32_t>): Renamed this from saturatedAddition for
clarity. The function returns a sum, so that's a better name than calling
it "addition". Also, it's clearer to be explicit about the return type.
(WTF::signedSubtractInt32Overflows): Renamed. Same reason as above.
(WTF::saturatedDifference<int32_t>): Ditto.
(WTF::saturatedSum): Added. Does unsigned integer saturated addition.
This one can be written in a portable manner and still get really
efficient code on at least Intel and ARM64.
(WTF::saturatedSum): Added a function template that lets callers pass
larger number of arguments to saturatedSum, rather than exactly two.

  • wtf/text/StringBuilder.cpp:

(WTF::expandedCapacity): Renamed to use the term capacity rather than
length for the new required capacity.
(WTF::StringBuilder::didOverflow): Implement the new approach to
overflow, meaning we need to write the CRASH() here explicitly and
in the non-crashing mode, set m_length.
(WTF::StringBuilder::reifyString const): Changed the overflow check
into a RELEASE_ASSERT. This is now responsible for doing the check that
callers were doing earlier, so we want it in production builds. Also
simplified this since our m_length member is a simple integer now,
and removed the unused m_isReified.
(WTF::StringBuilder::shrink): Renamed this to shrink to match the
Vector::shrink function, since this has never supported making the
builder larger. Removed unnecessary overflow checks, since shrinking
cannot cause overflow.
(WTF::StringBuilder::allocateBuffer): Replaced two separate functions
with a single simpler function template. Removed extra overflow checks
because the StringImpl::tryCreateUninitialized function already does
the only overflow check we need. Also move to StringImpl::copyCharacters
for copying characters rather than using std::memcpy directly.
Removed code to set m_is8Bit and m_bufferCharacters.
(WTF::StringBuilder::reallocateBuffer): Replaced two separate
functions with a function template and a cover that calls the
appropriate instance of the template for places where we aren't
already in character-type-specific code paths. This version now
supports allocating a buffer for the first time in cases where
we have m_string and not m_buffer, which used to be handled at
the higher level. Removed code to set m_bufferCharacters.
(WTF::StringBuilder::reserveCapacity): Rewrote for simplicity.
By relying on the overflow checking inside reallocateBuffer and
allocateBuffer we no longer need checking of the passed-in value
at this level.
(WTF::StringBuilder::extendBufferForAppending): Removed the
version of this that takes additionalLength since it's
potentially confusing to have a family of functions that have the
same name and take the same type of argument, but interpret it
subtly differently. Streamlined the code using std::exchange.
This function now also includes the logic from the function named
extendBufferForAppendingWithoutOverflowCheck, which was subtly
misnamed since that was not the only semantic difference. Also
removed the ALWAYS_INLINE because the compiler will do the right
thing without such heavy handed advice.
(WTF::StringBuilder::extendBufferForAppendingSlowCase): Streamlined
this by using std::exchange and removed additional overflow checks
at this level since reallocateBuffer already does them. Also added
a check for the case where the new total length is 0, which would
not be handled correctly and efficiently by reallocateBuffer.
(WTF::StringBuilder::extendBufferForAppendingLChar): Renamed this
from extendBufferForAppending8, since it's now identical to calling
extendBufferForAppending<LChar>, except for inlining and linkage.
(WTF::StringBuilder::extendBufferForAppendingWithUpconvert):
Renamed this from extendBufferForAppending16. It is different from
the other extendBuffer functions because is supports upconverting
from LChar to UChar. Like the others it relies on allocateBuffer
for the overflow checking.
(WTF::StringBuilder::appendCharacters): Removed an unnecessary
assertion that the characters pointer is non-null; that will fail
in an obvious way without an assertion. Simplified the logic and
removed some invariant assertions that don't help us much. Changed
overflow checking by using saturatedSum to compute the new length.
In overflow cases, the new sum will be larger than the maximum
string length, but will fit in an unsigned, so we can pass it
down to lower levels and let functions like reallocateBuffer do
the actual overflow checking. Also use StringImpl::copyCharacters.
(WTF::StringBuilder::append): Removed the CFStringRef overload.
(WTF::StringBuilder::shouldShrinkToFit const): Rename this from
canShrink. Simplify the function a bit and remove the vague FIXME
that says "this should be tuned". That may be so, but the FIXME
is not really driving us to action.
(WTF::StringBuilder::shrinkToFit): Simplify by using the new
reallocateBuffer and std::exchange. Removed unneeded assertion
about overflow that doesn't help us maintain the invariant.
(WTF::StringBuilder::isAllASCII const): Was tempted to remove
this function, but for now just made it use the StringView
version for brevity.

  • wtf/text/StringBuilder.h: Removed many unneeded includes, and

notably included SaturatedArithmetic.h instead of
CheckedArithmetic.h because we now use the former instead of the
latter. Changed the overflow checking implementation to work
more simply based on saturated addition rather than Checked.
This allowed us to get rid of dependency on our own unique mode
for Checked, called ConditionalCrashOnOverflow. Removed a
comment about making a templatized version of StringBuilder.
We can do it if we like, but does not seem urgent. Moved
fucntion bodies out of the class definition so it's easier to
see what's going on in the class. Since m_length is now an
ordinary integer, the check for overflowed simply checks to see
if the length is larger than the maximum string length. When we
encounter overflow that is not about length computation, we set
the length to the maximum integer to indicate the failure.
Deleted the append overloads for CFStringRef and NSString.
Removed m_bufferCharacters, m_is8Bit, and m_isReified.
(WTF::StringBuilder::StringBuilder): Simplified the constructor
since we only have to initialize the m_shouldCrashOnOverflow member.
(WTF::StringBuilder::clear): Fixed a mistake where this was not
resetting the m_isReified flag.
(WTF::StringBuilder::swap): Updated for changes in the data members.
(WTF::StringBuilder::operator StringView const): Moved out of line.
Made sure to call the length() function so we crash if this is
called after overflow.
(WTF::StringBuilder::append): Remove some of the unnecessary checks
and special cases in the various versions of append. Most of the
checking is done inside appendCharacters, with only a few exceptions.
(WTF::StringBuilder::appendSubstring): Moved out of the class
definition without making significant changes.
(WTF::StringBuilder::appendCharacter): Ditto.
(WTF::StringBuilder::toString): Greatly simplified this function
by relying on overflow checking in the reifyString function instead
of doing it here and removing unneeded invariant assertions.
(WTF::StringBuilder::toStringPreserveCapacity const): Ditto.
(WTF::StringBuilder::toAtomString const): Rewrote this to streamline,
removing explicit overflow checks.
(WTF::StringBuilder::length const): Moved out of the class
definition without making significant changes.
(WTF::StringBuilder::capacity const): Ditto.
(WTF::StringBuilder::operator[] const): Ditto.
(WTF::StringBuilder::characters const): Implemented this operation
in the function template. Now rather than having this call the
characters8 and characters16 functions, they can call it.
(WTF::StringBuilder::getBufferCharacters<LChar>): Deleted.
(WTF::StringBuilder::getBufferCharacters<UChar>): Deleted.
(WTF::StringBuilder::appendFromAdapters): Use saturatedSum to
compute the required length, which allows the extendBuffer
functions to do overflow checking without having to take special
checked integer types for arguments.
(WTF::StringBuilder::equal): Implement using StringView.

  • wtf/text/StringBuilderJSON.cpp:

(WTF::StringBuilder::appendQuotedJSONString): Simplified the checked
arithmetic for computing the required capacity. Updated since we
removed m_bufferCharacters and changed the type of m_length.

  • wtf/text/cf/StringConcatenateCF.h: Added. Specializes StringTypeAdapter for

both CFStringRef and NSString *. If CFStringGetCStringPtr works for Latin-1, then
does the 8-bit code path, otherwise the 16-bit.

  • wtf/text/cocoa/TextStreamCocoa.mm: Include StringConcatenateCF.h, since it's

now needed to use CFStringRef with StringBuilder.

Tools:

  • TestWebKitAPI/Tests/WTF/SaturatedArithmeticOperations.cpp: Updated

tests for changes to SaturatedArithmetic.h.

  • TestWebKitAPI/Tests/WTF/StringBuilder.cpp: Updated tests for changes

to StringBuilder.

  • TestWebKitAPI/Tests/WebKit/GetUserMedia.mm:

(TestWebKitAPI::wkMediaCaptureStateString): Ditto.

  • WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:

Added include of StringConcatenateCF.h.
Added StringTypeAdapter for WKStringRef.
(WTR::styleDecToStr): Use ASCIILiteral instead of StringBuilder.
(WTR::string): Removed unneeded toWTFString since the WKStringRef
StringTypeAdapter takes care of it.
(WTR::string): Renamed from frameToStr. Use makeString.
(WTR::dumpResourceURL): Use append instead of appendLiteral.
(WTR::dumpFrameDescriptionSuitableForTestResult): Deleted.
(WTR::dumpLoadEvent): Use makeString.
(WTR::string): Renamed from a longer name. Return a String
instead of building in a StringBuilder. Use makeString.
(WTR::string): Ditto.
(WTR::dumpErrorDescriptionSuitableForTestResult): Removed
unneeded toWTFString.
(WTR::dumpFrameScrollPosition): Ditto.
(WTR::dumpDescendantFramesText): Ditto.
(WTR::InjectedBundlePage::dumpDOMAsWebArchive): Removed an
unneeded local variable.
(WTR::InjectedBundlePage::dump): Removed unneeded toWTFString.
(WTR::InjectedBundlePage::didReceiveTitleForFrame): Ditto.
(WTR::InjectedBundlePage::didFinishDocumentLoadForFrame):
Updated for functon name change.
(WTR::InjectedBundlePage::willSendRequestForFrame): Ditto.
Also use variadic append. Also use makeString.
(WTR::InjectedBundlePage::didReceiveResponseForResource): Ditto.
(WTR::InjectedBundlePage::didFinishLoadForResource): Ditto.
(WTR::InjectedBundlePage::didFailLoadForResource): Ditto.
(WTR::InjectedBundlePage::decidePolicyForNavigationAction): Ditto.
(WTR::InjectedBundlePage::decidePolicyForResponse): Ditto.
(WTR::InjectedBundlePage::willAddMessageToConsole): Ditto.
(WTR::InjectedBundlePage::willSetStatusbarText): Ditto.
(WTR::InjectedBundlePage::willRunJavaScriptPrompt): Ditto.
(WTR::InjectedBundlePage::didExceedDatabaseQuota): Ditto.
(WTR::InjectedBundlePage::shouldInsertNode): Ditto.
(WTR::InjectedBundlePage::shouldInsertText): Ditto.
(WTR::InjectedBundlePage::shouldDeleteRange): Ditto.
(WTR::InjectedBundlePage::shouldChangeSelectedRange): Ditto.
(WTR::InjectedBundlePage::shouldApplyStyle): Ditto.
(WTR::InjectedBundlePage::didBeginEditing): Ditto.
(WTR::InjectedBundlePage::didEndEditing): Ditto.
(WTR::InjectedBundlePage::didChange): Ditto.
(WTR::InjectedBundlePage::didChangeSelection): Ditto.
(WTR::InjectedBundlePage::dumpHistory): Ditto.

Location:
trunk
Files:
1 added
34 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r277727 r277744  
     12021-05-18  Darin Adler  <darin@apple.com>
     2
     3        Move CFStringRef and NSString support from StringBuilder into StringConcatenateCF
     4        https://bugs.webkit.org/show_bug.cgi?id=225839
     5
     6        Reviewed by Sam Weinig.
     7
     8        * inspector/ConsoleMessage.cpp:
     9        (Inspector::ConsoleMessage::ConsoleMessage): Use StringBuilder::clear instead of
     10        StringBuilder::resize; no advantage to the latter after calling StringBuilder::toString.
     11
     12        * runtime/JSONObject.cpp:
     13        (JSC::Stringifier::Holder::appendNextProperty): Update for name change of
     14        StringBuilder::resize to StringBuilder::shrink.
     15        * runtime/TypeSet.cpp:
     16        (JSC::StructureShape::stringRepresentation): Ditto.
     17
    1182021-05-19  Mark Lam  <mark.lam@apple.com>
    219
  • trunk/Source/JavaScriptCore/inspector/ConsoleMessage.cpp

    r272499 r277744  
    137137            if (builder.length()) {
    138138                m_jsonLogValues.append({ JSONLogValue::Type::String, builder.toString() });
    139                 builder.resize(0);
     139                builder.clear();
    140140            }
    141141
  • trunk/Source/JavaScriptCore/runtime/JSONObject.cpp

    r277437 r277744  
    576576            // an object property. In this case we don't want the separator and
    577577            // property name that we already appended, so roll back.
    578             builder.resize(rollBackPoint);
     578            builder.shrink(rollBackPoint);
    579579            break;
    580580    }
  • trunk/Source/JavaScriptCore/runtime/TypeSet.cpp

    r266885 r277744  
    420420
    421421    if (representation.length() >= 3)
    422         representation.resize(representation.length() - 2);
     422        representation.shrink(representation.length() - 2);
    423423
    424424    representation.append('}');
  • trunk/Source/WTF/ChangeLog

    r277740 r277744  
     12021-05-18  Darin Adler  <darin@apple.com>
     2
     3        Move CFStringRef and NSString support from StringBuilder into StringConcatenateCF
     4        https://bugs.webkit.org/show_bug.cgi?id=225839
     5
     6        Reviewed by Sam Weinig.
     7
     8        The new header makes CFStringRef and NSString work with string concatenation,
     9        which means it now works with the variadic StringBuilder::append and makeString,
     10        and still works with the single-argument StringBuilder::append. More efficient
     11        that the old version because it does not allocate a temporary WTF::String for
     12        the 16-bit character path.
     13
     14        Also made many other small improvements to the StringBuilder implementation.
     15
     16        * WTF.xcodeproj/project.pbxproj: Added StringConcatenateCF.h.
     17
     18        * wtf/CheckedArithmetic.h: Removed ConditionalCrashOnOverflow, which was only
     19        here for use by StringBuilder, which does not use CheckedArithmetic any more.
     20
     21        * wtf/PlatformFTW.cmake: Added StringConcatenateCF.h..
     22        * wtf/PlatformMac.cmake: Ditto.
     23        * wtf/PlatformWin.cmake: Ditto.
     24
     25        * wtf/SaturatedArithmetic.h: Moved the contents of this file inside the
     26        WTF namespace.
     27        (WTF::signedAddInt32Overflows): Renamed this function. The type here is
     28        important, and we are not doing anything to prevent type conversion or
     29        create ambiguity, so it's good to be explicit in the function name.
     30        (WTF::saturatedSum<int32_t>): Renamed this from saturatedAddition for
     31        clarity. The function returns a sum, so that's a better name than calling
     32        it "addition". Also, it's clearer to be explicit about the return type.
     33        (WTF::signedSubtractInt32Overflows): Renamed. Same reason as above.
     34        (WTF::saturatedDifference<int32_t>): Ditto.
     35        (WTF::saturatedSum): Added. Does unsigned integer saturated addition.
     36        This one can be written in a portable manner and still get really
     37        efficient code on at least Intel and ARM64.
     38        (WTF::saturatedSum): Added a function template that lets callers pass
     39        larger number of arguments to saturatedSum, rather than exactly two.
     40
     41        * wtf/text/StringBuilder.cpp:
     42        (WTF::expandedCapacity): Renamed to use the term capacity rather than
     43        length for the new required capacity.
     44        (WTF::StringBuilder::didOverflow): Implement the new approach to
     45        overflow, meaning we need to write the CRASH() here explicitly and
     46        in the non-crashing mode, set m_length.
     47        (WTF::StringBuilder::reifyString const): Changed the overflow check
     48        into a RELEASE_ASSERT. This is now responsible for doing the check that
     49        callers were doing earlier, so we want it in production builds. Also
     50        simplified this since our m_length member is a simple integer now,
     51        and removed the unused m_isReified.
     52        (WTF::StringBuilder::shrink): Renamed this to shrink to match the
     53        Vector::shrink function, since this has never supported making the
     54        builder larger. Removed unnecessary overflow checks, since shrinking
     55        cannot cause overflow.
     56        (WTF::StringBuilder::allocateBuffer): Replaced two separate functions
     57        with a single simpler function template. Removed extra overflow checks
     58        because the StringImpl::tryCreateUninitialized function already does
     59        the only overflow check we need. Also move to StringImpl::copyCharacters
     60        for copying characters rather than using std::memcpy directly.
     61        Removed code to set m_is8Bit and m_bufferCharacters.
     62        (WTF::StringBuilder::reallocateBuffer): Replaced two separate
     63        functions with a function template and a cover that calls the
     64        appropriate instance of the template for places where we aren't
     65        already in character-type-specific code paths. This version now
     66        supports allocating a buffer for the first time in cases where
     67        we have m_string and not m_buffer, which used to be handled at
     68        the higher level. Removed code to set m_bufferCharacters.
     69        (WTF::StringBuilder::reserveCapacity): Rewrote for simplicity.
     70        By relying on the overflow checking inside reallocateBuffer and
     71        allocateBuffer we no longer need checking of the passed-in value
     72        at this level.
     73        (WTF::StringBuilder::extendBufferForAppending): Removed the
     74        version of this that takes additionalLength since it's
     75        potentially confusing to have a family of functions that have the
     76        same name and take the same type of argument, but interpret it
     77        subtly differently. Streamlined the code using std::exchange.
     78        This function now also includes the logic from the function named
     79        extendBufferForAppendingWithoutOverflowCheck, which was subtly
     80        misnamed since that was not the only semantic difference. Also
     81        removed the ALWAYS_INLINE because the compiler will do the right
     82        thing without such heavy handed advice.
     83        (WTF::StringBuilder::extendBufferForAppendingSlowCase): Streamlined
     84        this by using std::exchange and removed additional overflow checks
     85        at this level since reallocateBuffer already does them. Also added
     86        a check for the case where the new total length is 0, which would
     87        not be handled correctly and efficiently by reallocateBuffer.
     88        (WTF::StringBuilder::extendBufferForAppendingLChar): Renamed this
     89        from extendBufferForAppending8, since it's now identical to calling
     90        extendBufferForAppending<LChar>, except for inlining and linkage.
     91        (WTF::StringBuilder::extendBufferForAppendingWithUpconvert):
     92        Renamed this from extendBufferForAppending16. It is different from
     93        the other extendBuffer functions because is supports upconverting
     94        from LChar to UChar. Like the others it relies on allocateBuffer
     95        for the overflow checking.
     96        (WTF::StringBuilder::appendCharacters): Removed an unnecessary
     97        assertion that the characters pointer is non-null; that will fail
     98        in an obvious way without an assertion. Simplified the logic and
     99        removed some invariant assertions that don't help us much. Changed
     100        overflow checking by using saturatedSum to compute the new length.
     101        In overflow cases, the new sum will be larger than the maximum
     102        string length, but will fit in an unsigned, so we can pass it
     103        down to lower levels and let functions like reallocateBuffer do
     104        the actual overflow checking. Also use StringImpl::copyCharacters.
     105        (WTF::StringBuilder::append): Removed the CFStringRef overload.
     106        (WTF::StringBuilder::shouldShrinkToFit const): Rename this from
     107        canShrink. Simplify the function a bit and remove the vague FIXME
     108        that says "this should be tuned". That may be so, but the FIXME
     109        is not really driving us to action.
     110        (WTF::StringBuilder::shrinkToFit): Simplify by using the new
     111        reallocateBuffer and std::exchange. Removed unneeded assertion
     112        about overflow that doesn't help us maintain the invariant.
     113        (WTF::StringBuilder::isAllASCII const): Was tempted to remove
     114        this function, but for now just made it use the StringView
     115        version for brevity.
     116
     117        * wtf/text/StringBuilder.h: Removed many unneeded includes, and
     118        notably included SaturatedArithmetic.h instead of
     119        CheckedArithmetic.h because we now use the former instead of the
     120        latter. Changed the overflow checking implementation to work
     121        more simply based on saturated addition rather than Checked.
     122        This allowed us to get rid of dependency on our own unique mode
     123        for Checked, called ConditionalCrashOnOverflow. Removed a
     124        comment about making a templatized version of StringBuilder.
     125        We can do it if we like, but does not seem urgent. Moved
     126        fucntion bodies out of the class definition so it's easier to
     127        see what's going on in the class. Since m_length is now an
     128        ordinary integer, the check for overflowed simply checks to see
     129        if the length is larger than the maximum string length. When we
     130        encounter overflow that is not about length computation, we set
     131        the length to the maximum integer to indicate the failure.
     132        Deleted the append overloads for CFStringRef and NSString.
     133        Removed m_bufferCharacters, m_is8Bit, and m_isReified.
     134        (WTF::StringBuilder::StringBuilder): Simplified the constructor
     135        since we only have to initialize the m_shouldCrashOnOverflow member.
     136        (WTF::StringBuilder::clear): Fixed a mistake where this was not
     137        resetting the m_isReified flag.
     138        (WTF::StringBuilder::swap): Updated for changes in the data members.
     139        (WTF::StringBuilder::operator StringView const): Moved out of line.
     140        Made sure to call the length() function so we crash if this is
     141        called after overflow.
     142        (WTF::StringBuilder::append): Remove some of the unnecessary checks
     143        and special cases in the various versions of append. Most of the
     144        checking is done inside appendCharacters, with only a few exceptions.
     145        (WTF::StringBuilder::appendSubstring): Moved out of the class
     146        definition without making significant changes.
     147        (WTF::StringBuilder::appendCharacter): Ditto.
     148        (WTF::StringBuilder::toString): Greatly simplified this function
     149        by relying on overflow checking in the reifyString function instead
     150        of doing it here and removing unneeded invariant assertions.
     151        (WTF::StringBuilder::toStringPreserveCapacity const): Ditto.
     152        (WTF::StringBuilder::toAtomString const): Rewrote this to streamline,
     153        removing explicit overflow checks.
     154        (WTF::StringBuilder::length const): Moved out of the class
     155        definition without making significant changes.
     156        (WTF::StringBuilder::capacity const): Ditto.
     157        (WTF::StringBuilder::operator[] const): Ditto.
     158        (WTF::StringBuilder::characters const): Implemented this operation
     159        in the function template. Now rather than having this call the
     160        characters8 and characters16 functions, they can call it.
     161        (WTF::StringBuilder::getBufferCharacters<LChar>): Deleted.
     162        (WTF::StringBuilder::getBufferCharacters<UChar>): Deleted.
     163        (WTF::StringBuilder::appendFromAdapters): Use saturatedSum to
     164        compute the required length, which allows the extendBuffer
     165        functions to do overflow checking without having to take special
     166        checked integer types for arguments.
     167        (WTF::StringBuilder::equal): Implement using StringView.
     168
     169        * wtf/text/StringBuilderJSON.cpp:
     170        (WTF::StringBuilder::appendQuotedJSONString): Simplified the checked
     171        arithmetic for computing the required capacity. Updated since we
     172        removed m_bufferCharacters and changed the type of m_length.
     173
     174        * wtf/text/cf/StringConcatenateCF.h: Added. Specializes StringTypeAdapter for
     175        both CFStringRef and NSString *. If CFStringGetCStringPtr works for Latin-1, then
     176        does the 8-bit code path, otherwise the 16-bit.
     177
     178        * wtf/text/cocoa/TextStreamCocoa.mm: Include StringConcatenateCF.h, since it's
     179        now needed to use CFStringRef with StringBuilder.
     180
    11812021-05-19  Sam Weinig  <weinig@apple.com>
    2182
  • trunk/Source/WTF/WTF.xcodeproj/project.pbxproj

    r277714 r277744  
    502502                93B5B44D2213D616004B7AA7 /* HexNumber.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HexNumber.cpp; sourceTree = "<group>"; };
    503503                93B5B45022171EE9004B7AA7 /* Logger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Logger.cpp; sourceTree = "<group>"; };
     504                93D0017B264DBACF00BCF109 /* StringConcatenateCF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringConcatenateCF.h; sourceTree = "<group>"; };
    504505                93D191CF20CAECE800C51B8E /* objcSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = objcSPI.h; sourceTree = "<group>"; };
    505506                93DDE9311CDC052D00FD3491 /* dyldSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dyldSPI.h; sourceTree = "<group>"; };
    … …  
    928929                                A5BA15F7182435A600A82E69 /* AtomStringImplCF.cpp */,
    929930                                A5BA15F8182435A600A82E69 /* StringCF.cpp */,
     931                                93D0017B264DBACF00BCF109 /* StringConcatenateCF.h */,
    930932                                A5BA15F9182435A600A82E69 /* StringImplCF.cpp */,
    931933                                93934BD418A1F16900D0D6A1 /* StringViewCF.cpp */,
  • trunk/Source/WTF/wtf/CheckedArithmetic.h

    r276577 r277744  
    9696};
    9797
    98 class ConditionalCrashOnOverflow {
    99 public:
    100     void overflowed()
    101     {
    102         m_overflowed = true;
    103         if (m_shouldCrashOnOverflow)
    104             crash();
    105     }
    106 
    107     bool shouldCrashOnOverflow() const { return m_shouldCrashOnOverflow; }
    108     void setShouldCrashOnOverflow(bool value) { m_shouldCrashOnOverflow = value; }
    109 
    110     bool hasOverflowed() const { return m_overflowed; }
    111     void clearOverflow() { m_overflowed = false; }
    112 
    113     static NO_RETURN_DUE_TO_CRASH void crash()
    114     {
    115         CRASH();
    116     }
    117 
    118 private:
    119     bool m_overflowed { false };
    120     bool m_shouldCrashOnOverflow { true };
    121 };
    122 
    12398class CrashOnOverflow {
    12499public:
    … …  
    250225template <typename T> struct RemoveChecked {
    251226    typedef T CleanType;
    252     static constexpr CleanType DefaultValue = 0;
    253 };
    254 
    255 template <typename T> struct RemoveChecked<Checked<T, ConditionalCrashOnOverflow>> {
    256     using CleanType = typename RemoveChecked<T>::CleanType;
    257227    static constexpr CleanType DefaultValue = 0;
    258228};
    … …  
    10701040using WTF::CheckedUint64;
    10711041using WTF::CheckedSize;
    1072 using WTF::ConditionalCrashOnOverflow;
    10731042using WTF::CrashOnOverflow;
    10741043using WTF::RecordOverflow;
  • trunk/Source/WTF/wtf/PlatformFTW.cmake

    r255491 r277744  
    4040        cf/TypeCastsCF.h
    4141
     42        text/cf/StringConcatenateCF.h
    4243        text/cf/TextBreakIteratorCF.h
    4344    )
  • trunk/Source/WTF/wtf/PlatformMac.cmake

    r275484 r277744  
    4242    spi/mac/MetadataSPI.h
    4343
     44    text/cf/StringConcatenateCF.h
    4445    text/cf/TextBreakIteratorCF.h
    4546)
  • trunk/Source/WTF/wtf/PlatformWin.cmake

    r260477 r277744  
    3838        cf/TypeCastsCF.h
    3939
     40        text/cf/StringConcatenateCF.h
    4041        text/cf/TextBreakIteratorCF.h
    4142    )
  • trunk/Source/WTF/wtf/SaturatedArithmetic.h

    r237099 r277744  
    11/*
    22 * Copyright (c) 2012, Google Inc. All rights reserved.
    3  * Copyright (C) 2014 Apple Inc. All rights reserved.
     3 * Copyright (C) 2014-2021 Apple Inc. All rights reserved.
    44 *
    55 * Redistribution and use in source and binary forms, with or without
    … …  
    3737#include <wtf/Compiler.h>
    3838
    39 inline bool signedAddOverflows(int32_t a, int32_t b, int32_t& result)
     39namespace WTF {
     40
     41// FIXME: Enhance this so it fails to compile calls where either of the arguments can be outside the range of the integral type instead of quietly converting.
     42template<typename SignedIntegralType> std::enable_if_t<std::is_integral_v<SignedIntegralType> && std::is_signed_v<SignedIntegralType>, SignedIntegralType> saturatedSum(SignedIntegralType, SignedIntegralType);
     43template<typename UnsignedIntegralType> constexpr std::enable_if_t<std::is_integral_v<UnsignedIntegralType> && !std::is_signed_v<UnsignedIntegralType>, UnsignedIntegralType> saturatedSum(UnsignedIntegralType, UnsignedIntegralType);
     44template<typename IntegralType> IntegralType saturatedDifference(IntegralType, IntegralType);
     45
     46inline bool signedAddInt32Overflows(int32_t a, int32_t b, int32_t& result)
    4047{
    4148#if COMPILER_HAS_CLANG_BUILTIN(__builtin_sadd_overflow) && !(defined __clang_major__ && __clang_major__ < 7)
    … …  
    5360}
    5461
    55 inline int32_t saturatedAddition(int32_t a, int32_t b)
     62template<> inline int32_t saturatedSum<int32_t>(int32_t a, int32_t b)
    5663{
    5764    int32_t result;
    … …  
    6370        );
    6471#else
    65     if (signedAddOverflows(a, b, result))
     72    if (signedAddInt32Overflows(a, b, result))
    6673        result = std::numeric_limits<int32_t>::max() + (static_cast<uint32_t>(a) >> 31);
    6774#endif
    … …  
    6976}
    7077
    71 inline bool signedSubtractOverflows(int32_t a, int32_t b, int32_t& result)
     78inline bool signedSubtractInt32Overflows(int32_t a, int32_t b, int32_t& result)
    7279{
    7380#if COMPILER_HAS_CLANG_BUILTIN(__builtin_ssub_overflow) && !(defined __clang_major__ && __clang_major__ < 7)
    … …  
    8592}
    8693
    87 inline int32_t saturatedSubtraction(int32_t a, int32_t b)
     94// FIXME: Enhance this so it fails to compile calls where either of the arguments can be outside the range of int32_t instead of quietly converting.
     95template<> inline int32_t saturatedDifference<int32_t>(int32_t a, int32_t b)
    8896{
    8997    int32_t result;
    … …  
    95103        );
    96104#else
    97     if (signedSubtractOverflows(a, b, result))
     105    if (signedSubtractInt32Overflows(a, b, result))
    98106        result = std::numeric_limits<int32_t>::max() + (static_cast<uint32_t>(a) >> 31);
    99107#endif
    100108    return result;
    101109}
     110
     111template<typename UnsignedIntegralType> constexpr std::enable_if_t<std::is_integral_v<UnsignedIntegralType> && !std::is_signed_v<UnsignedIntegralType>, UnsignedIntegralType> saturatedSum(UnsignedIntegralType a, UnsignedIntegralType b)
     112{
     113    auto sum = a + b;
     114    return sum < a ? std::numeric_limits<UnsignedIntegralType>::max() : sum;
     115}
     116
     117template<typename IntegralType, typename... ArgumentTypes> constexpr uint32_t saturatedSum(IntegralType value, ArgumentTypes... arguments)
     118{
     119    return saturatedSum<IntegralType>(value, saturatedSum<IntegralType>(arguments...));
     120}
     121
     122}
     123
     124using WTF::saturatedSum;
     125using WTF::saturatedDifference;
  • trunk/Source/WTF/wtf/text/StringBuilder.cpp

    r277437 r277744  
    11/*
    2  * Copyright (C) 2010-2019 Apple Inc. All rights reserved.
     2 * Copyright (C) 2010-2021 Apple Inc. All rights reserved.
    33 * Copyright (C) 2012 Google Inc. All rights reserved.
    44 *
    … …  
    3434static constexpr unsigned maxCapacity = String::MaxLength;
    3535
    36 static unsigned expandedCapacity(unsigned capacity, unsigned requiredLength)
     36static unsigned expandedCapacity(unsigned capacity, unsigned requiredCapacity)
    3737{
    3838    static constexpr unsigned minimumCapacity = 16;
    39     return std::max(requiredLength, std::max(minimumCapacity, std::min(capacity * 2, maxCapacity)));
     39    return std::max(requiredCapacity, std::max(minimumCapacity, std::min(capacity * 2, maxCapacity)));
     40}
     41
     42void StringBuilder::didOverflow()
     43{
     44    if (m_shouldCrashOnOverflow)
     45        CRASH();
     46    m_length = std::numeric_limits<unsigned>::max();
    4047}
    4148
    4249void StringBuilder::reifyString() const
    4350{
    44     ASSERT(!hasOverflowed());
     51    RELEASE_ASSERT(!hasOverflowed());
    4552
    4653    // Check if the string already exists.
    4754    if (!m_string.isNull()) {
    48         ASSERT(m_string.length() == m_length.unsafeGet<unsigned>());
    49         return;
    50     }
    51 
    52 #if ASSERT_ENABLED
    53     m_isReified = true;
    54 #endif
     55        ASSERT(m_string.length() == m_length);
     56        return;
     57    }
    5558
    5659    // Check for empty.
    … …  
    6164
    6265    // Must be valid in the buffer, take a substring (unless string fills the buffer).
    63     ASSERT(m_buffer && m_length.unsafeGet<unsigned>() <= m_buffer->length());
    64     if (m_length.unsafeGet<unsigned>() == m_buffer->length())
     66    ASSERT(m_length <= m_buffer->length());
     67    if (m_length == m_buffer->length())
    6568        m_string = m_buffer.get();
    6669    else
    67         m_string = StringImpl::createSubstringSharingImpl(*m_buffer, 0, m_length.unsafeGet());
    68 }
    69 
    70 void StringBuilder::resize(unsigned newSize)
     70        m_string = StringImpl::createSubstringSharingImpl(*m_buffer, 0, m_length);
     71}
     72
     73void StringBuilder::shrink(unsigned newLength)
    7174{
    7275    if (hasOverflowed())
    7376        return;
    7477
    75     // Check newSize < m_length, hence m_length > 0.
    76     unsigned oldLength = m_length.unsafeGet();
    77     ASSERT(newSize <= oldLength);
    78     if (newSize == oldLength)
    79         return;
    80     ASSERT(oldLength);
    81 
    82     m_length = newSize;
     78    ASSERT(newLength <= m_length);
     79    if (newLength >= m_length) {
     80        if (newLength > m_length)
     81            didOverflow();
     82        return;
     83    }
     84
     85    m_length = newLength;
     86
     87    if (m_buffer) {
     88        m_string = { }; // Clear the string to remove the reference to m_buffer if any before checking the reference count of m_buffer.
     89        if (m_buffer->hasOneRef()) {
     90            // If the old buffer had only the one ref, we can just reduce the length and keep using the buffer.
     91            return;
     92        }
     93        // Allocate a fresh buffer, with a copy of the characters we are keeping.
     94        if (m_buffer->is8Bit())
     95            allocateBuffer<LChar>(m_buffer->characters<LChar>(), newLength);
     96        else
     97            allocateBuffer<UChar>(m_buffer->characters<UChar>(), newLength);
     98        return;
     99    }
     100
     101    // Since the old length was not 0 and m_buffer is null, m_string is guaranteed to be non-null.
     102    m_string = StringImpl::createSubstringSharingImpl(*m_string.impl(), 0, newLength);
     103}
     104
     105// Allocate a new buffer, copying in currentCharacters (these may come from either m_string or m_buffer.
     106template<typename AllocationCharacterType, typename CurrentCharacterType> void StringBuilder::allocateBuffer(const CurrentCharacterType* currentCharacters, unsigned requiredCapacity)
     107{
     108    AllocationCharacterType* bufferCharacters;
     109    auto buffer = StringImpl::tryCreateUninitialized(requiredCapacity, bufferCharacters);
     110    if (UNLIKELY(!buffer)) {
     111        didOverflow();
     112        return;
     113    }
     114
    83115    ASSERT(!hasOverflowed());
    84 
    85     // If there is a buffer, we only need to duplicate it if it has more than one ref.
     116    StringImpl::copyCharacters(bufferCharacters, currentCharacters, m_length);
     117
     118    m_buffer = WTFMove(buffer);
     119    m_string = { };
     120}
     121
     122template<typename CharacterType> void StringBuilder::reallocateBuffer(unsigned requiredCapacity)
     123{
     124    // If the buffer has only one ref (by this StringBuilder), reallocate it.
    86125    if (m_buffer) {
    87         m_string = String(); // Clear the string to remove the reference to m_buffer if any before checking the reference count of m_buffer.
    88         if (!m_buffer->hasOneRef()) {
    89             if (m_buffer->is8Bit())
    90                 allocateBuffer(m_buffer->characters8(), m_buffer->length());
     126        m_string = { }; // Clear the string to remove the reference to m_buffer if any before checking the reference count of m_buffer.
     127        if (m_buffer->hasOneRef()) {
     128            CharacterType* bufferCharacters;
     129            auto buffer = StringImpl::tryReallocate(m_buffer.releaseNonNull(), requiredCapacity, bufferCharacters);
     130            if (UNLIKELY(!buffer)) {
     131                didOverflow();
     132                return;
     133            }
     134            m_buffer = WTFMove(*buffer);
     135            return;
     136        }
     137    }
     138
     139    allocateBuffer<CharacterType>(characters<CharacterType>(), requiredCapacity);
     140}
     141
     142void StringBuilder::reallocateBuffer(unsigned requiredCapacity)
     143{
     144    if (is8Bit())
     145        reallocateBuffer<LChar>(requiredCapacity);
     146    else
     147        reallocateBuffer<UChar>(requiredCapacity);
     148}
     149
     150void StringBuilder::reserveCapacity(unsigned newCapacity)
     151{
     152    if (hasOverflowed())
     153        return;
     154
     155    if (m_buffer) {
     156        if (newCapacity > m_buffer->length())
     157            reallocateBuffer(newCapacity);
     158    } else {
     159        if (newCapacity > m_length) {
     160            if (!m_length)
     161                allocateBuffer<LChar>(static_cast<LChar*>(nullptr), newCapacity);
     162            else if (m_string.is8Bit())
     163                allocateBuffer<LChar>(m_string.characters8(), newCapacity);
    91164            else
    92                 allocateBuffer(m_buffer->characters16(), m_buffer->length());
     165                allocateBuffer<UChar>(m_string.characters16(), newCapacity);
    93166        }
    94         ASSERT(hasOverflowed() || m_buffer->length() >= m_length.unsafeGet<unsigned>());
    95         return;
    96     }
    97 
    98     // Since m_length && !m_buffer, the string must be valid in m_string, and m_string.length() > 0.
    99     ASSERT(!m_string.isEmpty());
    100     ASSERT(oldLength == m_string.length());
    101     ASSERT(newSize < m_string.length());
    102     m_string = StringImpl::createSubstringSharingImpl(*m_string.impl(), 0, newSize);
    103 }
    104 
    105 // Allocate a new 8 bit buffer, copying in currentCharacters (these may come from either m_string
    106 // or m_buffer, neither will be reassigned until the copy has completed).
    107 void StringBuilder::allocateBuffer(const LChar* currentCharacters, unsigned requiredLength)
     167    }
     168    ASSERT(hasOverflowed() || !newCapacity || m_buffer->length() >= newCapacity);
     169}
     170
     171// Make 'additionalLength' additional capacity be available in m_buffer, update m_string & m_length to use,
     172// that capacity and return a pointer to the newly allocated storage so the caller can write characters there.
     173// Returns nullptr if allocation fails, length overflows, or if total capacity is 0 so no buffer is needed.
     174// The caller has the responsibility for checking that CharacterType is the type of the existing buffer.
     175template<typename CharacterType> CharacterType* StringBuilder::extendBufferForAppending(unsigned requiredLength)
     176{
     177    if (m_buffer && requiredLength <= m_buffer->length()) {
     178        m_string = { };
     179        return const_cast<CharacterType*>(m_buffer->characters<CharacterType>()) + std::exchange(m_length, requiredLength);
     180    }
     181    return extendBufferForAppendingSlowCase<CharacterType>(requiredLength);
     182}
     183
     184// Shared by the other extendBuffer functions.
     185template<typename CharacterType> CharacterType* StringBuilder::extendBufferForAppendingSlowCase(unsigned requiredLength)
    108186{
    109187    ASSERT(!hasOverflowed());
    110     ASSERT(m_is8Bit);
    111     // Copy the existing data into a new buffer, set result to point to the end of the existing data.
    112     auto buffer = StringImpl::tryCreateUninitialized(requiredLength, m_bufferCharacters8);
    113     if (UNLIKELY(!buffer))
    114         return didOverflow();
    115 
    116     if (m_length)
    117         std::memcpy(m_bufferCharacters8, currentCharacters, m_length.unsafeGet());
    118 
    119     // Update the builder state.
    120     m_buffer = WTFMove(buffer);
    121     m_string = String();
    122     ASSERT(m_buffer->length() == requiredLength);
    123 }
    124 
    125 // Allocate a new 16 bit buffer, copying in currentCharacters (these may come from either m_string
    126 // or m_buffer,  neither will be reassigned until the copy has completed).
    127 void StringBuilder::allocateBuffer(const UChar* currentCharacters, unsigned requiredLength)
    128 {
    129     ASSERT(!hasOverflowed());
    130     ASSERT(!m_is8Bit);
    131     // Copy the existing data into a new buffer, set result to point to the end of the existing data.
    132     auto buffer = StringImpl::tryCreateUninitialized(requiredLength, m_bufferCharacters16);
    133     if (UNLIKELY(!buffer))
    134         return didOverflow();
    135     std::memcpy(m_bufferCharacters16, currentCharacters, static_cast<size_t>(m_length.unsafeGet()) * sizeof(UChar)); // This can't overflow.
    136    
    137     // Update the builder state.
    138     m_buffer = WTFMove(buffer);
    139     m_string = String();
    140     ASSERT(m_buffer->length() == requiredLength);
    141 }
    142 
    143 // Allocate a new 16 bit buffer, copying in currentCharacters (which is 8 bit and may come
    144 // from either m_string or m_buffer, neither will be reassigned until the copy has completed).
    145 void StringBuilder::allocateBufferUpConvert(const LChar* currentCharacters, unsigned requiredLength)
    146 {
    147     ASSERT(!hasOverflowed());
    148     ASSERT(m_is8Bit);
    149     unsigned length = m_length.unsafeGet();
    150     ASSERT(requiredLength <= maxCapacity && requiredLength >= length);
    151     // Copy the existing data into a new buffer, set result to point to the end of the existing data.
    152     auto buffer = StringImpl::tryCreateUninitialized(requiredLength, m_bufferCharacters16);
    153     if (UNLIKELY(!buffer))
    154         return didOverflow(); // Treat a failure to allcoate as an overflow.
    155     for (unsigned i = 0; i < length; ++i)
    156         m_bufferCharacters16[i] = currentCharacters[i];
    157    
    158     m_is8Bit = false;
    159    
    160     // Update the builder state.
    161     m_buffer = WTFMove(buffer);
    162     m_string = String();
    163     ASSERT(m_buffer->length() == requiredLength);
    164 }
    165 
    166 template<>
    167 void StringBuilder::reallocateBuffer<LChar>(unsigned requiredLength)
    168 {
    169     // If the buffer has only one ref (by this StringBuilder), reallocate it,
    170     // otherwise fall back to "allocate and copy" method.
    171     m_string = String();
    172    
    173     ASSERT(m_is8Bit);
    174     ASSERT(m_buffer->is8Bit());
    175    
    176     if (m_buffer->hasOneRef()) {
    177         auto expectedStringImpl = StringImpl::tryReallocate(m_buffer.releaseNonNull(), requiredLength, m_bufferCharacters8);
    178         if (UNLIKELY(!expectedStringImpl))
    179             return didOverflow();
    180         m_buffer = WTFMove(expectedStringImpl.value());
    181     } else
    182         allocateBuffer(m_buffer->characters8(), requiredLength);
    183     ASSERT(hasOverflowed() || m_buffer->length() == requiredLength);
    184 }
    185 
    186 template<>
    187 void StringBuilder::reallocateBuffer<UChar>(unsigned requiredLength)
    188 {
    189     // If the buffer has only one ref (by this StringBuilder), reallocate it,
    190     // otherwise fall back to "allocate and copy" method.
    191     m_string = String();
    192    
    193     if (m_buffer->is8Bit())
    194         allocateBufferUpConvert(m_buffer->characters8(), requiredLength);
    195     else if (m_buffer->hasOneRef()) {
    196         auto expectedStringImpl = StringImpl::tryReallocate(m_buffer.releaseNonNull(), requiredLength, m_bufferCharacters16);
    197         if (UNLIKELY(!expectedStringImpl))
    198             return didOverflow();
    199         m_buffer = WTFMove(expectedStringImpl.value());
    200     } else
    201         allocateBuffer(m_buffer->characters16(), requiredLength);
    202     ASSERT(hasOverflowed() || m_buffer->length() == requiredLength);
    203 }
    204 
    205 void StringBuilder::reserveCapacity(unsigned newCapacity)
    206 {
    207     if (hasOverflowed())
    208         return;
    209     ASSERT(newCapacity <= String::MaxLength);
    210     if (m_buffer) {
    211         // If there is already a buffer, then grow if necessary.
    212         if (newCapacity > m_buffer->length()) {
    213             if (m_buffer->is8Bit())
    214                 reallocateBuffer<LChar>(newCapacity);
    215             else
    216                 reallocateBuffer<UChar>(newCapacity);
    217         }
    218     } else {
    219         // Grow the string, if necessary.
    220         unsigned length = m_length.unsafeGet();
    221         if (newCapacity > length) {
    222             if (!length) {
    223                 LChar* nullPlaceholder = nullptr;
    224                 allocateBuffer(nullPlaceholder, newCapacity);
    225             } else if (m_string.is8Bit())
    226                 allocateBuffer(m_string.characters8(), newCapacity);
    227             else
    228                 allocateBuffer(m_string.characters16(), newCapacity);
    229         }
    230     }
    231     ASSERT(hasOverflowed() || !newCapacity || m_buffer->length() >= newCapacity);
    232 }
    233 
    234 // Make 'additionalLength' additional capacity be available in m_buffer, update m_string & m_length,
    235 // return a pointer to the newly allocated storage.
    236 // Returns nullptr if the size of the new builder would have overflowed
    237 template<typename CharacterType> ALWAYS_INLINE CharacterType* StringBuilder::extendBufferForAppending(unsigned additionalLength)
    238 {
    239     ASSERT(additionalLength);
    240 
    241     // Calculate the new size of the builder after appending.
    242     CheckedInt32 requiredLength = m_length + additionalLength;
    243     if (requiredLength.hasOverflowed()) {
    244         didOverflow();
     188    if (!requiredLength)
    245189        return nullptr;
    246     }
    247 
    248     return extendBufferForAppendingWithoutOverflowCheck<CharacterType>(requiredLength);
    249 }
    250 
    251 template<typename CharacterType> ALWAYS_INLINE CharacterType* StringBuilder::extendBufferForAppendingWithoutOverflowCheck(CheckedInt32 requiredLength)
    252 {
    253     ASSERT(!requiredLength.hasOverflowed());
    254 
    255     if (m_buffer && (requiredLength.unsafeGet<unsigned>() <= m_buffer->length())) {
    256         // If the buffer is valid it must be at least as long as the current builder contents!
    257         ASSERT(m_buffer->length() >= m_length.unsafeGet<unsigned>());
    258         unsigned currentLength = m_length.unsafeGet();
    259         m_string = String();
    260         m_length = requiredLength;
    261         return getBufferCharacters<CharacterType>() + currentLength;
    262     }
    263 
    264     return extendBufferForAppendingSlowCase<CharacterType>(requiredLength.unsafeGet());
    265 }
    266 
    267 LChar* StringBuilder::extendBufferForAppending8(CheckedInt32 requiredLength)
    268 {
    269     if (UNLIKELY(requiredLength.hasOverflowed())) {
    270         didOverflow();
     190    reallocateBuffer(expandedCapacity(capacity(), requiredLength));
     191    if (UNLIKELY(hasOverflowed()))
    271192        return nullptr;
    272     }
    273     return extendBufferForAppendingWithoutOverflowCheck<LChar>(requiredLength);
    274 }
    275 
    276 UChar* StringBuilder::extendBufferForAppending16(CheckedInt32 requiredLength)
    277 {
    278     if (UNLIKELY(requiredLength.hasOverflowed())) {
    279         didOverflow();
    280         return nullptr;
    281     }
    282     if (m_is8Bit) {
    283         const LChar* characters;
    284         if (m_buffer) {
    285             ASSERT(m_buffer->length() >= m_length.unsafeGet<unsigned>());
    286             characters = m_buffer->characters8();
    287         } else {
    288             ASSERT(m_string.length() == m_length.unsafeGet<unsigned>());
    289             characters = m_string.isNull() ? nullptr : m_string.characters8();
    290         }
    291         allocateBufferUpConvert(characters, expandedCapacity(capacity(), requiredLength.unsafeGet()));
     193    return const_cast<CharacterType*>(m_buffer->characters<CharacterType>()) + std::exchange(m_length, requiredLength);
     194}
     195
     196// Alterative extendBufferForAppending that can be called from the header without inlining.
     197LChar* StringBuilder::extendBufferForAppendingLChar(unsigned requiredLength)
     198{
     199    return extendBufferForAppending<LChar>(requiredLength);
     200}
     201
     202UChar* StringBuilder::extendBufferForAppendingWithUpconvert(unsigned requiredLength)
     203{
     204    if (is8Bit()) {
     205        allocateBuffer<UChar>(characters<LChar>(), expandedCapacity(capacity(), requiredLength));
    292206        if (UNLIKELY(hasOverflowed()))
    293207            return nullptr;
    294         unsigned oldLength = m_length.unsafeGet();
    295         m_length = requiredLength.unsafeGet();
    296         return m_bufferCharacters16 + oldLength;
    297     }
    298     return extendBufferForAppendingWithoutOverflowCheck<UChar>(requiredLength);
    299 }
    300 
    301 // Make 'requiredLength' capacity be available in m_buffer, update m_string & m_length,
    302 // return a pointer to the newly allocated storage.
    303 template<typename CharacterType> CharacterType* StringBuilder::extendBufferForAppendingSlowCase(unsigned requiredLength)
    304 {
    305     ASSERT(!hasOverflowed());
    306     ASSERT(requiredLength);
    307 
    308     if (m_buffer) {
    309         // If the buffer is valid it must be at least as long as the current builder contents!
    310         ASSERT(m_buffer->length() >= m_length.unsafeGet<unsigned>());
    311        
    312         reallocateBuffer<CharacterType>(expandedCapacity(capacity(), requiredLength));
     208        return const_cast<UChar*>(m_buffer->characters<UChar>()) + std::exchange(m_length, requiredLength);
     209    }
     210    return extendBufferForAppending<UChar>(requiredLength);
     211}
     212
     213void StringBuilder::appendCharacters(const UChar* characters, unsigned length)
     214{
     215    if (!length || hasOverflowed())
     216        return;
     217    if (length == 1 && isLatin1(characters[0]) && is8Bit()) {
     218        append(static_cast<LChar>(characters[0]));
     219        return;
     220    }
     221    if (auto destination = extendBufferForAppendingWithUpconvert(saturatedSum<uint32_t>(m_length, length)))
     222        StringImpl::copyCharacters(destination, characters, length);
     223}
     224
     225void StringBuilder::appendCharacters(const LChar* characters, unsigned length)
     226{
     227    if (!length || hasOverflowed())
     228        return;
     229    if (is8Bit()) {
     230        if (auto destination = extendBufferForAppending<LChar>(saturatedSum<uint32_t>(m_length, length)))
     231            StringImpl::copyCharacters(destination, characters, length);
    313232    } else {
    314         ASSERT(m_string.length() == m_length.unsafeGet<unsigned>());
    315         allocateBuffer(m_length ? m_string.characters<CharacterType>() : nullptr, expandedCapacity(capacity(), requiredLength));
    316     }
    317     if (UNLIKELY(hasOverflowed()))
    318         return nullptr;
    319 
    320     CharacterType* result = getBufferCharacters<CharacterType>() + m_length.unsafeGet();
    321     m_length = requiredLength;
    322     ASSERT(!hasOverflowed());
    323     ASSERT(m_buffer->length() >= m_length.unsafeGet<unsigned>());
    324     return result;
    325 }
    326 
    327 void StringBuilder::appendCharacters(const UChar* characters, unsigned length)
    328 {
    329     if (!length || hasOverflowed())
    330         return;
    331 
    332     ASSERT(characters);
    333 
    334     if (m_is8Bit && length == 1 && isLatin1(characters[0])) {
    335         append(static_cast<LChar>(characters[0]));
    336         return;
    337     }
    338 
    339     // FIXME: Should we optimize memory by keeping the string 8-bit when all the characters are Latin-1?
    340 
    341     UChar* destination = extendBufferForAppending16(m_length + length);
    342     if (UNLIKELY(!destination))
    343         return;
    344     std::memcpy(destination, characters, static_cast<size_t>(length) * sizeof(UChar));
    345     ASSERT(!hasOverflowed());
    346     ASSERT(m_buffer->length() >= m_length.unsafeGet<unsigned>());
    347 }
    348 
    349 void StringBuilder::appendCharacters(const LChar* characters, unsigned length)
    350 {
    351     if (!length || hasOverflowed())
    352         return;
    353 
    354     ASSERT(characters);
    355 
    356     if (m_is8Bit) {
    357         LChar* destination = extendBufferForAppending<LChar>(length);
    358         if (!destination) {
    359             ASSERT(hasOverflowed());
    360             return;
    361         }
    362         if (length > 8)
    363             std::memcpy(destination, characters, length);
    364         else {
    365             // FIXME: How strong is our evidence that this is faster than memcpy? What platforms is this true for?
    366             const LChar* end = characters + length;
    367             while (characters < end)
    368                 *destination++ = *characters++;
    369         }
    370     } else {
    371         UChar* destination = extendBufferForAppending<UChar>(length);
    372         if (!destination) {
    373             ASSERT(hasOverflowed());
    374             return;
    375         }
    376         const LChar* end = characters + length;
    377         while (characters < end)
    378             *destination++ = *characters++;
    379     }
    380 }
    381 
    382 #if USE(CF)
    383 
    384 void StringBuilder::append(CFStringRef string)
    385 {
    386     // Fast path: avoid constructing a temporary String when possible.
    387     if (auto* characters = CFStringGetCStringPtr(string, kCFStringEncodingISOLatin1)) {
    388         appendCharacters(reinterpret_cast<const LChar*>(characters), CFStringGetLength(string));
    389         return;
    390     }
    391     append(String(string));
    392 }
    393 
    394 #endif
    395 
    396 bool StringBuilder::canShrink() const
    397 {
    398     if (hasOverflowed())
    399         return false;
    400     // Only shrink the buffer if it's less than 80% full.
    401     // FIXME: We should tune this heuristic based some actual test case measurements.
    402     unsigned length = m_length.unsafeGet();
    403     return m_buffer && m_buffer->length() > (length + (length >> 2));
     233        if (auto destination = extendBufferForAppending<UChar>(saturatedSum<uint32_t>(m_length, length)))
     234            StringImpl::copyCharacters(destination, characters, length);
     235    }
     236}
     237
     238bool StringBuilder::shouldShrinkToFit() const
     239{
     240    // Shrink the buffer if it's 80% full or less.
     241    static_assert(static_cast<size_t>(String::MaxLength) + (String::MaxLength >> 2) <= static_cast<size_t>(std::numeric_limits<unsigned>::max()));
     242    return !hasOverflowed() && m_buffer && m_buffer->length() > m_length + (m_length >> 2);
    404243}
    405244
    406245void StringBuilder::shrinkToFit()
    407246{
    408     if (canShrink()) {
    409         if (m_is8Bit)
    410             reallocateBuffer<LChar>(m_length.unsafeGet());
    411         else
    412             reallocateBuffer<UChar>(m_length.unsafeGet());
    413         ASSERT(!hasOverflowed());
    414         m_string = WTFMove(m_buffer);
     247    if (shouldShrinkToFit()) {
     248        reallocateBuffer(m_length);
     249        m_string = std::exchange(m_buffer, nullptr);
    415250    }
    416251}
    … …  
    418253bool StringBuilder::isAllASCII() const
    419254{
    420     auto length = this->length();
    421     if (!length)
    422         return true;
    423     if (m_is8Bit)
    424         return charactersAreAllASCII(characters8(), length);
    425     return charactersAreAllASCII(characters16(), length);
     255    return StringView { *this }.isAllASCII();
    426256}
    427257
  • trunk/Source/WTF/wtf/text/StringBuilder.h

    r277437 r277744  
    11/*
    2  * Copyright (C) 2009-2019 Apple Inc. All rights reserved.
     2 * Copyright (C) 2009-2021 Apple Inc. All rights reserved.
    33 * Copyright (C) 2012 Google Inc. All rights reserved.
    44 *
    … …  
    2727#pragma once
    2828
    29 #include <wtf/CheckedArithmetic.h>
    30 #include <wtf/text/AtomString.h>
    31 #include <wtf/text/IntegerToStringConversion.h>
     29#include <wtf/SaturatedArithmetic.h>
    3230#include <wtf/text/StringConcatenateNumbers.h>
    33 #include <wtf/text/StringView.h>
    34 #include <wtf/text/WTFString.h>
    3531
    3632namespace WTF {
    3733
    38 // StringBuilder currently uses a Checked<int32_t, ConditionalCrashOnOverflow> for m_length.
    39 // Ideally, we would want to make StringBuilder a template with an OverflowHandler parameter, and
    40 // m_length can be instantiated based on that OverflowHandler instead. However, currently, we're
    41 // not able to get clang to export explicitly instantiated template methods (which would be needed
    42 // if we templatize StringBuilder). As a workaround, we use the ConditionalCrashOnOverflow handler
    43 // instead to do a runtime check on whether it should crash on overflows or not.
    44 //
    45 // When clang is able to export explicitly instantiated template methods, we can templatize
    46 // StringBuilder and do away with ConditionalCrashOnOverflow.
    47 // See https://bugs.webkit.org/show_bug.cgi?id=191050.
    48 
    4934class StringBuilder {
    50     // Disallow copying since it's expensive and we don't want code to do it by accident.
     35    // Disallow copying since we don't want to share m_buffer between two builders.
    5136    WTF_MAKE_NONCOPYABLE(StringBuilder);
    5237    WTF_MAKE_FAST_ALLOCATED;
    5338
    5439public:
    55     enum class OverflowHandler {
    56         CrashOnOverflow,
    57         RecordOverflow
    58     };
    59 
    60     StringBuilder(OverflowHandler handler = OverflowHandler::CrashOnOverflow)
    61         : m_bufferCharacters8(nullptr)
    62     {
    63         m_length.setShouldCrashOnOverflow(handler == OverflowHandler::CrashOnOverflow);
    64     }
     40    StringBuilder() = default;
    6541    StringBuilder(StringBuilder&&) = default;
    6642    StringBuilder& operator=(StringBuilder&&) = default;
    6743
    68     ALWAYS_INLINE void didOverflow() { m_length.overflowed(); }
    69     ALWAYS_INLINE bool hasOverflowed() const { return m_length.hasOverflowed(); }
    70     ALWAYS_INLINE bool crashesOnOverflow() const { return m_length.shouldCrashOnOverflow(); }
     44    enum class OverflowHandler { CrashOnOverflow, RecordOverflow }; // FIXME: Despite its use in Checked<>, "handler" does not seem the correct name for this.
     45    explicit StringBuilder(OverflowHandler);
     46
     47    void clear();
     48    void swap(StringBuilder&);
     49
     50    void didOverflow();
     51    bool hasOverflowed() const { return m_length > String::MaxLength; }
     52    bool crashesOnOverflow() const { return m_shouldCrashOnOverflow; }
    7153
    7254    WTF_EXPORT_PRIVATE void appendCharacters(const UChar*, unsigned);
    7355    WTF_EXPORT_PRIVATE void appendCharacters(const LChar*, unsigned);
    74 
    75     ALWAYS_INLINE void appendCharacters(const char* characters, unsigned length) { appendCharacters(reinterpret_cast<const LChar*>(characters), length); }
    76 
    77     void append(const AtomString& atomString)
    78     {
    79         append(atomString.string());
    80     }
    81 
    82     void append(const String& string)
    83     {
    84         if (hasOverflowed())
    85             return;
    86 
    87         if (!string.length())
    88             return;
    89 
    90         // If we're appending to an empty string, and there is not a buffer (reserveCapacity has not been called)
    91         // then just retain the string.
    92         if (!m_length && !m_buffer) {
    93             m_string = string;
    94             m_length = string.length();
    95             m_is8Bit = m_string.is8Bit();
     56    void appendCharacters(const char* characters, unsigned length) { appendCharacters(reinterpret_cast<const LChar*>(characters), length); }
     57
     58    template<typename... StringTypes> void append(StringTypes...);
     59
     60    // FIXME: We should keep these overloads only if optimizations make them more efficient than the single-argument form of the variadic append above.
     61    void append(const AtomString& string) { append(string.string()); }
     62    void append(const String&);
     63    void append(StringView);
     64    void append(UChar);
     65    void append(LChar);
     66    void append(char character) { append(static_cast<LChar>(character)); }
     67    void append(const char*);
     68
     69    // FIXME: Add a StringTypeAdapter so we can append one string builder to another with variadic append.
     70    void append(const StringBuilder&);
     71
     72    template<unsigned characterCount> void appendLiteral(const char (&characters)[characterCount]) { appendCharacters(characters, characterCount - 1); }
     73
     74    void appendCharacter(UChar) = delete;
     75    void appendCharacter(LChar) = delete;
     76    void appendCharacter(char) = delete;
     77    void appendCharacter(UChar32);
     78
     79    void appendSubstring(const String&, unsigned offset, unsigned length = String::MaxLength);
     80    WTF_EXPORT_PRIVATE void appendQuotedJSONString(const String&);
     81
     82    // FIXME: Unclear why toString returns String and toStringPreserveCapacity returns const String&. Make them consistent.
     83    String toString();
     84    const String& toStringPreserveCapacity() const;
     85    AtomString toAtomString() const;
     86
     87    bool isEmpty() const { return !m_length; }
     88    unsigned length() const;
     89
     90    operator StringView() const;
     91    UChar operator[](unsigned i) const;
     92
     93    bool is8Bit() const;
     94    template<typename CharacterType> const CharacterType* characters() const;
     95    const LChar* characters8() const { return characters<LChar>(); }
     96    const UChar* characters16() const { return characters<UChar>(); }
     97   
     98    unsigned capacity() const;
     99    WTF_EXPORT_PRIVATE void reserveCapacity(unsigned newCapacity);
     100
     101    WTF_EXPORT_PRIVATE void shrink(unsigned newLength);
     102    WTF_EXPORT_PRIVATE bool shouldShrinkToFit() const;
     103    WTF_EXPORT_PRIVATE void shrinkToFit();
     104
     105    WTF_EXPORT_PRIVATE bool isAllASCII() const;
     106
     107private:
     108    template<typename AllocationCharacterType, typename CurrentCharacterType> void allocateBuffer(const CurrentCharacterType* currentCharacters, unsigned requiredCapacity);
     109    template<typename CharacterType> void reallocateBuffer(unsigned requiredCapacity);
     110    void reallocateBuffer(unsigned requiredCapacity);
     111
     112    template<typename CharacterType> CharacterType* extendBufferForAppending(unsigned requiredLength);
     113    template<typename CharacterType> CharacterType* extendBufferForAppendingSlowCase(unsigned requiredLength);
     114    WTF_EXPORT_PRIVATE LChar* extendBufferForAppendingLChar(unsigned requiredLength);
     115    WTF_EXPORT_PRIVATE UChar* extendBufferForAppendingWithUpconvert(unsigned requiredLength);
     116
     117    WTF_EXPORT_PRIVATE void reifyString() const;
     118
     119    template<typename... StringTypeAdapters> void appendFromAdapters(StringTypeAdapters...);
     120
     121    mutable String m_string;
     122    RefPtr<StringImpl> m_buffer;
     123    unsigned m_length { 0 };
     124    bool m_shouldCrashOnOverflow { true };
     125};
     126
     127template<> struct IntegerToStringConversionTrait<StringBuilder>;
     128
     129// FIXME: Move this to StringView and make it take a StringView instead of a StringBuilder?
     130template<typename CharacterType> bool equal(const StringBuilder&, const CharacterType*, unsigned length);
     131
     132// Inline function implementations.
     133
     134inline StringBuilder::StringBuilder(OverflowHandler policy)
     135    : m_shouldCrashOnOverflow { policy == OverflowHandler::CrashOnOverflow }
     136{
     137}
     138
     139inline void StringBuilder::clear()
     140{
     141    m_string = { };
     142    m_buffer = nullptr;
     143    m_length = 0;
     144    // We intentionally do not change m_shouldCrashOnOverflow.
     145}
     146
     147inline void StringBuilder::swap(StringBuilder& other)
     148{
     149    m_string.swap(other.m_string);
     150    m_buffer.swap(other.m_buffer);
     151    std::swap(m_length, other.m_length);
     152    std::swap(m_shouldCrashOnOverflow, other.m_shouldCrashOnOverflow);
     153}
     154
     155inline StringBuilder::operator StringView() const
     156{
     157    if (is8Bit())
     158        return { characters<LChar>(), length() };
     159    return { characters<UChar>(), length() };
     160}
     161
     162inline void StringBuilder::append(UChar character)
     163{
     164    if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) {
     165        if (!m_buffer->is8Bit()) {
     166            const_cast<UChar*>(m_buffer->characters<UChar>())[m_length++] = character;
    96167            return;
    97168        }
    98 
    99         if (string.is8Bit())
    100             appendCharacters(string.characters8(), string.length());
    101         else
    102             appendCharacters(string.characters16(), string.length());
    103     }
    104 
    105     void append(const StringBuilder& other)
    106     {
    107         if (hasOverflowed())
    108             return;
    109         if (other.hasOverflowed())
    110             return didOverflow();
    111 
    112         if (!other.m_length)
    113             return;
    114 
    115         // If we're appending to an empty string, and there is not a buffer (reserveCapacity has not been called)
    116         // then just retain the string.
    117         if (!m_length && !m_buffer && !other.m_string.isNull()) {
    118             m_string = other.m_string;
    119             m_length = other.m_length;
    120             m_is8Bit = other.m_is8Bit;
     169        if (isLatin1(character)) {
     170            const_cast<LChar*>(m_buffer->characters<LChar>())[m_length++] = static_cast<LChar>(character);
    121171            return;
    122172        }
    123 
    124         if (other.is8Bit())
    125             appendCharacters(other.characters8(), other.m_length.unsafeGet());
     173    }
     174    appendCharacters(&character, 1);
     175}
     176
     177inline void StringBuilder::append(LChar character)
     178{
     179    if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) {
     180        if (m_buffer->is8Bit())
     181            const_cast<LChar*>(m_buffer->characters<LChar>())[m_length++] = character;
    126182        else
    127             appendCharacters(other.characters16(), other.m_length.unsafeGet());
    128     }
    129 
    130     void append(StringView stringView)
    131     {
    132         if (stringView.is8Bit())
    133             appendCharacters(stringView.characters8(), stringView.length());
    134         else
    135             appendCharacters(stringView.characters16(), stringView.length());
    136     }
    137 
    138 #if USE(CF)
    139     WTF_EXPORT_PRIVATE void append(CFStringRef);
    140 #endif
    141 #if USE(CF) && defined(__OBJC__)
    142     void append(NSString *string) { append((__bridge CFStringRef)string); }
    143 #endif
    144    
    145     void appendSubstring(const String& string, unsigned offset, unsigned length = String::MaxLength)
    146     {
    147         if (offset >= string.length())
    148             return;
    149 
    150         unsigned clampedLength = std::min(length, string.length() - offset);
    151         if (string.is8Bit())
    152             appendCharacters(string.characters8() + offset, clampedLength);
    153         else
    154             appendCharacters(string.characters16() + offset, clampedLength);
    155     }
    156 
    157     void append(const char* characters)
    158     {
    159         if (characters)
    160             appendCharacters(characters, strlen(characters));
    161     }
    162 
    163     void appendCharacter(UChar) = delete;
    164     void append(UChar c)
    165     {
    166         if (hasOverflowed())
    167             return;
    168         unsigned length = m_length.unsafeGet<unsigned>();
    169         if (m_buffer && length < m_buffer->length() && m_string.isNull()) {
    170             if (!m_is8Bit) {
    171                 m_bufferCharacters16[length] = c;
    172                 m_length++;
    173                 return;
    174             }
    175 
    176             if (isLatin1(c)) {
    177                 m_bufferCharacters8[length] = static_cast<LChar>(c);
    178                 m_length++;
    179                 return;
    180             }
    181         }
    182         appendCharacters(&c, 1);
    183     }
    184 
    185     void appendCharacter(LChar) = delete;
    186     void append(LChar c)
    187     {
    188         if (hasOverflowed())
    189             return;
    190         unsigned length = m_length.unsafeGet<unsigned>();
    191         if (m_buffer && length < m_buffer->length() && m_string.isNull()) {
    192             if (m_is8Bit)
    193                 m_bufferCharacters8[length] = c;
    194             else
    195                 m_bufferCharacters16[length] = c;
    196             m_length++;
    197         } else
    198             appendCharacters(&c, 1);
    199     }
    200 
    201     void appendCharacter(char) = delete;
    202     void append(char c)
    203     {
    204         append(static_cast<LChar>(c));
    205     }
    206 
    207     void appendCharacter(UChar32 c)
    208     {
    209         if (U_IS_BMP(c)) {
    210             append(static_cast<UChar>(c));
    211             return;
    212         }
    213         append(U16_LEAD(c));
    214         append(U16_TRAIL(c));
    215     }
    216 
    217     WTF_EXPORT_PRIVATE void appendQuotedJSONString(const String&);
    218 
    219     template<unsigned characterCount>
    220     ALWAYS_INLINE void appendLiteral(const char (&characters)[characterCount]) { appendCharacters(characters, characterCount - 1); }
    221 
    222     template<typename... StringTypes> void append(StringTypes...);
    223 
    224     String toString()
    225     {
    226         if (!m_string.isNull()) {
    227             ASSERT(!m_buffer || m_isReified);
    228             ASSERT(!hasOverflowed());
    229             return m_string;
    230         }
    231 
    232         RELEASE_ASSERT(!hasOverflowed());
     183            const_cast<UChar*>(m_buffer->characters<UChar>())[m_length++] = character;
     184        return;
     185    }
     186    appendCharacters(&character, 1);
     187}
     188
     189inline void StringBuilder::append(const String& string)
     190{
     191    // If we're appending to an empty string, and there is not a buffer (reserveCapacity has not been called)
     192    // then just retain the string.
     193    if (!m_length && !m_buffer) {
     194        m_string = string;
     195        m_length = string.length();
     196        return;
     197    }
     198
     199    append(StringView { string });
     200}
     201
     202inline void StringBuilder::append(const StringBuilder& other)
     203{
     204    // If we're appending to an empty string, and there is not a buffer (reserveCapacity has not been called)
     205    // then just retain the string.
     206    if (!m_length && !m_buffer && !other.m_string.isNull()) {
     207        // Use the length function here so we crash on overflow without explicit overflow checks.
     208        m_string = other.m_string;
     209        m_length = other.length();
     210        return;
     211    }
     212
     213    append(StringView { other });
     214}
     215
     216inline void StringBuilder::append(StringView string)
     217{
     218    if (string.is8Bit())
     219        appendCharacters(string.characters8(), string.length());
     220    else
     221        appendCharacters(string.characters16(), string.length());
     222}
     223
     224inline void StringBuilder::appendSubstring(const String& string, unsigned offset, unsigned length)
     225{
     226    append(StringView { string }.substring(offset, length));
     227}
     228
     229inline void StringBuilder::append(const char* characters)
     230{
     231    append(StringView { characters });
     232}
     233
     234inline void StringBuilder::appendCharacter(UChar32 c)
     235{
     236    if (U_IS_BMP(c)) {
     237        append(static_cast<UChar>(c));
     238        return;
     239    }
     240    append(U16_LEAD(c));
     241    append(U16_TRAIL(c));
     242}
     243
     244inline String StringBuilder::toString()
     245{
     246    if (m_string.isNull()) {
    233247        shrinkToFit();
    234248        reifyString();
     249    }
     250    return m_string;
     251}
     252
     253inline const String& StringBuilder::toStringPreserveCapacity() const
     254{
     255    if (m_string.isNull())
     256        reifyString();
     257    return m_string;
     258}
     259
     260inline AtomString StringBuilder::toAtomString() const
     261{
     262    if (isEmpty())
     263        return emptyAtom();
     264
     265    // If the buffer is sufficiently over-allocated, make a new AtomString from a copy so its buffer is not so large.
     266    if (shouldShrinkToFit())
     267        return StringView { *this }.toAtomString();
     268
     269    if (!m_string.isNull())
    235270        return m_string;
    236     }
    237 
    238     const String& toStringPreserveCapacity() const
    239     {
    240         RELEASE_ASSERT(!hasOverflowed());
    241         if (m_string.isNull())
    242             reifyString();
    243         return m_string;
    244     }
    245 
    246     AtomString toAtomString() const
    247     {
    248         RELEASE_ASSERT(!hasOverflowed());
    249         if (!m_length)
    250             return emptyAtom();
    251 
    252         // If the buffer is sufficiently over-allocated, make a new AtomString from a copy so its buffer is not so large.
    253         if (canShrink()) {
    254             if (is8Bit())
    255                 return AtomString(characters8(), length());
    256             return AtomString(characters16(), length());           
    257         }
    258 
    259         if (!m_string.isNull())
    260             return AtomString(m_string);
    261 
    262         ASSERT(m_buffer);
    263         return AtomString(m_buffer.get(), 0, m_length.unsafeGet());
    264     }
    265 
    266     unsigned length() const
    267     {
    268         RELEASE_ASSERT(!hasOverflowed());
    269         return m_length.unsafeGet();
    270     }
    271 
    272     bool isEmpty() const { return !m_length; }
    273 
    274     WTF_EXPORT_PRIVATE void reserveCapacity(unsigned newCapacity);
    275 
    276     unsigned capacity() const
    277     {
    278         RELEASE_ASSERT(!hasOverflowed());
    279         return m_buffer ? m_buffer->length() : m_length.unsafeGet();
    280     }
    281 
    282     WTF_EXPORT_PRIVATE void resize(unsigned newSize);
    283 
    284     WTF_EXPORT_PRIVATE bool canShrink() const;
    285 
    286     WTF_EXPORT_PRIVATE void shrinkToFit();
    287 
    288     UChar operator[](unsigned i) const
    289     {
    290         RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!hasOverflowed() && i < m_length.unsafeGet<unsigned>());
    291         if (m_is8Bit)
    292             return characters8()[i];
    293         return characters16()[i];
    294     }
    295 
    296     const LChar* characters8() const
    297     {
    298         ASSERT(m_is8Bit);
    299         if (!m_length)
    300             return nullptr;
    301         if (!m_string.isNull())
    302             return m_string.characters8();
    303         ASSERT(m_buffer);
    304         return m_buffer->characters8();
    305     }
    306 
    307     const UChar* characters16() const
    308     {
    309         ASSERT(!m_is8Bit);
    310         if (!m_length)
    311             return nullptr;
    312         if (!m_string.isNull())
    313             return m_string.characters16();
    314         ASSERT(m_buffer);
    315         return m_buffer->characters16();
    316     }
    317    
    318     bool is8Bit() const { return m_is8Bit; }
    319     WTF_EXPORT_PRIVATE bool isAllASCII() const;
    320 
    321     operator StringView() const;
    322 
    323     void clear()
    324     {
    325         m_length = 0;
    326         m_string = String();
    327         m_buffer = nullptr;
    328         m_bufferCharacters8 = nullptr;
    329         m_is8Bit = true;
    330     }
    331 
    332     void swap(StringBuilder& stringBuilder)
    333     {
    334         std::swap(m_length, stringBuilder.m_length);
    335         m_string.swap(stringBuilder.m_string);
    336         m_buffer.swap(stringBuilder.m_buffer);
    337         std::swap(m_is8Bit, stringBuilder.m_is8Bit);
    338         std::swap(m_bufferCharacters8, stringBuilder.m_bufferCharacters8);
    339         ASSERT(!m_buffer || hasOverflowed() || m_buffer->length() >= m_length.unsafeGet<unsigned>());
    340     }
    341 
    342 private:
    343     void allocateBuffer(const LChar* currentCharacters, unsigned requiredLength);
    344     void allocateBuffer(const UChar* currentCharacters, unsigned requiredLength);
    345     void allocateBufferUpConvert(const LChar* currentCharacters, unsigned requiredLength);
    346     template<typename CharacterType> void reallocateBuffer(unsigned requiredLength);
    347     template<typename CharacterType> ALWAYS_INLINE CharacterType* extendBufferForAppending(unsigned additionalLength);
    348     template<typename CharacterType> ALWAYS_INLINE CharacterType* extendBufferForAppendingWithoutOverflowCheck(CheckedInt32 requiredLength);
    349     template<typename CharacterType> CharacterType* extendBufferForAppendingSlowCase(unsigned requiredLength);
    350     WTF_EXPORT_PRIVATE LChar* extendBufferForAppending8(CheckedInt32 requiredLength);
    351     WTF_EXPORT_PRIVATE UChar* extendBufferForAppending16(CheckedInt32 requiredLength);
    352 
    353     template<typename CharacterType> ALWAYS_INLINE CharacterType* getBufferCharacters();
    354     WTF_EXPORT_PRIVATE void reifyString() const;
    355 
    356     template<typename... StringTypeAdapters> void appendFromAdapters(StringTypeAdapters...);
    357 
    358     mutable String m_string;
    359     RefPtr<StringImpl> m_buffer;
    360     union {
    361         LChar* m_bufferCharacters8;
    362         UChar* m_bufferCharacters16;
    363     };
    364     static_assert(String::MaxLength == std::numeric_limits<int32_t>::max(), "");
    365     Checked<int32_t, ConditionalCrashOnOverflow> m_length;
    366     bool m_is8Bit { true };
    367 #if ASSERT_ENABLED
    368     mutable bool m_isReified { false };
    369 #endif
    370 };
    371 
    372 inline StringBuilder::operator StringView() const
    373 {
    374     if (m_is8Bit)
    375         return { characters8(), length() };
    376     return { characters16(), length() };
    377 }
    378 
    379 template<>
    380 ALWAYS_INLINE LChar* StringBuilder::getBufferCharacters<LChar>()
    381 {
    382     ASSERT(m_is8Bit);
    383     return m_bufferCharacters8;
    384 }
    385 
    386 template<>
    387 ALWAYS_INLINE UChar* StringBuilder::getBufferCharacters<UChar>()
    388 {
    389     ASSERT(!m_is8Bit);
    390     return m_bufferCharacters16;
    391 }
    392 
    393 template<typename... StringTypeAdapters>
    394 void StringBuilder::appendFromAdapters(StringTypeAdapters... adapters)
    395 {
    396     auto requiredLength = checkedSum<int32_t>(m_length, adapters.length()...);
    397     if (m_is8Bit && are8Bit(adapters...)) {
    398         LChar* destination = extendBufferForAppending8(requiredLength);
    399         if (!destination) {
    400             ASSERT(hasOverflowed());
     271
     272    // Use the length function here so we crash on overflow without explicit overflow checks.
     273    ASSERT(m_buffer);
     274    return { m_buffer.get(), 0, length() };
     275}
     276
     277inline unsigned StringBuilder::length() const
     278{
     279    RELEASE_ASSERT(!hasOverflowed());
     280    return m_length;
     281}
     282
     283inline unsigned StringBuilder::capacity() const
     284{
     285    return m_buffer ? m_buffer->length() : length();
     286}
     287
     288inline UChar StringBuilder::operator[](unsigned i) const
     289{
     290    RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(i < length());
     291    return is8Bit() ? characters<LChar>()[i] : characters<UChar>()[i];
     292}
     293
     294inline bool StringBuilder::is8Bit() const
     295{
     296    return m_buffer ? m_buffer->is8Bit() : m_string.is8Bit();
     297}
     298
     299template<typename CharacterType> inline const CharacterType* StringBuilder::characters() const
     300{
     301    if (!m_length)
     302        return nullptr;
     303    if (!m_string.isNull())
     304        return m_string.characters<CharacterType>();
     305    return m_buffer->characters<CharacterType>();
     306}
     307
     308template<typename... StringTypeAdapters> void StringBuilder::appendFromAdapters(StringTypeAdapters... adapters)
     309{
     310    auto requiredLength = saturatedSum<uint32_t>(m_length, adapters.length()...);
     311    if (is8Bit() && are8Bit(adapters...)) {
     312        auto destination = extendBufferForAppendingLChar(requiredLength);
     313        if (!destination)
    401314            return;
    402         }
    403315        stringTypeAdapterAccumulator(destination, adapters...);
    404316    } else {
    405         UChar* destination = extendBufferForAppending16(requiredLength);
    406         if (!destination) {
    407             ASSERT(hasOverflowed());
     317        auto destination = extendBufferForAppendingWithUpconvert(requiredLength);
     318        if (!destination)
    408319            return;
    409         }
    410320        stringTypeAdapterAccumulator(destination, adapters...);
    411321    }
    412322}
    413323
    414 template<typename... StringTypes>
    415 void StringBuilder::append(StringTypes... strings)
     324template<typename... StringTypes> void StringBuilder::append(StringTypes... strings)
    416325{
    417326    appendFromAdapters(StringTypeAdapter<StringTypes>(strings)...);
    418327}
    419328
    420 // FIXME: Move this to StringView and make it take a StringView instead of a StringBuilder?
    421 template<typename CharacterType>
    422 bool equal(const StringBuilder& s, const CharacterType* buffer, unsigned length)
    423 {
    424     if (s.length() != length)
    425         return false;
    426 
    427     if (s.is8Bit())
    428         return equal(s.characters8(), buffer, length);
    429 
    430     return equal(s.characters16(), buffer, length);
     329template<typename CharacterType> bool equal(const StringBuilder& builder, const CharacterType* buffer, unsigned length)
     330{
     331    return builder == StringView { buffer, length };
    431332}
    432333
    … …  
    434335    using ReturnType = void;
    435336    using AdditionalArgumentType = StringBuilder;
    436     static void flush(LChar* characters, unsigned length, StringBuilder* stringBuilder) { stringBuilder->appendCharacters(characters, length); }
     337    static void flush(const LChar* characters, unsigned length, StringBuilder* builder) { builder->appendCharacters(characters, length); }
    437338};
    438339
  • trunk/Source/WTF/wtf/text/StringBuilderJSON.cpp

    r239537 r277744  
    106106    if (hasOverflowed())
    107107        return;
    108     // Make sure we have enough buffer space to append this string without having
    109     // to worry about reallocating in the middle.
     108
     109    // Make sure we have enough buffer space to append this string for worst case without reallocating.
    110110    // The 2 is for the '"' quotes on each end.
    111     // The 6 is for characters that need to be \uNNNN encoded.
     111    // The 6 is the worst case for a single code unit that could be encoded as \uNNNN.
    112112    Checked<unsigned, RecordOverflow> stringLength = string.length();
    113     Checked<unsigned, RecordOverflow> maximumCapacityRequired = length();
    114     maximumCapacityRequired += 2 + stringLength * 6;
    115     unsigned allocationSize;
    116     if (CheckedState::DidOverflow == maximumCapacityRequired.safeGet(allocationSize))
    117         return didOverflow();
    118     // This max() is here to allow us to allocate sizes between the range [2^31, 2^32 - 2] because roundUpToPowerOfTwo(1<<31 + some int smaller than 1<<31) == 0.
    119     // FIXME: roundUpToPowerOfTwo should take Checked<unsigned> and abort if it fails to round up.
     113    auto maximumCapacityRequired = m_length + 2 + stringLength * 6;
     114    if (maximumCapacityRequired.hasOverflowed()) {
     115        didOverflow();
     116        return;
     117    }
     118
     119    // We need to check maximum length before calling roundUpPowerOfTwo because that function returns 0 for values in the range [2^31, 2^32-2].
     120    // FIXME: Instead, roundUpToPowerOfTwo should be fixed to do something more useful in those cases, perhaps using checked or saturated arithmetic.
    120121    // https://bugs.webkit.org/show_bug.cgi?id=176086
    121     allocationSize = std::max(allocationSize, roundUpToPowerOfTwo(allocationSize));
     122    auto allocationSize = maximumCapacityRequired.unsafeGet();
     123    if (allocationSize > String::MaxLength) {
     124        didOverflow();
     125        return;
     126    }
     127    allocationSize = roundUpToPowerOfTwo(allocationSize);
     128    if (allocationSize > String::MaxLength) {
     129        didOverflow();
     130        return;
     131    }
    122132
    123     // Allocating this much will definitely fail.
    124     if (allocationSize > String::MaxLength)
    125         return didOverflow();
    126 
     133    // FIXME: Consider switching to extendBufferForAppending/shrink instead to share more code with the rest of StringBuilder.
    127134    if (is8Bit() && !string.is8Bit())
    128         allocateBufferUpConvert(m_bufferCharacters8, allocationSize);
     135        allocateBuffer<UChar>(characters<LChar>(), allocationSize);
    129136    else
    130137        reserveCapacity(allocationSize);
    131138    if (UNLIKELY(hasOverflowed()))
    132139        return;
    133     ASSERT(m_buffer->length() >= allocationSize);
    134140
    135     if (is8Bit()) {
    136         ASSERT(string.is8Bit());
    137         LChar* output = m_bufferCharacters8 + m_length.unsafeGet<unsigned>();
     141    if (m_buffer->is8Bit()) {
     142        auto characters = const_cast<LChar*>(m_buffer->characters<LChar>());
     143        auto output = characters + m_length;
    138144        *output++ = '"';
    139145        appendQuotedJSONStringInternal(output, string.characters8(), string.length());
    140146        *output++ = '"';
    141         m_length = output - m_bufferCharacters8;
     147        m_length = output - characters;
    142148    } else {
    143         UChar* output = m_bufferCharacters16 + m_length.unsafeGet<unsigned>();
     149        auto characters = const_cast<UChar*>(m_buffer->characters<UChar>());
     150        auto output = characters + m_length;
    144151        *output++ = '"';
    145152        if (string.is8Bit())
    … …  
    148155            appendQuotedJSONStringInternal(output, string.characters16(), string.length());
    149156        *output++ = '"';
    150         m_length = output - m_bufferCharacters16;
     157        m_length = output - characters;
    151158    }
    152     ASSERT(!hasOverflowed());
    153     ASSERT(m_buffer->length() >= m_length.unsafeGet<unsigned>());
     159    ASSERT(m_buffer->length() >= m_length);
    154160}
    155161
  • trunk/Source/WTF/wtf/text/cocoa/TextStreamCocoa.mm

    r260366 r277744  
    2222#import <wtf/text/TextStream.h>
    2323
     24#import <wtf/text/cf/StringConcatenateCF.h>
     25
    2426namespace WTF {
    2527
  • trunk/Source/WebCore/ChangeLog

    r277740 r277744  
     12021-05-18  Darin Adler  <darin@apple.com>
     2
     3        Move CFStringRef and NSString support from StringBuilder into StringConcatenateCF
     4        https://bugs.webkit.org/show_bug.cgi?id=225839
     5
     6        Reviewed by Sam Weinig.
     7
     8        * Modules/airplay/WebMediaSessionManager.cpp:
     9        (WebCore::mediaProducerStateString): Use StringBuilder exclusively instead of
     10        mixing it with makeString. Also updated for StringBuilder::shrink name.
     11        * html/HTMLTextFormControlElement.cpp:
     12        (WebCore::stripTrailingNewline): Updated for StringBuilder::shrink name.
     13
     14        * page/CaptionUserPreferencesMediaAF.cpp:
     15        (WebCore::CaptionUserPreferencesMediaAF::captionsTextColor const): Tweaked
     16        coding style a bit.
     17        (WebCore::appendCSS): Use variadic StringBuilder::append instead of many
     18        separate calls.
     19        (WebCore::CaptionUserPreferencesMediaAF::captionsDefaultFontCSS const):
     20        Tweaked coding style a bit, and use variadic StrinBuilder::append calls
     21        to reduce the number of calls and streamline the code.
     22        (WebCore::CaptionUserPreferencesMediaAF::captionsStyleSheetOverride const):
     23        Ditto. Also removed unnecessary checks that strings are empty before appending.
     24
     25        * page/scrolling/ScrollingCoordinator.cpp:
     26        (WebCore::ScrollingCoordinator::synchronousScrollingReasonsAsText):
     27        Updated for StringBuilder::shrink name.
     28
     29        * platform/LayoutUnit.h: Updated for saturatedSum/Difference names.
     30
     31        * platform/network/cocoa/NetworkStorageSessionCocoa.mm:
     32        (WebCore::NetworkStorageSession::cookiesForSession const): Tweaked codin
     33        style a bit, and use variadic StrinBuilder::append calls to reduce the
     34        number of calls and streamline the code.
     35
     36        * rendering/RenderCounter.cpp:
     37        (WebCore::planCounter): Updated for saturatedSum name.
     38        * style/StyleBuilderCustom.h:
     39        (WebCore::Style::BuilderCustom::applyValueCounter): Ditto.
     40
     41        * svg/SVGPathStringBuilder.cpp:
     42        (WebCore::SVGPathStringBuilder::result): Updated for StringBuilder::shrink name.
     43        * testing/Internals.cpp:
     44        (WebCore::Internals::pageMediaState): Ditto.
     45        * xml/XSLTProcessorLibxslt.cpp:
     46        (WebCore::saveResultToString): Ditto.
     47
    1482021-05-19  Sam Weinig  <weinig@apple.com>
    249
  • trunk/Source/WebCore/Modules/airplay/WebMediaSessionManager.cpp

    r276952 r277744  
    7474{
    7575    StringBuilder string;
     76    string.append(" { ");
    7677    if (flags & MediaProducer::MediaState::IsPlayingAudio)
    7778        string.append("IsPlayingAudio+");
    … …  
    9394        string.append("IsNotPlaying");
    9495    else
    95         string.resize(string.length() - 1);
    96 
    97     return makeString(" { ", string.toString(), " }");
     96        string.shrink(string.length() - 1);
     97    string.append(" }");
     98    return string.toString();
    9899}
    99100
  • trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp

    r271672 r277744  
    557557    size_t size = result.length();
    558558    if (size && result[size - 1] == newlineCharacter)
    559         result.resize(size - 1);
     559        result.shrink(size - 1);
    560560}
    561561
  • trunk/Source/WebCore/page/CaptionUserPreferencesMediaAF.cpp

    r273191 r277744  
    4949#include <wtf/text/StringBuilder.h>
    5050#include <wtf/text/StringConcatenateNumbers.h>
     51#include <wtf/text/cf/StringConcatenateCF.h>
    5152
    5253#if PLATFORM(IOS_FAMILY)
    … …  
    309310{
    310311    MACaptionAppearanceBehavior behavior;
    311     RetainPtr<CGColorRef> color = adoptCF(MACaptionAppearanceCopyForegroundColor(kMACaptionAppearanceDomainUser, &behavior));
    312     Color textColor(color.get());
    313     if (!textColor.isValid())
     312    Color textColor = adoptCF(MACaptionAppearanceCopyForegroundColor(kMACaptionAppearanceDomainUser, &behavior)).get();
     313    if (!textColor.isValid()) {
    314314        // This default value must be the same as the one specified in mediaControls.css for -webkit-media-text-track-container.
    315315        textColor = Color::white;
    316    
     316    }
    317317    important = behavior == kMACaptionAppearanceBehaviorUseValue;
    318318    CGFloat opacity = MACaptionAppearanceGetForegroundOpacity(kMACaptionAppearanceDomainUser, &behavior);
    … …  
    321321    return textColor.colorWithAlpha(opacity);
    322322}
    323    
     323
    324324String CaptionUserPreferencesMediaAF::captionsTextColorCSS() const
    325325{
    326326    bool important;
    327     Color textColor = captionsTextColor(important);
    328 
     327    auto textColor = captionsTextColor(important);
    329328    if (!textColor.isValid())
    330329        return emptyString();
    331 
    332330    return colorPropertyCSS(CSSPropertyColor, textColor, important);
    333331}
    … …  
    335333static void appendCSS(StringBuilder& builder, CSSPropertyID id, const String& value, bool important)
    336334{
    337     builder.append(getPropertyNameString(id));
    338     builder.append(':');
    339     builder.append(value);
    340     if (important)
    341         builder.appendLiteral(" !important");
    342     builder.append(';');
     335    builder.append(getPropertyNameString(id), ':', value, important ? " !important;" : ";");
    343336}
    344337   
    … …  
    380373    strokeWidth = strokeWidthPt * 2;
    381374    important = behavior == kMACaptionAppearanceBehaviorUseValue;
    382    
    383375    return true;
    384376}
    … …  
    419411    MACaptionAppearanceBehavior behavior;
    420412   
    421     RetainPtr<CTFontDescriptorRef> font = adoptCF(MACaptionAppearanceCopyFontDescriptorForStyle(kMACaptionAppearanceDomainUser, &behavior, kMACaptionAppearanceFontStyleDefault));
     413    auto font = adoptCF(MACaptionAppearanceCopyFontDescriptorForStyle(kMACaptionAppearanceDomainUser, &behavior, kMACaptionAppearanceFontStyleDefault));
    422414    if (!font)
    423415        return emptyString();
    424416
    425     RetainPtr<CFTypeRef> name = adoptCF(CTFontDescriptorCopyAttribute(font.get(), kCTFontNameAttribute));
     417    auto name = adoptCF(static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(font.get(), kCTFontNameAttribute)));
    426418    if (!name)
    427419        return emptyString();
    428420
    429421    StringBuilder builder;
    430    
    431     builder.append(getPropertyNameString(CSSPropertyFontFamily));
    432     builder.appendLiteral(": \"");
    433     builder.append(static_cast<CFStringRef>(name.get()));
    434     builder.append('"');
    435 
    436     auto cascadeList = adoptCF(static_cast<CFArrayRef>(CTFontDescriptorCopyAttribute(font.get(), kCTFontCascadeListAttribute)));
    437 
    438     if (cascadeList) {
     422    builder.append("font-family: \"", name.get(), '"');
     423    if (auto cascadeList = adoptCF(static_cast<CFArrayRef>(CTFontDescriptorCopyAttribute(font.get(), kCTFontCascadeListAttribute)))) {
    439424        for (CFIndex i = 0; i < CFArrayGetCount(cascadeList.get()); i++) {
    440425            auto fontCascade = static_cast<CTFontDescriptorRef>(CFArrayGetValueAtIndex(cascadeList.get(), i));
    441426            if (!fontCascade)
    442427                continue;
    443             auto fontCascadeName = adoptCF(CTFontDescriptorCopyAttribute(fontCascade, kCTFontNameAttribute));
     428            auto fontCascadeName = adoptCF(static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(fontCascade, kCTFontNameAttribute)));
    444429            if (!fontCascadeName)
    445430                continue;
    446             builder.append(", \"");
    447             builder.append(static_cast<CFStringRef>(fontCascadeName.get()));
    448             builder.append('"');
     431            builder.append(", \"", fontCascadeName.get(), '"');
    449432        }
    450433    }
    451    
    452     if (behavior == kMACaptionAppearanceBehaviorUseValue)
    453         builder.appendLiteral(" !important");
    454     builder.append(';');
    455    
     434    builder.append(behavior == kMACaptionAppearanceBehaviorUseValue ? " !important;" : ";");
    456435    return builder.toString();
    457436}
    … …  
    562541    if (!MediaAccessibilityLibrary())
    563542        return CaptionUserPreferences::captionsStyleSheetOverride();
    564    
     543
    565544    String captionsColor = captionsTextColorCSS();
    566545    String edgeStyle = captionsTextEdgeCSS();
    567546    String fontName = captionsDefaultFontCSS();
    568547    String background = captionsBackgroundCSS();
    569     if (!background.isEmpty() || !captionsColor.isEmpty() || !edgeStyle.isEmpty() || !fontName.isEmpty()) {
    570         captionsOverrideStyleSheet.appendLiteral(" ::");
    571         captionsOverrideStyleSheet.append(TextTrackCue::cueShadowPseudoId());
    572         captionsOverrideStyleSheet.append('{');
    573        
    574         if (!background.isEmpty())
    575             captionsOverrideStyleSheet.append(background);
    576         if (!captionsColor.isEmpty())
    577             captionsOverrideStyleSheet.append(captionsColor);
    578         if (!edgeStyle.isEmpty())
    579             captionsOverrideStyleSheet.append(edgeStyle);
    580         if (!fontName.isEmpty())
    581             captionsOverrideStyleSheet.append(fontName);
    582        
    583         captionsOverrideStyleSheet.append('}');
    584     }
    585    
     548    if (!background.isEmpty() || !captionsColor.isEmpty() || !edgeStyle.isEmpty() || !fontName.isEmpty())
     549        captionsOverrideStyleSheet.append(" ::", TextTrackCue::cueShadowPseudoId(), '{', background, captionsColor, edgeStyle, fontName, '}');
     550
    586551    String windowColor = captionsWindowCSS();
    587552    String windowCornerRadius = windowRoundedCornerRadiusCSS();
    588     if (!windowColor.isEmpty() || !windowCornerRadius.isEmpty()) {
    589         captionsOverrideStyleSheet.appendLiteral(" ::");
    590         captionsOverrideStyleSheet.append(TextTrackCue::cueBackdropShadowPseudoId());
    591         captionsOverrideStyleSheet.append('{');
    592        
    593         if (!windowColor.isEmpty())
    594             captionsOverrideStyleSheet.append(windowColor);
    595         if (!windowCornerRadius.isEmpty()) {
    596             captionsOverrideStyleSheet.append(windowCornerRadius);
    597         }
    598        
    599         captionsOverrideStyleSheet.append('}');
    600     }
     553    if (!windowColor.isEmpty() || !windowCornerRadius.isEmpty())
     554        captionsOverrideStyleSheet.append(" ::", TextTrackCue::cueBackdropShadowPseudoId(), '{', windowColor, windowCornerRadius, '}');
    601555#endif // HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK)
    602556
  • trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp

    r271070 r277744  
    405405
    406406    if (stringBuilder.length())
    407         stringBuilder.resize(stringBuilder.length() - 2);
     407        stringBuilder.shrink(stringBuilder.length() - 2);
    408408    return stringBuilder.toString();
    409409}
  • trunk/Source/WebCore/platform/LayoutUnit.h

    r253290 r277744  
    151151    {
    152152        if (m_value > 0)
    153             return saturatedAddition(rawValue(), kFixedPointDenominator / 2) / kFixedPointDenominator;
    154         return saturatedSubtraction(rawValue(), (kFixedPointDenominator / 2) - 1) / kFixedPointDenominator;
     153            return saturatedSum<int>(rawValue(), kFixedPointDenominator / 2) / kFixedPointDenominator;
     154        return saturatedDifference<int>(rawValue(), (kFixedPointDenominator / 2) - 1) / kFixedPointDenominator;
    155155    }
    156156
    … …  
    589589{
    590590    LayoutUnit returnVal;
    591     returnVal.setRawValue(saturatedAddition(a.rawValue(), b.rawValue()));
     591    returnVal.setRawValue(saturatedSum<int>(a.rawValue(), b.rawValue()));
    592592    return returnVal;
    593593}
    … …  
    626626{
    627627    LayoutUnit returnVal;
    628     returnVal.setRawValue(saturatedSubtraction(a.rawValue(), b.rawValue()));
     628    returnVal.setRawValue(saturatedDifference<int>(a.rawValue(), b.rawValue()));
    629629    return returnVal;
    630630}
    … …  
    692692inline LayoutUnit& operator+=(LayoutUnit& a, const LayoutUnit& b)
    693693{
    694     a.setRawValue(saturatedAddition(a.rawValue(), b.rawValue()));
     694    a.setRawValue(saturatedSum<int>(a.rawValue(), b.rawValue()));
    695695    return a;
    696696}
    … …  
    722722inline LayoutUnit& operator-=(LayoutUnit& a, const LayoutUnit& b)
    723723{
    724     a.setRawValue(saturatedSubtraction(a.rawValue(), b.rawValue()));
     724    a.setRawValue(saturatedDifference<int>(a.rawValue(), b.rawValue()));
    725725    return a;
    726726}
  • trunk/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm

    r274429 r277744  
    4040#import <wtf/cocoa/VectorCocoa.h>
    4141#import <wtf/text/StringBuilder.h>
     42#import <wtf/text/cf/StringConcatenateCF.h>
    4243
    4344@interface NSURL ()
    … …  
    350351    BEGIN_BLOCK_OBJC_EXCEPTIONS
    351352
    352     RetainPtr<NSArray> cookies = cookiesForURL(firstParty, sameSiteInfo, url, frameID, pageID, shouldAskITP, shouldRelaxThirdPartyCookieBlocking);
    353     if (!cookies || ![cookies count])
    354         return { String(), false }; // Return a null string, not an empty one that StringBuilder would create below.
     353    auto cookies = cookiesForURL(firstParty, sameSiteInfo, url, frameID, pageID, shouldAskITP, shouldRelaxThirdPartyCookieBlocking);
     354    if (![cookies count])
     355        return { String(), false }; // Return a null string; StringBuilder below would create an empty one.
    355356
    356357    StringBuilder cookiesBuilder;
    … …  
    359360        if (![[cookie name] length])
    360361            continue;
    361 
    362362        if (!includeHTTPOnly && [cookie isHTTPOnly])
    363363            continue;
    364 
    365364        if ([cookie isSecure]) {
    366365            didAccessSecureCookies = true;
    … …  
    368367                continue;
    369368        }
    370 
    371         if (!cookiesBuilder.isEmpty())
    372             cookiesBuilder.appendLiteral("; ");
    373 
    374         cookiesBuilder.append([cookie name]);
    375         cookiesBuilder.append('=');
    376         cookiesBuilder.append([cookie value]);
     369        cookiesBuilder.append(cookiesBuilder.isEmpty() ? "" : "; ", [cookie name], '=', [cookie value]);
    377370    }
    378371    return { cookiesBuilder.toString(), didAccessSecureCookies };
  • trunk/Source/WebCore/rendering/RenderCounter.cpp

    r274580 r277744  
    188188
    189189    if (directives.resetValue)
    190         return CounterPlan { true, saturatedAddition(*directives.resetValue, directives.incrementValue.valueOr(0)) };
     190        return CounterPlan { true, saturatedSum<int>(*directives.resetValue, directives.incrementValue.valueOr(0)) };
    191191    if (directives.incrementValue)
    192192        return CounterPlan { false, *directives.incrementValue };
  • trunk/Source/WebCore/style/StyleBuilderCustom.h

    r277580 r277744  
    13611361            directives.resetValue = value;
    13621362        else
    1363             directives.incrementValue = saturatedAddition(directives.incrementValue.valueOr(0), value);
     1363            directives.incrementValue = saturatedSum<int>(directives.incrementValue.valueOr(0), value);
    13641364    }
    13651365}
  • trunk/Source/WebCore/svg/SVGPathStringBuilder.cpp

    r254514 r277744  
    3737
    3838    // Remove trailing space.
    39     m_stringBuilder.resize(size - 1);
     39    m_stringBuilder.shrink(size - 1);
    4040    return m_stringBuilder.toString();
    4141}
  • trunk/Source/WebCore/testing/Internals.cpp

    r277584 r277744  
    46394639        string.append("IsNotPlaying");
    46404640    else
    4641         string.resize(string.length() - 1);
     4641        string.shrink(string.length() - 1);
    46424642
    46434643    return string.toString();
  • trunk/Source/WebCore/xml/XSLTProcessorLibxslt.cpp

    r270449 r277744  
    213213    // Workaround for <http://bugzilla.gnome.org/show_bug.cgi?id=495668>: libxslt appends an extra line feed to the result.
    214214    if (resultBuilder.length() > 0 && resultBuilder[resultBuilder.length() - 1] == '\n')
    215         resultBuilder.resize(resultBuilder.length() - 1);
     215        resultBuilder.shrink(resultBuilder.length() - 1);
    216216
    217217    resultString = resultBuilder.toString();
  • trunk/Source/WebKit/ChangeLog

    r277743 r277744  
     12021-05-18  Darin Adler  <darin@apple.com>
     2
     3        Move CFStringRef and NSString support from StringBuilder into StringConcatenateCF
     4        https://bugs.webkit.org/show_bug.cgi?id=225839
     5
     6        Reviewed by Sam Weinig.
     7
     8        * UIProcess/WebsiteData/Cocoa/WebsiteDataStoreCocoa.mm:
     9        (WebKit::WebsiteDataStore::platformSetNetworkParameters): Use makeString instead
     10        of StringBuilder.
     11
    1122021-05-19  Aditya Keerthi  <akeerthi@apple.com>
    213
  • trunk/Source/WebKit/UIProcess/WebsiteData/Cocoa/WebsiteDataStoreCocoa.mm

    r277449 r277744  
    4848#import <wtf/URL.h>
    4949#import <wtf/cocoa/Entitlements.h>
    50 #import <wtf/text/StringBuilder.h>
     50#import <wtf/text/cf/StringConcatenateCF.h>
    5151
    5252#if PLATFORM(IOS_FAMILY)
    … …  
    116116    }
    117117
    118     auto* manualPrevalentResource = [defaults stringForKey:@"ITPManualPrevalentResource"];
    119     if (manualPrevalentResource) {
    120         URL url { URL(), manualPrevalentResource };
    121         if (!url.isValid()) {
    122             StringBuilder builder;
    123             builder.appendLiteral("http://");
    124             builder.append(manualPrevalentResource);
    125             url = { URL(), builder.toString() };
    126         }
     118    if (auto manualPrevalentResource = [defaults stringForKey:@"ITPManualPrevalentResource"]) {
     119        URL url { { }, manualPrevalentResource };
     120        if (!url.isValid())
     121            url = { { }, makeString("http://", manualPrevalentResource) };
    127122        if (url.isValid())
    128123            resourceLoadStatisticsManualPrevalentResource = WebCore::RegistrableDomain { url };
  • trunk/Tools/ChangeLog

    r277742 r277744  
     12021-05-18  Darin Adler  <darin@apple.com>
     2
     3        Move CFStringRef and NSString support from StringBuilder into StringConcatenateCF
     4        https://bugs.webkit.org/show_bug.cgi?id=225839
     5
     6        Reviewed by Sam Weinig.
     7
     8        * TestWebKitAPI/Tests/WTF/SaturatedArithmeticOperations.cpp: Updated
     9        tests for changes to SaturatedArithmetic.h.
     10
     11        * TestWebKitAPI/Tests/WTF/StringBuilder.cpp: Updated tests for changes
     12        to StringBuilder.
     13        * TestWebKitAPI/Tests/WebKit/GetUserMedia.mm:
     14        (TestWebKitAPI::wkMediaCaptureStateString): Ditto.
     15
     16        * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
     17        Added include of StringConcatenateCF.h.
     18        Added StringTypeAdapter for WKStringRef.
     19        (WTR::styleDecToStr): Use ASCIILiteral instead of StringBuilder.
     20        (WTR::string): Removed unneeded toWTFString since the WKStringRef
     21        StringTypeAdapter takes care of it.
     22        (WTR::string): Renamed from frameToStr. Use makeString.
     23        (WTR::dumpResourceURL): Use append instead of appendLiteral.
     24        (WTR::dumpFrameDescriptionSuitableForTestResult): Deleted.
     25        (WTR::dumpLoadEvent): Use makeString.
     26        (WTR::string): Renamed from a longer name. Return a String
     27        instead of building in a StringBuilder. Use makeString.
     28        (WTR::string): Ditto.
     29        (WTR::dumpErrorDescriptionSuitableForTestResult): Removed
     30        unneeded toWTFString.
     31        (WTR::dumpFrameScrollPosition): Ditto.
     32        (WTR::dumpDescendantFramesText): Ditto.
     33        (WTR::InjectedBundlePage::dumpDOMAsWebArchive): Removed an
     34        unneeded local variable.
     35        (WTR::InjectedBundlePage::dump): Removed unneeded toWTFString.
     36        (WTR::InjectedBundlePage::didReceiveTitleForFrame): Ditto.
     37        (WTR::InjectedBundlePage::didFinishDocumentLoadForFrame):
     38        Updated for functon name change.
     39        (WTR::InjectedBundlePage::willSendRequestForFrame): Ditto.
     40        Also use variadic append. Also use makeString.
     41        (WTR::InjectedBundlePage::didReceiveResponseForResource): Ditto.
     42        (WTR::InjectedBundlePage::didFinishLoadForResource): Ditto.
     43        (WTR::InjectedBundlePage::didFailLoadForResource): Ditto.
     44        (WTR::InjectedBundlePage::decidePolicyForNavigationAction): Ditto.
     45        (WTR::InjectedBundlePage::decidePolicyForResponse): Ditto.
     46        (WTR::InjectedBundlePage::willAddMessageToConsole): Ditto.
     47        (WTR::InjectedBundlePage::willSetStatusbarText): Ditto.
     48        (WTR::InjectedBundlePage::willRunJavaScriptPrompt): Ditto.
     49        (WTR::InjectedBundlePage::didExceedDatabaseQuota): Ditto.
     50        (WTR::InjectedBundlePage::shouldInsertNode): Ditto.
     51        (WTR::InjectedBundlePage::shouldInsertText): Ditto.
     52        (WTR::InjectedBundlePage::shouldDeleteRange): Ditto.
     53        (WTR::InjectedBundlePage::shouldChangeSelectedRange): Ditto.
     54        (WTR::InjectedBundlePage::shouldApplyStyle): Ditto.
     55        (WTR::InjectedBundlePage::didBeginEditing): Ditto.
     56        (WTR::InjectedBundlePage::didEndEditing): Ditto.
     57        (WTR::InjectedBundlePage::didChange): Ditto.
     58        (WTR::InjectedBundlePage::didChangeSelection): Ditto.
     59        (WTR::InjectedBundlePage::dumpHistory): Ditto.
     60
    1612021-05-19  Aakash Jain  <aakash_jain@apple.com>
    262
  • trunk/Tools/TestWebKitAPI/Tests/WTF/SaturatedArithmeticOperations.cpp

    r126509 r277744  
    11/*
    2  * Copyright (c) 2012, Google Inc. All rights reserved.
     2 * Copyright (c) 2012 Google Inc. All rights reserved.
     3 * Copyright (c) 2021 Apple Inc. All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
    … …  
    3031
    3132#include "config.h"
    32 #include "limits.h"
     33
     34#include <limits.h>
    3335#include <wtf/SaturatedArithmetic.h>
    3436
    … …  
    3739TEST(WTF, SaturatedArithmeticAddition)
    3840{
    39     ASSERT_EQ(saturatedAddition(0, 0), 0);
    40     ASSERT_EQ(saturatedAddition(0, 1), 1);
    41     ASSERT_EQ(saturatedAddition(0, 100), 100);
    42     ASSERT_EQ(saturatedAddition(100, 50), 150);
     41    EXPECT_EQ(0, saturatedSum<int32_t>(0, 0));
     42    EXPECT_EQ(1, saturatedSum<int32_t>(0, 1));
     43    EXPECT_EQ(100, saturatedSum<int32_t>(0, 100));
     44    EXPECT_EQ(150, saturatedSum<int32_t>(100, 50));
    4345
    44     ASSERT_EQ(saturatedAddition(0, -1), -1);
    45     ASSERT_EQ(saturatedAddition(1, -1), 0);
    46     ASSERT_EQ(saturatedAddition(100, -50), 50);
    47     ASSERT_EQ(saturatedAddition(50, -100), -50);
     46    EXPECT_EQ(-1, saturatedSum<int32_t>(0, -1));
     47    EXPECT_EQ(0, saturatedSum<int32_t>(1, -1));
     48    EXPECT_EQ(50, saturatedSum<int32_t>(100, -50));
     49    EXPECT_EQ(-50, saturatedSum<int32_t>(50, -100));
    4850
    49     ASSERT_EQ(saturatedAddition(INT_MAX - 1, 0), INT_MAX - 1);
    50     ASSERT_EQ(saturatedAddition(INT_MAX - 1, 1), INT_MAX);
    51     ASSERT_EQ(saturatedAddition(INT_MAX - 1, 2), INT_MAX);
    52     ASSERT_EQ(saturatedAddition(0, INT_MAX - 1), INT_MAX - 1);
    53     ASSERT_EQ(saturatedAddition(1, INT_MAX - 1), INT_MAX);
    54     ASSERT_EQ(saturatedAddition(2, INT_MAX - 1), INT_MAX);
    55     ASSERT_EQ(saturatedAddition(INT_MAX - 1, INT_MAX - 1), INT_MAX);
    56     ASSERT_EQ(saturatedAddition(INT_MAX, INT_MAX), INT_MAX);
     51    EXPECT_EQ(INT_MAX - 1, saturatedSum<int32_t>(INT_MAX - 1, 0));
     52    EXPECT_EQ(INT_MAX, saturatedSum<int32_t>(INT_MAX - 1, 1));
     53    EXPECT_EQ(INT_MAX, saturatedSum<int32_t>(INT_MAX - 1, 2));
     54    EXPECT_EQ(INT_MAX - 1, saturatedSum<int32_t>(0, INT_MAX - 1));
     55    EXPECT_EQ(INT_MAX, saturatedSum<int32_t>(1, INT_MAX - 1));
     56    EXPECT_EQ(INT_MAX, saturatedSum<int32_t>(2, INT_MAX - 1));
     57    EXPECT_EQ(INT_MAX, saturatedSum<int32_t>(INT_MAX - 1, INT_MAX - 1));
     58    EXPECT_EQ(INT_MAX, saturatedSum<int32_t>(INT_MAX, INT_MAX));
    5759
    58     ASSERT_EQ(saturatedAddition(INT_MIN, 0), INT_MIN);
    59     ASSERT_EQ(saturatedAddition(INT_MIN + 1, 0), INT_MIN + 1);
    60     ASSERT_EQ(saturatedAddition(INT_MIN + 1, 1), INT_MIN + 2);
    61     ASSERT_EQ(saturatedAddition(INT_MIN + 1, 2), INT_MIN + 3);
    62     ASSERT_EQ(saturatedAddition(INT_MIN + 1, -1), INT_MIN);
    63     ASSERT_EQ(saturatedAddition(INT_MIN + 1, -2), INT_MIN);
    64     ASSERT_EQ(saturatedAddition(0, INT_MIN + 1), INT_MIN + 1);
    65     ASSERT_EQ(saturatedAddition(-1, INT_MIN + 1), INT_MIN);
    66     ASSERT_EQ(saturatedAddition(-2, INT_MIN + 1), INT_MIN);
     60    EXPECT_EQ(INT_MIN, saturatedSum<int32_t>(INT_MIN, 0));
     61    EXPECT_EQ(INT_MIN + 1, saturatedSum<int32_t>(INT_MIN + 1, 0));
     62    EXPECT_EQ(INT_MIN + 2, saturatedSum<int32_t>(INT_MIN + 1, 1));
     63    EXPECT_EQ(INT_MIN + 3, saturatedSum<int32_t>(INT_MIN + 1, 2));
     64    EXPECT_EQ(INT_MIN, saturatedSum<int32_t>(INT_MIN + 1, -1));
     65    EXPECT_EQ(INT_MIN, saturatedSum<int32_t>(INT_MIN + 1, -2));
     66    EXPECT_EQ(INT_MIN + 1, saturatedSum<int32_t>(0, INT_MIN + 1));
     67    EXPECT_EQ(INT_MIN, saturatedSum<int32_t>(-1, INT_MIN + 1));
     68    EXPECT_EQ(INT_MIN, saturatedSum<int32_t>(-2, INT_MIN + 1));
    6769
    68     ASSERT_EQ(saturatedAddition(INT_MAX / 2, 10000), INT_MAX / 2 + 10000);
    69     ASSERT_EQ(saturatedAddition(INT_MAX / 2 + 1, INT_MAX / 2 + 1), INT_MAX);
    70     ASSERT_EQ(saturatedAddition(INT_MIN, INT_MAX), -1);
     70    EXPECT_EQ(INT_MAX / 2 + 10000, saturatedSum<int32_t>(INT_MAX / 2, 10000));
     71    EXPECT_EQ(INT_MAX, saturatedSum<int32_t>(INT_MAX / 2 + 1, INT_MAX / 2 + 1));
     72    EXPECT_EQ(-1, saturatedSum<int32_t>(INT_MIN, INT_MAX));
     73
     74    EXPECT_EQ(0U, saturatedSum<uint32_t>(0U, 0U));
     75    EXPECT_EQ(1U, saturatedSum<uint32_t>(0U, 1U));
     76    EXPECT_EQ(100U, saturatedSum<uint32_t>(0U, 100U));
     77    EXPECT_EQ(150U, saturatedSum<uint32_t>(100U, 50U));
     78
     79    EXPECT_EQ(UINT_MAX - 1, saturatedSum<uint32_t>(UINT_MAX - 1U, 0U));
     80    EXPECT_EQ(UINT_MAX, saturatedSum<uint32_t>(UINT_MAX - 1U, 1U));
     81    EXPECT_EQ(UINT_MAX, saturatedSum<uint32_t>(UINT_MAX - 1U, 2U));
     82    EXPECT_EQ(UINT_MAX - 1, saturatedSum<uint32_t>(0U, UINT_MAX - 1U));
     83    EXPECT_EQ(UINT_MAX, saturatedSum<uint32_t>(1U, UINT_MAX - 1U));
     84    EXPECT_EQ(UINT_MAX, saturatedSum<uint32_t>(2U, UINT_MAX - 1U));
     85    EXPECT_EQ(UINT_MAX, saturatedSum<uint32_t>(UINT_MAX - 1U, UINT_MAX - 1U));
     86    EXPECT_EQ(UINT_MAX, saturatedSum<uint32_t>(UINT_MAX, UINT_MAX));
     87
     88    EXPECT_EQ(UINT_MAX / 2 + 10000, saturatedSum<uint32_t>(UINT_MAX / 2U, 10000U));
     89    EXPECT_EQ(UINT_MAX, saturatedSum<uint32_t>(UINT_MAX / 2U, UINT_MAX / 2U + 1U));
     90    EXPECT_EQ(UINT_MAX, saturatedSum<uint32_t>(UINT_MAX / 2U + 1U, UINT_MAX / 2U + 1U));
     91    EXPECT_EQ(UINT_MAX, saturatedSum<uint32_t>(UINT_MAX / 3U + 1U, UINT_MAX / 3U, UINT_MAX / 3U));
     92    EXPECT_EQ(UINT_MAX, saturatedSum<uint32_t>(UINT_MAX / 3U + 1U, UINT_MAX / 3U + 1U, UINT_MAX / 3U + 1U));
    7193}
    7294
    7395TEST(WTF, SaturatedArithmeticSubtraction)
    7496{
    75     ASSERT_EQ(saturatedSubtraction(0, 0), 0);
    76     ASSERT_EQ(saturatedSubtraction(0, 1), -1);
    77     ASSERT_EQ(saturatedSubtraction(0, 100), -100);
    78     ASSERT_EQ(saturatedSubtraction(100, 50), 50);
     97    EXPECT_EQ(0, saturatedDifference<int32_t>(0, 0));
     98    EXPECT_EQ(-1, saturatedDifference<int32_t>(0, 1));
     99    EXPECT_EQ(-100, saturatedDifference<int32_t>(0, 100));
     100    EXPECT_EQ(50, saturatedDifference<int32_t>(100, 50));
    79101   
    80     ASSERT_EQ(saturatedSubtraction(0, -1), 1);
    81     ASSERT_EQ(saturatedSubtraction(1, -1), 2);
    82     ASSERT_EQ(saturatedSubtraction(100, -50), 150);
    83     ASSERT_EQ(saturatedSubtraction(50, -100), 150);
     102    EXPECT_EQ(1, saturatedDifference<int32_t>(0, -1));
     103    EXPECT_EQ(2, saturatedDifference<int32_t>(1, -1));
     104    EXPECT_EQ(150, saturatedDifference<int32_t>(100, -50));
     105    EXPECT_EQ(150, saturatedDifference<int32_t>(50, -100));
    84106
    85     ASSERT_EQ(saturatedSubtraction(INT_MAX, 0), INT_MAX);
    86     ASSERT_EQ(saturatedSubtraction(INT_MAX, 1), INT_MAX - 1);
    87     ASSERT_EQ(saturatedSubtraction(INT_MAX - 1, 0), INT_MAX - 1);
    88     ASSERT_EQ(saturatedSubtraction(INT_MAX - 1, -1), INT_MAX);
    89     ASSERT_EQ(saturatedSubtraction(INT_MAX - 1, -2), INT_MAX);
    90     ASSERT_EQ(saturatedSubtraction(0, INT_MAX - 1), -INT_MAX + 1);
    91     ASSERT_EQ(saturatedSubtraction(-1, INT_MAX - 1), -INT_MAX);
    92     ASSERT_EQ(saturatedSubtraction(-2, INT_MAX - 1), -INT_MAX - 1);
    93     ASSERT_EQ(saturatedSubtraction(-3, INT_MAX - 1), -INT_MAX - 1);
     107    EXPECT_EQ(INT_MAX, saturatedDifference<int32_t>(INT_MAX, 0));
     108    EXPECT_EQ(INT_MAX - 1, saturatedDifference<int32_t>(INT_MAX, 1));
     109    EXPECT_EQ(INT_MAX - 1, saturatedDifference<int32_t>(INT_MAX - 1, 0));
     110    EXPECT_EQ(INT_MAX, saturatedDifference<int32_t>(INT_MAX - 1, -1));
     111    EXPECT_EQ(INT_MAX, saturatedDifference<int32_t>(INT_MAX - 1, -2));
     112    EXPECT_EQ(-INT_MAX + 1, saturatedDifference<int32_t>(0, INT_MAX - 1));
     113    EXPECT_EQ(-INT_MAX, saturatedDifference<int32_t>(-1, INT_MAX - 1));
     114    EXPECT_EQ(-INT_MAX - 1, saturatedDifference<int32_t>(-2, INT_MAX - 1));
     115    EXPECT_EQ(-INT_MAX - 1, saturatedDifference<int32_t>(-3, INT_MAX - 1));
    94116
    95     ASSERT_EQ(saturatedSubtraction(INT_MIN, 0), INT_MIN);
    96     ASSERT_EQ(saturatedSubtraction(INT_MIN + 1, 0), INT_MIN + 1);
    97     ASSERT_EQ(saturatedSubtraction(INT_MIN + 1, 1), INT_MIN);
    98     ASSERT_EQ(saturatedSubtraction(INT_MIN + 1, 2), INT_MIN);
     117    EXPECT_EQ(INT_MIN, saturatedDifference<int32_t>(INT_MIN, 0));
     118    EXPECT_EQ(INT_MIN + 1, saturatedDifference<int32_t>(INT_MIN + 1, 0));
     119    EXPECT_EQ(INT_MIN, saturatedDifference<int32_t>(INT_MIN + 1, 1));
     120    EXPECT_EQ(INT_MIN, saturatedDifference<int32_t>(INT_MIN + 1, 2));
    99121
    100     ASSERT_EQ(saturatedSubtraction(INT_MIN, INT_MIN), 0);
    101     ASSERT_EQ(saturatedSubtraction(INT_MAX, INT_MAX), 0);
    102     ASSERT_EQ(saturatedSubtraction(INT_MAX, INT_MIN), INT_MAX);
     122    EXPECT_EQ(0, saturatedDifference<int32_t>(INT_MIN, INT_MIN));
     123    EXPECT_EQ(0, saturatedDifference<int32_t>(INT_MAX, INT_MAX));
     124    EXPECT_EQ(INT_MAX, saturatedDifference<int32_t>(INT_MAX, INT_MIN));
    103125}
    104126
  • trunk/Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp

    r277437 r277744  
    216216    // Resizing the StringBuilder should not affect the original result of toString().
    217217    string1 = builder.toString();
    218     builder.resize(10);
     218    builder.shrink(10);
    219219    builder.append("###");
    220220    EXPECT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
    … …  
    261261    EXPECT_EQ(capacity, builder.capacity());
    262262    EXPECT_EQ(string.characters8(), builder.characters8());
    263     builder.resize(10);
     263    builder.shrink(10);
    264264    builder.append("###");
    265265    EXPECT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
    … …  
    289289    StringBuilder builder;
    290290    builder.append("0123456789");
    291     builder.resize(10);
     291    builder.shrink(10);
    292292    EXPECT_EQ(10U, builder.length());
    293293    expectBuilderContent("0123456789", builder);
    294     builder.resize(8);
     294    builder.shrink(8);
    295295    EXPECT_EQ(8U, builder.length());
    296296    expectBuilderContent("01234567", builder);
    297297
    298298    builder.toString();
    299     builder.resize(7);
     299    builder.shrink(7);
    300300    EXPECT_EQ(7U, builder.length());
    301301    expectBuilderContent("0123456", builder);
    302     builder.resize(0);
     302    builder.shrink(0);
    303303    expectEmpty(builder);
    304304}
    … …  
    330330    EXPECT_TRUE(builder1 != builder2);
    331331
    332     builder2.resize(3);
     332    builder2.shrink(3);
    333333    EXPECT_TRUE(builder1 == builder2);
    334334
    … …  
    337337}
    338338
    339 TEST(StringBuilderTest, CanShrink)
     339TEST(StringBuilderTest, ShouldShrinkToFit)
    340340{
    341341    StringBuilder builder;
    342342    builder.reserveCapacity(256);
    343     EXPECT_TRUE(builder.canShrink());
     343    EXPECT_TRUE(builder.shouldShrinkToFit());
    344344    for (int i = 0; i < 256; i++)
    345345        builder.append('x');
    346346    EXPECT_EQ(builder.length(), builder.capacity());
    347     EXPECT_FALSE(builder.canShrink());
     347    EXPECT_FALSE(builder.shouldShrinkToFit());
    348348}
    349349
    … …  
    356356
    357357    builder.reserveCapacity(256);
    358     EXPECT_TRUE(builder.canShrink());
     358    EXPECT_TRUE(builder.shouldShrinkToFit());
    359359    for (int i = builder.length(); i < 128; i++)
    360360        builder.append('x');
    … …  
    368368    EXPECT_EQ(128u, atomString1.length());
    369369
    370     EXPECT_FALSE(builder.canShrink());
     370    EXPECT_FALSE(builder.shouldShrinkToFit());
    371371    String string = builder.toString();
    372372    AtomString atomString2 = builder.toAtomString();
  • trunk/Tools/TestWebKitAPI/Tests/WebKit/GetUserMedia.mm

    r276892 r277744  
    128128        string.append("_WKMediaCaptureStateDeprecatedNone");
    129129    else
    130         string.resize(string.length() - 2);
    131 
     130        string.shrink(string.length() - 2);
    132131    return string.toString();
    133132}
  • trunk/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp

    r277437 r277744  
    5353#include <wtf/text/StringBuilder.h>
    5454
     55#if USE(CF)
     56#include <wtf/text/cf/StringConcatenateCF.h>
     57#endif
     58
    5559#if USE(CF) && !PLATFORM(WIN_CAIRO) && !USE(DIRECT2D)
    5660#include "WebArchiveDumpSupport.h"
    … …  
    5862
    5963using namespace std;
     64
     65namespace WTF {
     66
     67template<> class StringTypeAdapter<WKStringRef> {
     68public:
     69    StringTypeAdapter(WKStringRef);
     70    unsigned length() const { return m_string ? WKStringGetLength(m_string) : 0; }
     71    bool is8Bit() const { return !m_string; }
     72    template<typename CharacterType> void writeTo(CharacterType*) const;
     73
     74private:
     75    WKStringRef m_string;
     76};
     77
     78inline StringTypeAdapter<WKStringRef>::StringTypeAdapter(WKStringRef string)
     79    : m_string { string }
     80{
     81}
     82
     83template<> inline void StringTypeAdapter<WKStringRef>::writeTo<LChar>(LChar*) const
     84{
     85}
     86
     87template<> inline void StringTypeAdapter<WKStringRef>::writeTo<UChar>(UChar* destination) const
     88{
     89    if (m_string)
     90        WKStringGetCharacters(m_string, reinterpret_cast<WKChar*>(destination), WKStringGetLength(m_string));
     91}
     92
     93}
    6094
    6195namespace WTR {
    … …  
    90124}
    91125
    92 static WTF::String rangeToStr(WKBundlePageRef page, WKBundleScriptWorldRef world, WKBundleRangeHandleRef rangeRef)
     126static WTF::String string(WKBundlePageRef page, WKBundleScriptWorldRef world, WKBundleRangeHandleRef rangeRef)
    93127{
    94128    if (!rangeRef)
    … …  
    131165}
    132166
    133 static WTF::String styleDecToStr(WKBundleCSSStyleDeclarationRef style)
     167static WTF::String styleDecToStr(WKBundleCSSStyleDeclarationRef)
    134168{
    135169    // DumpRenderTree calls -[DOMCSSStyleDeclaration description], which just dumps class name and object address.
    136170    // No existing tests actually hit this code path at the time of this writing, because WebCore doesn't call
    137171    // the editing client if the styling operation source is CommandFromDOM or CommandFromDOMWithUserInterface.
    138     StringBuilder stringBuilder;
    139     stringBuilder.appendLiteral("<DOMCSSStyleDeclaration ADDRESS>");
    140     return stringBuilder.toString();
     172    return "<DOMCSSStyleDeclaration ADDRESS>"_s;
    141173}
    142174
    143175static WTF::String string(WKSecurityOriginRef origin)
    144176{
    145     return makeString('{', toWTFString(adoptWK(WKSecurityOriginCopyProtocol(origin))), ", ", toWTFString(adoptWK(WKSecurityOriginCopyHost(origin))), ", ", WKSecurityOriginGetPort(origin), '}');
    146 }
    147 
    148 static WTF::String frameToStr(WKBundleFrameRef frame)
     177    return makeString('{', adoptWK(WKSecurityOriginCopyProtocol(origin)).get(), ", ", adoptWK(WKSecurityOriginCopyHost(origin)).get(), ", ", WKSecurityOriginGetPort(origin), '}');
     178}
     179
     180static WTF::String string(WKBundleFrameRef frame)
    149181{
    150182    auto name = adoptWK(WKBundleFrameCopyName(frame));
    151     StringBuilder stringBuilder;
    152     if (WKBundleFrameIsMainFrame(frame)) {
    153         if (!WKStringIsEmpty(name.get())) {
    154             stringBuilder.appendLiteral("main frame \"");
    155             stringBuilder.append(toWTFString(name));
    156             stringBuilder.append('"');
    157         } else
    158             stringBuilder.appendLiteral("main frame");
    159     } else {
    160         if (!WKStringIsEmpty(name.get())) {
    161             stringBuilder.appendLiteral("frame \"");
    162             stringBuilder.append(toWTFString(name));
    163             stringBuilder.append('"');
    164         }
    165         else
    166             stringBuilder.appendLiteral("frame (anonymous)");
    167     }
    168    
    169     return stringBuilder.toString();
     183    bool isMain = WKBundleFrameIsMainFrame(frame);
     184    if (WKStringIsEmpty(name.get()))
     185        return isMain ? "main frame"_s : "frame (anonymous)"_s;
     186    return makeString(isMain ? "main frame \"" : "frame \"", name.get(), '"');
    170187}
    171188
    … …  
    211228        stringBuilder.append(assignedUrlsCache().get(identifier));
    212229    else
    213         stringBuilder.appendLiteral("<unknown>");
     230        stringBuilder.append("<unknown>");
    214231}
    215232
    … …  
    394411// Loader Client Callbacks
    395412
    396 // String output must be identical to -[WebFrame _drt_descriptionSuitableForTestResult].
    397 static void dumpFrameDescriptionSuitableForTestResult(WKBundleFrameRef frame, StringBuilder& stringBuilder)
    398 {
    399     auto name = adoptWK(WKBundleFrameCopyName(frame));
    400     if (WKBundleFrameIsMainFrame(frame)) {
    401         if (WKStringIsEmpty(name.get())) {
    402             stringBuilder.appendLiteral("main frame");
    403             return;
    404         }
    405 
    406         stringBuilder.appendLiteral("main frame \"");
    407         stringBuilder.append(toWTFString(name));
    408         stringBuilder.append('"');
    409         return;
    410     }
    411 
    412     if (WKStringIsEmpty(name.get())) {
    413         stringBuilder.appendLiteral("frame (anonymous)");
    414         return;
    415     }
    416 
    417     stringBuilder.appendLiteral("frame \"");
    418     stringBuilder.append(toWTFString(name));
    419     stringBuilder.append('"');
    420 }
    421 
    422413static void dumpLoadEvent(WKBundleFrameRef frame, const char* eventName)
    423414{
    424     StringBuilder stringBuilder;
    425     dumpFrameDescriptionSuitableForTestResult(frame, stringBuilder);
    426     stringBuilder.appendLiteral(" - ");
    427     stringBuilder.append(eventName);
    428     stringBuilder.append('\n');
    429     InjectedBundle::singleton().outputText(stringBuilder.toString());
    430 }
    431 
    432 static inline void dumpRequestDescriptionSuitableForTestResult(WKURLRequestRef request, StringBuilder& stringBuilder)
     415    InjectedBundle::singleton().outputText(makeString(string(frame), " - ", eventName, '\n'));
     416}
     417
     418static String string(WKURLRequestRef request)
    433419{
    434420    auto url = adoptWK(WKURLRequestCopyURL(request));
    435421    auto firstParty = adoptWK(WKURLRequestCopyFirstPartyForCookies(request));
    436422    auto httpMethod = adoptWK(WKURLRequestCopyHTTPMethod(request));
    437 
    438     stringBuilder.append("<NSURLRequest URL ", pathSuitableForTestResult(url.get()), ", main document URL ", pathSuitableForTestResult(firstParty.get()), ", http method ");
    439     if (WKStringIsEmpty(httpMethod.get()))
    440         stringBuilder.appendLiteral("(none)");
    441     else
    442         stringBuilder.append(toWTFString(httpMethod));
    443     stringBuilder.append('>');
    444 }
    445 
    446 static inline void dumpResponseDescriptionSuitableForTestResult(WKURLResponseRef response, StringBuilder& stringBuilder, bool shouldDumpResponseHeaders = false)
     423    return makeString("<NSURLRequest URL ", pathSuitableForTestResult(url.get()),
     424        ", main document URL ", pathSuitableForTestResult(firstParty.get()),
     425        ", http method ", WKStringIsEmpty(httpMethod.get()) ? "(none)" : "", httpMethod.get(), '>');
     426}
     427
     428static String string(WKURLResponseRef response, bool shouldDumpResponseHeaders = false)
    447429{
    448430    auto url = adoptWK(WKURLResponseCopyURL(response));
    449     if (!url) {
    450         stringBuilder.appendLiteral("(null)");
    451         return;
    452     }
    453     stringBuilder.append("<NSURLResponse ", pathSuitableForTestResult(url.get()), ", http status code ", WKURLResponseHTTPStatusCode(response));
    454     if (shouldDumpResponseHeaders)
    455         stringBuilder.append(", ", InjectedBundlePage::responseHeaderCount(response), " headers");
    456     stringBuilder.append('>');
     431    if (!url)
     432        return "(null)"_s;
     433    if (!shouldDumpResponseHeaders) {
     434        return makeString("<NSURLResponse ", pathSuitableForTestResult(url.get()),
     435            ", http status code ", WKURLResponseHTTPStatusCode(response), '>');
     436    }
     437    return makeString("<NSURLResponse ", pathSuitableForTestResult(url.get()),
     438        ", http status code ", WKURLResponseHTTPStatusCode(response),
     439        ", ", InjectedBundlePage::responseHeaderCount(response), " headers>");
    457440}
    458441
    459442#if !PLATFORM(COCOA)
    460 // FIXME: Implement this for non cocoa ports.
    461 //       [GTK][WPE] https://bugs.webkit.org/show_bug.cgi?id=184295
     443
     444// FIXME: Implement this for non-Cocoa ports. [GTK][WPE] https://bugs.webkit.org/show_bug.cgi?id=184295
    462445uint64_t InjectedBundlePage::responseHeaderCount(WKURLResponseRef response)
    463446{
    464447    return 0;
    465448}
     449
    466450#endif
    467451
    … …  
    481465    stringBuilder.append("<NSError domain ", errorDomain, ", code ", errorCode);
    482466    if (auto url = adoptWK(WKErrorCopyFailingURL(error)))
    483         stringBuilder.append(", failing URL \"", toWTFString(adoptWK(WKURLCopyString(url.get()))), '"');
     467        stringBuilder.append(", failing URL \"", adoptWK(WKURLCopyString(url.get())).get(), '"');
    484468    stringBuilder.append('>');
    485469}
    … …  
    701685        return;
    702686    if (shouldIncludeFrameName)
    703         stringBuilder.append("frame '", toWTFString(adoptWK(WKBundleFrameCopyName(frame))), "' ");
     687        stringBuilder.append("frame '", adoptWK(WKBundleFrameCopyName(frame)).get(), "' ");
    704688    stringBuilder.append("scrolled to ", x, ',', y, '\n');
    705689}
    … …  
    759743            continue;
    760744
    761         stringBuilder.appendLiteral("\n--------\nFrame: '");
    762         stringBuilder.append(toWTFString(subframeName));
    763         stringBuilder.appendLiteral("'\n--------\n");
     745        stringBuilder.append("\n--------\nFrame: '", subframeName.get(), "'\n--------\n");
    764746
    765747        dumpFrameText(subframe, stringBuilder);
    … …  
    781763    auto wkData = adoptWK(WKBundleFrameCopyWebArchive(frame));
    782764    auto cfData = adoptCF(CFDataCreate(0, WKDataGetBytes(wkData.get()), WKDataGetSize(wkData.get())));
    783     auto cfString = WebCoreTestSupport::createXMLStringFromWebArchiveData(cfData.get());
    784     stringBuilder.append(cfString.get());
     765    stringBuilder.append(WebCoreTestSupport::createXMLStringFromWebArchiveData(cfData.get()).get());
    785766#endif
    786767}
    … …  
    808789    case WhatToDump::RenderTree: {
    809790        if (injectedBundle.testRunner()->isPrinting())
    810             stringBuilder.append(toWTFString(adoptWK(WKBundlePageCopyRenderTreeExternalRepresentationForPrinting(m_page)).get()));
     791            stringBuilder.append(adoptWK(WKBundlePageCopyRenderTreeExternalRepresentationForPrinting(m_page)).get());
    811792        else
    812             stringBuilder.append(toWTFString(adoptWK(WKBundlePageCopyRenderTreeExternalRepresentation(m_page, injectedBundle.testRunner()->renderTreeDumpOptions())).get()));
     793            stringBuilder.append(adoptWK(WKBundlePageCopyRenderTreeExternalRepresentation(m_page, injectedBundle.testRunner()->renderTreeDumpOptions())).get());
    813794        break;
    814795    }
    … …  
    891872
    892873    StringBuilder stringBuilder;
    893     if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) {
    894         dumpFrameDescriptionSuitableForTestResult(frame, stringBuilder);
    895         stringBuilder.appendLiteral(" - didReceiveTitle: ");
    896         stringBuilder.append(toWTFString(title));
    897         stringBuilder.append('\n');
    898     }
    899 
    900     if (injectedBundle.testRunner()->shouldDumpTitleChanges()) {
    901         stringBuilder.appendLiteral("TITLE CHANGED: '");
    902         stringBuilder.append(toWTFString(title));
    903         stringBuilder.appendLiteral("'\n");
    904     }
    905 
     874    if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
     875        stringBuilder.append(string(frame), " - didReceiveTitle: ", title, '\n');
     876    if (injectedBundle.testRunner()->shouldDumpTitleChanges())
     877        stringBuilder.append("TITLE CHANGED: '", title, "'\n");
    906878    injectedBundle.outputText(stringBuilder.toString());
    907879}
    … …  
    952924        return;
    953925
    954     StringBuilder stringBuilder;
    955     dumpFrameDescriptionSuitableForTestResult(frame, stringBuilder);
    956     stringBuilder.append(" - willPerformClientRedirectToURL: ", pathSuitableForTestResult(url), '\n');
    957     injectedBundle.outputText(stringBuilder.toString());
     926    injectedBundle.outputText(makeString(string(frame), " - willPerformClientRedirectToURL: ", pathSuitableForTestResult(url), '\n'));
    958927}
    959928
    … …  
    983952
    984953    if (unsigned pendingFrameUnloadEvents = WKBundleFrameGetPendingUnloadCount(frame))
    985         injectedBundle.outputText(makeString(frameToStr(frame), " - has ", pendingFrameUnloadEvents, " onunload handler(s)\n"));
     954        injectedBundle.outputText(makeString(string(frame), " - has ", pendingFrameUnloadEvents, " onunload handler(s)\n"));
    986955}
    987956
    … …  
    10501019        StringBuilder stringBuilder;
    10511020        dumpResourceURL(identifier, stringBuilder);
    1052         stringBuilder.appendLiteral(" - willSendRequest ");
    1053         dumpRequestDescriptionSuitableForTestResult(request, stringBuilder);
    1054         stringBuilder.appendLiteral(" redirectResponse ");
    1055         dumpResponseDescriptionSuitableForTestResult(response, stringBuilder, injectedBundle.testRunner()->shouldDumpAllHTTPRedirectedResponseHeaders());
    1056         stringBuilder.append('\n');
     1021        stringBuilder.append(" - willSendRequest ", string(request),
     1022            " redirectResponse ", string(response, injectedBundle.testRunner()->shouldDumpAllHTTPRedirectedResponseHeaders()), '\n');
    10571023        injectedBundle.outputText(stringBuilder.toString());
    10581024    }
    … …  
    10871053        }
    10881054        if (!mainFrameIsExternal && !isAllowedHost(host.get())) {
    1089             StringBuilder stringBuilder;
    1090             stringBuilder.appendLiteral("Blocked access to external URL ");
    1091             stringBuilder.append(toWTFString(urlString));
    1092             stringBuilder.append('\n');
    1093             injectedBundle.outputText(stringBuilder.toString());
     1055            injectedBundle.outputText(makeString("Blocked access to external URL ", urlString.get(), '\n'));
    10941056            return nullptr;
    10951057        }
    … …  
    11181080        StringBuilder stringBuilder;
    11191081        dumpResourceURL(identifier, stringBuilder);
    1120         stringBuilder.appendLiteral(" - didReceiveResponse ");
    1121         dumpResponseDescriptionSuitableForTestResult(response, stringBuilder);
    1122         stringBuilder.append('\n');
     1082        stringBuilder.append(" - didReceiveResponse ", string(response), '\n');
    11231083        injectedBundle.outputText(stringBuilder.toString());
    11241084    }
    … …  
    11331093
    11341094    StringBuilder stringBuilder;
    1135     stringBuilder.append(toWTFString(urlString));
    1136     stringBuilder.appendLiteral(" has MIME type ");
    1137     stringBuilder.append(toWTFString(mimeTypeString));
     1095    stringBuilder.append(urlString.get(), " has MIME type ", mimeTypeString.get());
    11381096
    11391097    String platformMimeType = platformResponseMimeType(response);
    11401098    if (!platformMimeType.isEmpty() && platformMimeType != toWTFString(mimeTypeString)) {
    1141         stringBuilder.appendLiteral(" but platform response has ");
    1142         stringBuilder.append(platformMimeType);
     1099        stringBuilder.append(" but platform response has ", platformMimeType);
    11431100    }
    11441101
    … …  
    11631120    StringBuilder stringBuilder;
    11641121    dumpResourceURL(identifier, stringBuilder);
    1165     stringBuilder.appendLiteral(" - didFinishLoading\n");
     1122    stringBuilder.append(" - didFinishLoading\n");
    11661123    injectedBundle.outputText(stringBuilder.toString());
    11671124}
    … …  
    11781135    StringBuilder stringBuilder;
    11791136    dumpResourceURL(identifier, stringBuilder);
    1180     stringBuilder.appendLiteral(" - didFailLoadingWithError: ");
     1137    stringBuilder.append(" - didFailLoadingWithError: ");
    11811138
    11821139    dumpErrorDescriptionSuitableForTestResult(error, stringBuilder);
    … …  
    12001157}
    12011158
    1202 
    12031159// Policy Client Callbacks
    12041160
    … …  
    12301186
    12311187    if (injectedBundle.testRunner()->shouldDumpPolicyCallbacks()) {
    1232         StringBuilder stringBuilder;
    1233         stringBuilder.appendLiteral(" - decidePolicyForNavigationAction\n");
    1234         dumpRequestDescriptionSuitableForTestResult(request, stringBuilder);
    1235         stringBuilder.append(" is main frame - ", WKBundleFrameIsMainFrame(frame) ? "yes" : "no");
    1236         stringBuilder.append(" should open URLs externally - ", WKBundleNavigationActionGetShouldOpenExternalURLs(navigationAction) ? "yes" : "no");
    1237         stringBuilder.append('\n');
    1238         injectedBundle.outputText(stringBuilder.toString());
     1188        injectedBundle.outputText(makeString(" - decidePolicyForNavigationAction\n", string(request),
     1189            " is main frame - ", WKBundleFrameIsMainFrame(frame) ? "yes" : "no",
     1190            " should open URLs externally - ", WKBundleNavigationActionGetShouldOpenExternalURLs(navigationAction) ? "yes" : "no", '\n'));
    12391191    }
    12401192
    … …  
    12461198
    12471199    StringBuilder stringBuilder;
    1248     stringBuilder.appendLiteral("Policy delegate: attempt to load ");
     1200    stringBuilder.append("Policy delegate: attempt to load ");
    12491201    if (isLocalFileScheme(urlScheme.get()))
    1250         stringBuilder.append(toWTFString(adoptWK(WKURLCopyLastPathComponent(url.get()))));
     1202        stringBuilder.append(adoptWK(WKURLCopyLastPathComponent(url.get())).get());
    12511203    else
    1252         stringBuilder.append(toWTFString(adoptWK(WKURLCopyString(url.get()))));
    1253     stringBuilder.appendLiteral(" with navigation type \'");
    1254     stringBuilder.append(toWTFString(NavigationTypeToString(WKBundleNavigationActionGetNavigationType(navigationAction))));
    1255     stringBuilder.appendLiteral("\'");
     1204        stringBuilder.append(adoptWK(WKURLCopyString(url.get())).get());
     1205    stringBuilder.append(" with navigation type \'", NavigationTypeToString(WKBundleNavigationActionGetNavigationType(navigationAction)).get(), '\'');
    12561206    auto hitTestResultRef = adoptWK(WKBundleNavigationActionCopyHitTestResult(navigationAction));
    12571207    if (hitTestResultRef) {
    12581208        auto nodeHandleRef = adoptWK(WKBundleHitTestResultCopyNodeHandle(hitTestResultRef.get()));
    1259         stringBuilder.appendLiteral(" originating from ");
    1260         stringBuilder.append(dumpPath(m_page, m_world.get(), nodeHandleRef.get()));
     1209        stringBuilder.append(" originating from ", dumpPath(m_page, m_world.get(), nodeHandleRef.get()));
    12611210    }
    12621211
    … …  
    12781227    auto& injectedBundle = InjectedBundle::singleton();
    12791228    if (injectedBundle.testRunner() && injectedBundle.testRunner()->isPolicyDelegateEnabled() && WKURLResponseIsAttachment(response)) {
    1280         InjectedBundle::singleton().outputText(makeString("Policy delegate: resource is an attachment, suggested file name \'", toWTFString(adoptWK(WKURLResponseCopySuggestedFilename(response))), "\'\n"));
     1229        InjectedBundle::singleton().outputText(makeString("Policy delegate: resource is an attachment, suggested file name \'", adoptWK(WKURLResponseCopySuggestedFilename(response)).get(), "'\n"));
    12811230    }
    12821231
    … …  
    13681317        return;
    13691318
    1370     WTF::String messageString = toWTFString(message);
     1319    auto messageString = toWTFString(message);
    13711320    size_t nullCharPos = messageString.find(UChar(0));
    13721321    if (nullCharPos != WTF::notFound)
    … …  
    13941343        return;
    13951344
    1396     injectedBundle.outputText(makeString("UI DELEGATE STATUS CALLBACK: setStatusText:", toWTFString(statusbarText), '\n'));
     1345    injectedBundle.outputText(makeString("UI DELEGATE STATUS CALLBACK: setStatusText:", statusbarText, '\n'));
    13971346}
    13981347
    … …  
    14171366void InjectedBundlePage::willRunJavaScriptPrompt(WKStringRef message, WKStringRef defaultValue, WKBundleFrameRef)
    14181367{
    1419     InjectedBundle::singleton().outputText(makeString("PROMPT: ", toWTFString(message), ", default text:", addLeadingSpaceStripTrailingSpacesAddNewline(toWTFString(defaultValue))));
     1368    InjectedBundle::singleton().outputText(makeString("PROMPT: ", message, ", default text:", addLeadingSpaceStripTrailingSpacesAddNewline(toWTFString(defaultValue))));
    14201369}
    14211370
    … …  
    14431392    auto& injectedBundle = InjectedBundle::singleton();
    14441393    if (injectedBundle.testRunner()->shouldDumpDatabaseCallbacks())
    1445         injectedBundle.outputText(makeString("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:", string(origin), " database:", toWTFString(databaseName), '\n'));
     1394        injectedBundle.outputText(makeString("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:", string(origin), " database:", databaseName, '\n'));
    14461395
    14471396    uint64_t defaultQuota = 5 * 1024 * 1024;
    … …  
    15261475
    15271476    if (injectedBundle.testRunner()->shouldDumpEditingCallbacks())
    1528         injectedBundle.outputText(makeString("EDITING DELEGATE: shouldBeginEditingInDOMRange:", rangeToStr(m_page, m_world.get(), range), '\n'));
     1477        injectedBundle.outputText(makeString("EDITING DELEGATE: shouldBeginEditingInDOMRange:", string(m_page, m_world.get(), range), '\n'));
    15291478    return injectedBundle.testRunner()->shouldAllowEditing();
    15301479}
    … …  
    15371486
    15381487    if (injectedBundle.testRunner()->shouldDumpEditingCallbacks())
    1539         injectedBundle.outputText(makeString("EDITING DELEGATE: shouldEndEditingInDOMRange:", rangeToStr(m_page, m_world.get(), range), '\n'));
     1488        injectedBundle.outputText(makeString("EDITING DELEGATE: shouldEndEditingInDOMRange:", string(m_page, m_world.get(), range), '\n'));
    15401489    return injectedBundle.testRunner()->shouldAllowEditing();
    15411490}
    … …  
    15471496        return true;
    15481497
    1549     static const char* insertactionstring[] = {
     1498    static constexpr const char* insertactionstring[] = {
    15501499        "WebViewInsertActionTyped",
    15511500        "WebViewInsertActionPasted",
    … …  
    15541503
    15551504    if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
    1556         StringBuilder stringBuilder;
    1557         stringBuilder.appendLiteral("EDITING DELEGATE: shouldInsertNode:");
    1558         stringBuilder.append(dumpPath(m_page, m_world.get(), node));
    1559         stringBuilder.appendLiteral(" replacingDOMRange:");
    1560         stringBuilder.append(rangeToStr(m_page, m_world.get(), rangeToReplace));
    1561         stringBuilder.appendLiteral(" givenAction:");
    1562         stringBuilder.append(insertactionstring[action]);
    1563         stringBuilder.append('\n');
    1564         injectedBundle.outputText(stringBuilder.toString());
     1505        injectedBundle.outputText(makeString("EDITING DELEGATE:"
     1506            " shouldInsertNode:", dumpPath(m_page, m_world.get(), node),
     1507            " replacingDOMRange:", string(m_page, m_world.get(), rangeToReplace),
     1508            " givenAction:", insertactionstring[action], '\n'));
    15651509    }
    15661510    return injectedBundle.testRunner()->shouldAllowEditing();
    … …  
    15731517        return true;
    15741518
    1575     static const char *insertactionstring[] = {
     1519    static constexpr const char* insertactionstring[] = {
    15761520        "WebViewInsertActionTyped",
    15771521        "WebViewInsertActionPasted",
    … …  
    15801524
    15811525    if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
    1582         StringBuilder stringBuilder;
    1583         stringBuilder.appendLiteral("EDITING DELEGATE: shouldInsertText:");
    1584         stringBuilder.append(toWTFString(text));
    1585         stringBuilder.appendLiteral(" replacingDOMRange:");
    1586         stringBuilder.append(rangeToStr(m_page, m_world.get(), rangeToReplace));
    1587         stringBuilder.appendLiteral(" givenAction:");
    1588         stringBuilder.append(insertactionstring[action]);
    1589         stringBuilder.append('\n');
    1590         injectedBundle.outputText(stringBuilder.toString());
     1526        injectedBundle.outputText(makeString("EDITING DELEGATE:"
     1527            " shouldInsertText:", text,
     1528            " replacingDOMRange:", string(m_page, m_world.get(), rangeToReplace),
     1529            " givenAction:", insertactionstring[action], '\n'));
    15911530    }
    15921531    return injectedBundle.testRunner()->shouldAllowEditing();
    … …  
    15991538        return true;
    16001539
    1601     if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
    1602         StringBuilder stringBuilder;
    1603         stringBuilder.appendLiteral("EDITING DELEGATE: shouldDeleteDOMRange:");
    1604         stringBuilder.append(rangeToStr(m_page, m_world.get(), range));
    1605         stringBuilder.append('\n');
    1606         injectedBundle.outputText(stringBuilder.toString());
    1607     }
     1540    if (injectedBundle.testRunner()->shouldDumpEditingCallbacks())
     1541        injectedBundle.outputText(makeString("EDITING DELEGATE: shouldDeleteDOMRange:", string(m_page, m_world.get(), range), '\n'));
    16081542    return injectedBundle.testRunner()->shouldAllowEditing();
    16091543}
    … …  
    16151549        return true;
    16161550
    1617     static const char *affinitystring[] = {
     1551    static constexpr const char* affinitystring[] = {
    16181552        "NSSelectionAffinityUpstream",
    16191553        "NSSelectionAffinityDownstream"
    16201554    };
    1621     static const char *boolstring[] = {
    1622         "FALSE",
    1623         "TRUE"
    1624     };
    16251555
    16261556    if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
    1627         StringBuilder stringBuilder;
    1628         stringBuilder.appendLiteral("EDITING DELEGATE: shouldChangeSelectedDOMRange:");
    1629         stringBuilder.append(rangeToStr(m_page, m_world.get(), fromRange));
    1630         stringBuilder.appendLiteral(" toDOMRange:");
    1631         stringBuilder.append(rangeToStr(m_page, m_world.get(), toRange));
    1632         stringBuilder.appendLiteral(" affinity:");
    1633         stringBuilder.append(affinitystring[affinity]);
    1634         stringBuilder.appendLiteral(" stillSelecting:");
    1635         stringBuilder.append(boolstring[stillSelecting]);
    1636         stringBuilder.append('\n');
    1637         injectedBundle.outputText(stringBuilder.toString());
     1557        injectedBundle.outputText(makeString("EDITING DELEGATE:"
     1558            " shouldChangeSelectedDOMRange:", string(m_page, m_world.get(), fromRange),
     1559            " toDOMRange:", string(m_page, m_world.get(), toRange),
     1560            " affinity:", affinitystring[affinity],
     1561            " stillSelecting:", stillSelecting ? "TRUE" : "FALSE", '\n'));
    16381562    }
    16391563    return injectedBundle.testRunner()->shouldAllowEditing();
    … …  
    16471571
    16481572    if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
    1649         StringBuilder stringBuilder;
    1650         stringBuilder.appendLiteral("EDITING DELEGATE: shouldApplyStyle:");
    1651         stringBuilder.append(styleDecToStr(style));
    1652         stringBuilder.appendLiteral(" toElementsInDOMRange:");
    1653         stringBuilder.append(rangeToStr(m_page, m_world.get(), range));
    1654         stringBuilder.append('\n');
    1655         injectedBundle.outputText(stringBuilder.toString());
     1573        injectedBundle.outputText(makeString("EDITING DELEGATE:"
     1574            " shouldApplyStyle:", styleDecToStr(style),
     1575            " toElementsInDOMRange:", string(m_page, m_world.get(), range), '\n'));
    16561576    }
    16571577    return injectedBundle.testRunner()->shouldAllowEditing();
    … …  
    16661586        return;
    16671587
    1668     StringBuilder stringBuilder;
    1669     stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidBeginEditing:");
    1670     stringBuilder.append(toWTFString(notificationName));
    1671     stringBuilder.append('\n');
    1672     injectedBundle.outputText(stringBuilder.toString());
     1588    injectedBundle.outputText(makeString("EDITING DELEGATE: webViewDidBeginEditing:", notificationName, '\n'));
    16731589}
    16741590
    … …  
    16811597        return;
    16821598
    1683     StringBuilder stringBuilder;
    1684     stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidEndEditing:");
    1685     stringBuilder.append(toWTFString(notificationName));
    1686     stringBuilder.append('\n');
    1687     injectedBundle.outputText(stringBuilder.toString());
     1599    injectedBundle.outputText(makeString("EDITING DELEGATE: webViewDidEndEditing:", notificationName, '\n'));
    16881600}
    16891601
    … …  
    16961608        return;
    16971609
    1698     StringBuilder stringBuilder;
    1699     stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidChange:");
    1700     stringBuilder.append(toWTFString(notificationName));
    1701     stringBuilder.append('\n');
    1702     injectedBundle.outputText(stringBuilder.toString());
     1610    injectedBundle.outputText(makeString("EDITING DELEGATE: webViewDidChange:", notificationName, '\n'));
    17031611}
    17041612
    … …  
    17111619        return;
    17121620
    1713     StringBuilder stringBuilder;
    1714     stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidChangeSelection:");
    1715     stringBuilder.append(toWTFString(notificationName));
    1716     stringBuilder.append('\n');
    1717     injectedBundle.outputText(stringBuilder.toString());
     1621    injectedBundle.outputText(makeString("EDITING DELEGATE: webViewDidChangeSelection:", notificationName, '\n'));
    17181622}
    17191623
    … …  
    17841688    return makeString(
    17851689        "\n============== Back Forward List ==============\n",
    1786         toWTFString(adoptWK(WKBundlePageDumpHistoryForTesting(m_page, toWK("/LayoutTests/").get())).get()),
     1690        adoptWK(WKBundlePageDumpHistoryForTesting(m_page, toWK("/LayoutTests/").get())).get(),
    17871691        "===============================================\n"
    17881692    );
Note: See TracChangeset for help on using the changeset viewer.