Changeset 277744 in webkit
- Timestamp:
- May 19, 2021, 12:37:21 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 34 edited
-
Source/JavaScriptCore/ChangeLog (modified) (1 diff)
-
Source/JavaScriptCore/inspector/ConsoleMessage.cpp (modified) (1 diff)
-
Source/JavaScriptCore/runtime/JSONObject.cpp (modified) (1 diff)
-
Source/JavaScriptCore/runtime/TypeSet.cpp (modified) (1 diff)
-
Source/WTF/ChangeLog (modified) (1 diff)
-
Source/WTF/WTF.xcodeproj/project.pbxproj (modified) (2 diffs)
-
Source/WTF/wtf/CheckedArithmetic.h (modified) (3 diffs)
-
Source/WTF/wtf/PlatformFTW.cmake (modified) (1 diff)
-
Source/WTF/wtf/PlatformMac.cmake (modified) (1 diff)
-
Source/WTF/wtf/PlatformWin.cmake (modified) (1 diff)
-
Source/WTF/wtf/SaturatedArithmetic.h (modified) (7 diffs)
-
Source/WTF/wtf/text/StringBuilder.cpp (modified) (4 diffs)
-
Source/WTF/wtf/text/StringBuilder.h (modified) (3 diffs)
-
Source/WTF/wtf/text/StringBuilderJSON.cpp (modified) (2 diffs)
-
Source/WTF/wtf/text/cf/StringConcatenateCF.h (added)
-
Source/WTF/wtf/text/cocoa/TextStreamCocoa.mm (modified) (1 diff)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/Modules/airplay/WebMediaSessionManager.cpp (modified) (2 diffs)
-
Source/WebCore/html/HTMLTextFormControlElement.cpp (modified) (1 diff)
-
Source/WebCore/page/CaptionUserPreferencesMediaAF.cpp (modified) (7 diffs)
-
Source/WebCore/page/scrolling/ScrollingCoordinator.cpp (modified) (1 diff)
-
Source/WebCore/platform/LayoutUnit.h (modified) (5 diffs)
-
Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm (modified) (4 diffs)
-
Source/WebCore/rendering/RenderCounter.cpp (modified) (1 diff)
-
Source/WebCore/style/StyleBuilderCustom.h (modified) (1 diff)
-
Source/WebCore/svg/SVGPathStringBuilder.cpp (modified) (1 diff)
-
Source/WebCore/testing/Internals.cpp (modified) (1 diff)
-
Source/WebCore/xml/XSLTProcessorLibxslt.cpp (modified) (1 diff)
-
Source/WebKit/ChangeLog (modified) (1 diff)
-
Source/WebKit/UIProcess/WebsiteData/Cocoa/WebsiteDataStoreCocoa.mm (modified) (2 diffs)
-
Tools/ChangeLog (modified) (1 diff)
-
Tools/TestWebKitAPI/Tests/WTF/SaturatedArithmeticOperations.cpp (modified) (3 diffs)
-
Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp (modified) (7 diffs)
-
Tools/TestWebKitAPI/Tests/WebKit/GetUserMedia.mm (modified) (1 diff)
-
Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp (modified) (42 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r277727 r277744 1 2021-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 1 18 2021-05-19 Mark Lam <mark.lam@apple.com> 2 19 -
trunk/Source/JavaScriptCore/inspector/ConsoleMessage.cpp
r272499 r277744 137 137 if (builder.length()) { 138 138 m_jsonLogValues.append({ JSONLogValue::Type::String, builder.toString() }); 139 builder. resize(0);139 builder.clear(); 140 140 } 141 141 -
trunk/Source/JavaScriptCore/runtime/JSONObject.cpp
r277437 r277744 576 576 // an object property. In this case we don't want the separator and 577 577 // property name that we already appended, so roll back. 578 builder. resize(rollBackPoint);578 builder.shrink(rollBackPoint); 579 579 break; 580 580 } -
trunk/Source/JavaScriptCore/runtime/TypeSet.cpp
r266885 r277744 420 420 421 421 if (representation.length() >= 3) 422 representation. resize(representation.length() - 2);422 representation.shrink(representation.length() - 2); 423 423 424 424 representation.append('}'); -
trunk/Source/WTF/ChangeLog
r277740 r277744 1 2021-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 1 181 2021-05-19 Sam Weinig <weinig@apple.com> 2 182 -
trunk/Source/WTF/WTF.xcodeproj/project.pbxproj
r277714 r277744 502 502 93B5B44D2213D616004B7AA7 /* HexNumber.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HexNumber.cpp; sourceTree = "<group>"; }; 503 503 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>"; }; 504 505 93D191CF20CAECE800C51B8E /* objcSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = objcSPI.h; sourceTree = "<group>"; }; 505 506 93DDE9311CDC052D00FD3491 /* dyldSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dyldSPI.h; sourceTree = "<group>"; }; … … 928 929 A5BA15F7182435A600A82E69 /* AtomStringImplCF.cpp */, 929 930 A5BA15F8182435A600A82E69 /* StringCF.cpp */, 931 93D0017B264DBACF00BCF109 /* StringConcatenateCF.h */, 930 932 A5BA15F9182435A600A82E69 /* StringImplCF.cpp */, 931 933 93934BD418A1F16900D0D6A1 /* StringViewCF.cpp */, -
trunk/Source/WTF/wtf/CheckedArithmetic.h
r276577 r277744 96 96 }; 97 97 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 123 98 class CrashOnOverflow { 124 99 public: … … 250 225 template <typename T> struct RemoveChecked { 251 226 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;257 227 static constexpr CleanType DefaultValue = 0; 258 228 }; … … 1070 1040 using WTF::CheckedUint64; 1071 1041 using WTF::CheckedSize; 1072 using WTF::ConditionalCrashOnOverflow;1073 1042 using WTF::CrashOnOverflow; 1074 1043 using WTF::RecordOverflow; -
trunk/Source/WTF/wtf/PlatformFTW.cmake
r255491 r277744 40 40 cf/TypeCastsCF.h 41 41 42 text/cf/StringConcatenateCF.h 42 43 text/cf/TextBreakIteratorCF.h 43 44 ) -
trunk/Source/WTF/wtf/PlatformMac.cmake
r275484 r277744 42 42 spi/mac/MetadataSPI.h 43 43 44 text/cf/StringConcatenateCF.h 44 45 text/cf/TextBreakIteratorCF.h 45 46 ) -
trunk/Source/WTF/wtf/PlatformWin.cmake
r260477 r277744 38 38 cf/TypeCastsCF.h 39 39 40 text/cf/StringConcatenateCF.h 40 41 text/cf/TextBreakIteratorCF.h 41 42 ) -
trunk/Source/WTF/wtf/SaturatedArithmetic.h
r237099 r277744 1 1 /* 2 2 * 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. 4 4 * 5 5 * Redistribution and use in source and binary forms, with or without … … 37 37 #include <wtf/Compiler.h> 38 38 39 inline bool signedAddOverflows(int32_t a, int32_t b, int32_t& result) 39 namespace 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. 42 template<typename SignedIntegralType> std::enable_if_t<std::is_integral_v<SignedIntegralType> && std::is_signed_v<SignedIntegralType>, SignedIntegralType> saturatedSum(SignedIntegralType, SignedIntegralType); 43 template<typename UnsignedIntegralType> constexpr std::enable_if_t<std::is_integral_v<UnsignedIntegralType> && !std::is_signed_v<UnsignedIntegralType>, UnsignedIntegralType> saturatedSum(UnsignedIntegralType, UnsignedIntegralType); 44 template<typename IntegralType> IntegralType saturatedDifference(IntegralType, IntegralType); 45 46 inline bool signedAddInt32Overflows(int32_t a, int32_t b, int32_t& result) 40 47 { 41 48 #if COMPILER_HAS_CLANG_BUILTIN(__builtin_sadd_overflow) && !(defined __clang_major__ && __clang_major__ < 7) … … 53 60 } 54 61 55 inline int32_t saturatedAddition(int32_t a, int32_t b)62 template<> inline int32_t saturatedSum<int32_t>(int32_t a, int32_t b) 56 63 { 57 64 int32_t result; … … 63 70 ); 64 71 #else 65 if (signedAdd Overflows(a, b, result))72 if (signedAddInt32Overflows(a, b, result)) 66 73 result = std::numeric_limits<int32_t>::max() + (static_cast<uint32_t>(a) >> 31); 67 74 #endif … … 69 76 } 70 77 71 inline bool signedSubtract Overflows(int32_t a, int32_t b, int32_t& result)78 inline bool signedSubtractInt32Overflows(int32_t a, int32_t b, int32_t& result) 72 79 { 73 80 #if COMPILER_HAS_CLANG_BUILTIN(__builtin_ssub_overflow) && !(defined __clang_major__ && __clang_major__ < 7) … … 85 92 } 86 93 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. 95 template<> inline int32_t saturatedDifference<int32_t>(int32_t a, int32_t b) 88 96 { 89 97 int32_t result; … … 95 103 ); 96 104 #else 97 if (signedSubtract Overflows(a, b, result))105 if (signedSubtractInt32Overflows(a, b, result)) 98 106 result = std::numeric_limits<int32_t>::max() + (static_cast<uint32_t>(a) >> 31); 99 107 #endif 100 108 return result; 101 109 } 110 111 template<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 117 template<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 124 using WTF::saturatedSum; 125 using WTF::saturatedDifference; -
trunk/Source/WTF/wtf/text/StringBuilder.cpp
r277437 r277744 1 1 /* 2 * Copyright (C) 2010-20 19Apple Inc. All rights reserved.2 * Copyright (C) 2010-2021 Apple Inc. All rights reserved. 3 3 * Copyright (C) 2012 Google Inc. All rights reserved. 4 4 * … … 34 34 static constexpr unsigned maxCapacity = String::MaxLength; 35 35 36 static unsigned expandedCapacity(unsigned capacity, unsigned required Length)36 static unsigned expandedCapacity(unsigned capacity, unsigned requiredCapacity) 37 37 { 38 38 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 42 void StringBuilder::didOverflow() 43 { 44 if (m_shouldCrashOnOverflow) 45 CRASH(); 46 m_length = std::numeric_limits<unsigned>::max(); 40 47 } 41 48 42 49 void StringBuilder::reifyString() const 43 50 { 44 ASSERT(!hasOverflowed());51 RELEASE_ASSERT(!hasOverflowed()); 45 52 46 53 // Check if the string already exists. 47 54 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 } 55 58 56 59 // Check for empty. … … 61 64 62 65 // 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()) 65 68 m_string = m_buffer.get(); 66 69 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 73 void StringBuilder::shrink(unsigned newLength) 71 74 { 72 75 if (hasOverflowed()) 73 76 return; 74 77 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. 106 template<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 83 115 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 122 template<typename CharacterType> void StringBuilder::reallocateBuffer(unsigned requiredCapacity) 123 { 124 // If the buffer has only one ref (by this StringBuilder), reallocate it. 86 125 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 142 void StringBuilder::reallocateBuffer(unsigned requiredCapacity) 143 { 144 if (is8Bit()) 145 reallocateBuffer<LChar>(requiredCapacity); 146 else 147 reallocateBuffer<UChar>(requiredCapacity); 148 } 149 150 void 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); 91 164 else 92 allocateBuffer (m_buffer->characters16(), m_buffer->length());165 allocateBuffer<UChar>(m_string.characters16(), newCapacity); 93 166 } 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. 175 template<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. 185 template<typename CharacterType> CharacterType* StringBuilder::extendBufferForAppendingSlowCase(unsigned requiredLength) 108 186 { 109 187 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) 245 189 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())) 271 192 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. 197 LChar* StringBuilder::extendBufferForAppendingLChar(unsigned requiredLength) 198 { 199 return extendBufferForAppending<LChar>(requiredLength); 200 } 201 202 UChar* StringBuilder::extendBufferForAppendingWithUpconvert(unsigned requiredLength) 203 { 204 if (is8Bit()) { 205 allocateBuffer<UChar>(characters<LChar>(), expandedCapacity(capacity(), requiredLength)); 292 206 if (UNLIKELY(hasOverflowed())) 293 207 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 213 void 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 225 void 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); 313 232 } 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 238 bool 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); 404 243 } 405 244 406 245 void StringBuilder::shrinkToFit() 407 246 { 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); 415 250 } 416 251 } … … 418 253 bool StringBuilder::isAllASCII() const 419 254 { 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(); 426 256 } 427 257 -
trunk/Source/WTF/wtf/text/StringBuilder.h
r277437 r277744 1 1 /* 2 * Copyright (C) 2009-20 19Apple Inc. All rights reserved.2 * Copyright (C) 2009-2021 Apple Inc. All rights reserved. 3 3 * Copyright (C) 2012 Google Inc. All rights reserved. 4 4 * … … 27 27 #pragma once 28 28 29 #include <wtf/CheckedArithmetic.h> 30 #include <wtf/text/AtomString.h> 31 #include <wtf/text/IntegerToStringConversion.h> 29 #include <wtf/SaturatedArithmetic.h> 32 30 #include <wtf/text/StringConcatenateNumbers.h> 33 #include <wtf/text/StringView.h>34 #include <wtf/text/WTFString.h>35 31 36 32 namespace WTF { 37 33 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, and40 // m_length can be instantiated based on that OverflowHandler instead. However, currently, we're41 // not able to get clang to export explicitly instantiated template methods (which would be needed42 // if we templatize StringBuilder). As a workaround, we use the ConditionalCrashOnOverflow handler43 // 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 templatize46 // StringBuilder and do away with ConditionalCrashOnOverflow.47 // See https://bugs.webkit.org/show_bug.cgi?id=191050.48 49 34 class 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. 51 36 WTF_MAKE_NONCOPYABLE(StringBuilder); 52 37 WTF_MAKE_FAST_ALLOCATED; 53 38 54 39 public: 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; 65 41 StringBuilder(StringBuilder&&) = default; 66 42 StringBuilder& operator=(StringBuilder&&) = default; 67 43 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; } 71 53 72 54 WTF_EXPORT_PRIVATE void appendCharacters(const UChar*, unsigned); 73 55 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 107 private: 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 127 template<> struct IntegerToStringConversionTrait<StringBuilder>; 128 129 // FIXME: Move this to StringView and make it take a StringView instead of a StringBuilder? 130 template<typename CharacterType> bool equal(const StringBuilder&, const CharacterType*, unsigned length); 131 132 // Inline function implementations. 133 134 inline StringBuilder::StringBuilder(OverflowHandler policy) 135 : m_shouldCrashOnOverflow { policy == OverflowHandler::CrashOnOverflow } 136 { 137 } 138 139 inline 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 147 inline 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 155 inline StringBuilder::operator StringView() const 156 { 157 if (is8Bit()) 158 return { characters<LChar>(), length() }; 159 return { characters<UChar>(), length() }; 160 } 161 162 inline 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; 96 167 return; 97 168 } 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); 121 171 return; 122 172 } 123 124 if (other.is8Bit()) 125 appendCharacters(other.characters8(), other.m_length.unsafeGet()); 173 } 174 appendCharacters(&character, 1); 175 } 176 177 inline 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; 126 182 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 189 inline 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 202 inline 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 216 inline 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 224 inline void StringBuilder::appendSubstring(const String& string, unsigned offset, unsigned length) 225 { 226 append(StringView { string }.substring(offset, length)); 227 } 228 229 inline void StringBuilder::append(const char* characters) 230 { 231 append(StringView { characters }); 232 } 233 234 inline 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 244 inline String StringBuilder::toString() 245 { 246 if (m_string.isNull()) { 233 247 shrinkToFit(); 234 248 reifyString(); 249 } 250 return m_string; 251 } 252 253 inline const String& StringBuilder::toStringPreserveCapacity() const 254 { 255 if (m_string.isNull()) 256 reifyString(); 257 return m_string; 258 } 259 260 inline 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()) 235 270 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 277 inline unsigned StringBuilder::length() const 278 { 279 RELEASE_ASSERT(!hasOverflowed()); 280 return m_length; 281 } 282 283 inline unsigned StringBuilder::capacity() const 284 { 285 return m_buffer ? m_buffer->length() : length(); 286 } 287 288 inline 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 294 inline bool StringBuilder::is8Bit() const 295 { 296 return m_buffer ? m_buffer->is8Bit() : m_string.is8Bit(); 297 } 298 299 template<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 308 template<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) 401 314 return; 402 }403 315 stringTypeAdapterAccumulator(destination, adapters...); 404 316 } else { 405 UChar* destination = extendBufferForAppending16(requiredLength); 406 if (!destination) { 407 ASSERT(hasOverflowed()); 317 auto destination = extendBufferForAppendingWithUpconvert(requiredLength); 318 if (!destination) 408 319 return; 409 }410 320 stringTypeAdapterAccumulator(destination, adapters...); 411 321 } 412 322 } 413 323 414 template<typename... StringTypes> 415 void StringBuilder::append(StringTypes... strings) 324 template<typename... StringTypes> void StringBuilder::append(StringTypes... strings) 416 325 { 417 326 appendFromAdapters(StringTypeAdapter<StringTypes>(strings)...); 418 327 } 419 328 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); 329 template<typename CharacterType> bool equal(const StringBuilder& builder, const CharacterType* buffer, unsigned length) 330 { 331 return builder == StringView { buffer, length }; 431 332 } 432 333 … … 434 335 using ReturnType = void; 435 336 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); } 437 338 }; 438 339 -
trunk/Source/WTF/wtf/text/StringBuilderJSON.cpp
r239537 r277744 106 106 if (hasOverflowed()) 107 107 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. 110 110 // 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. 112 112 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. 120 121 // 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 } 122 132 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. 127 134 if (is8Bit() && !string.is8Bit()) 128 allocateBuffer UpConvert(m_bufferCharacters8, allocationSize);135 allocateBuffer<UChar>(characters<LChar>(), allocationSize); 129 136 else 130 137 reserveCapacity(allocationSize); 131 138 if (UNLIKELY(hasOverflowed())) 132 139 return; 133 ASSERT(m_buffer->length() >= allocationSize);134 140 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; 138 144 *output++ = '"'; 139 145 appendQuotedJSONStringInternal(output, string.characters8(), string.length()); 140 146 *output++ = '"'; 141 m_length = output - m_bufferCharacters8;147 m_length = output - characters; 142 148 } 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; 144 151 *output++ = '"'; 145 152 if (string.is8Bit()) … … 148 155 appendQuotedJSONStringInternal(output, string.characters16(), string.length()); 149 156 *output++ = '"'; 150 m_length = output - m_bufferCharacters16;157 m_length = output - characters; 151 158 } 152 ASSERT(!hasOverflowed()); 153 ASSERT(m_buffer->length() >= m_length.unsafeGet<unsigned>()); 159 ASSERT(m_buffer->length() >= m_length); 154 160 } 155 161 -
trunk/Source/WTF/wtf/text/cocoa/TextStreamCocoa.mm
r260366 r277744 22 22 #import <wtf/text/TextStream.h> 23 23 24 #import <wtf/text/cf/StringConcatenateCF.h> 25 24 26 namespace WTF { 25 27 -
trunk/Source/WebCore/ChangeLog
r277740 r277744 1 2021-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 1 48 2021-05-19 Sam Weinig <weinig@apple.com> 2 49 -
trunk/Source/WebCore/Modules/airplay/WebMediaSessionManager.cpp
r276952 r277744 74 74 { 75 75 StringBuilder string; 76 string.append(" { "); 76 77 if (flags & MediaProducer::MediaState::IsPlayingAudio) 77 78 string.append("IsPlayingAudio+"); … … 93 94 string.append("IsNotPlaying"); 94 95 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(); 98 99 } 99 100 -
trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp
r271672 r277744 557 557 size_t size = result.length(); 558 558 if (size && result[size - 1] == newlineCharacter) 559 result. resize(size - 1);559 result.shrink(size - 1); 560 560 } 561 561 -
trunk/Source/WebCore/page/CaptionUserPreferencesMediaAF.cpp
r273191 r277744 49 49 #include <wtf/text/StringBuilder.h> 50 50 #include <wtf/text/StringConcatenateNumbers.h> 51 #include <wtf/text/cf/StringConcatenateCF.h> 51 52 52 53 #if PLATFORM(IOS_FAMILY) … … 309 310 { 310 311 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()) { 314 314 // This default value must be the same as the one specified in mediaControls.css for -webkit-media-text-track-container. 315 315 textColor = Color::white; 316 316 } 317 317 important = behavior == kMACaptionAppearanceBehaviorUseValue; 318 318 CGFloat opacity = MACaptionAppearanceGetForegroundOpacity(kMACaptionAppearanceDomainUser, &behavior); … … 321 321 return textColor.colorWithAlpha(opacity); 322 322 } 323 323 324 324 String CaptionUserPreferencesMediaAF::captionsTextColorCSS() const 325 325 { 326 326 bool important; 327 Color textColor = captionsTextColor(important); 328 327 auto textColor = captionsTextColor(important); 329 328 if (!textColor.isValid()) 330 329 return emptyString(); 331 332 330 return colorPropertyCSS(CSSPropertyColor, textColor, important); 333 331 } … … 335 333 static void appendCSS(StringBuilder& builder, CSSPropertyID id, const String& value, bool important) 336 334 { 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;" : ";"); 343 336 } 344 337 … … 380 373 strokeWidth = strokeWidthPt * 2; 381 374 important = behavior == kMACaptionAppearanceBehaviorUseValue; 382 383 375 return true; 384 376 } … … 419 411 MACaptionAppearanceBehavior behavior; 420 412 421 RetainPtr<CTFontDescriptorRef>font = adoptCF(MACaptionAppearanceCopyFontDescriptorForStyle(kMACaptionAppearanceDomainUser, &behavior, kMACaptionAppearanceFontStyleDefault));413 auto font = adoptCF(MACaptionAppearanceCopyFontDescriptorForStyle(kMACaptionAppearanceDomainUser, &behavior, kMACaptionAppearanceFontStyleDefault)); 422 414 if (!font) 423 415 return emptyString(); 424 416 425 RetainPtr<CFTypeRef> name = adoptCF(CTFontDescriptorCopyAttribute(font.get(), kCTFontNameAttribute));417 auto name = adoptCF(static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(font.get(), kCTFontNameAttribute))); 426 418 if (!name) 427 419 return emptyString(); 428 420 429 421 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)))) { 439 424 for (CFIndex i = 0; i < CFArrayGetCount(cascadeList.get()); i++) { 440 425 auto fontCascade = static_cast<CTFontDescriptorRef>(CFArrayGetValueAtIndex(cascadeList.get(), i)); 441 426 if (!fontCascade) 442 427 continue; 443 auto fontCascadeName = adoptCF( CTFontDescriptorCopyAttribute(fontCascade, kCTFontNameAttribute));428 auto fontCascadeName = adoptCF(static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(fontCascade, kCTFontNameAttribute))); 444 429 if (!fontCascadeName) 445 430 continue; 446 builder.append(", \""); 447 builder.append(static_cast<CFStringRef>(fontCascadeName.get())); 448 builder.append('"'); 431 builder.append(", \"", fontCascadeName.get(), '"'); 449 432 } 450 433 } 451 452 if (behavior == kMACaptionAppearanceBehaviorUseValue) 453 builder.appendLiteral(" !important"); 454 builder.append(';'); 455 434 builder.append(behavior == kMACaptionAppearanceBehaviorUseValue ? " !important;" : ";"); 456 435 return builder.toString(); 457 436 } … … 562 541 if (!MediaAccessibilityLibrary()) 563 542 return CaptionUserPreferences::captionsStyleSheetOverride(); 564 543 565 544 String captionsColor = captionsTextColorCSS(); 566 545 String edgeStyle = captionsTextEdgeCSS(); 567 546 String fontName = captionsDefaultFontCSS(); 568 547 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 586 551 String windowColor = captionsWindowCSS(); 587 552 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, '}'); 601 555 #endif // HAVE(MEDIA_ACCESSIBILITY_FRAMEWORK) 602 556 -
trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp
r271070 r277744 405 405 406 406 if (stringBuilder.length()) 407 stringBuilder. resize(stringBuilder.length() - 2);407 stringBuilder.shrink(stringBuilder.length() - 2); 408 408 return stringBuilder.toString(); 409 409 } -
trunk/Source/WebCore/platform/LayoutUnit.h
r253290 r277744 151 151 { 152 152 if (m_value > 0) 153 return saturated Addition(rawValue(), kFixedPointDenominator / 2) / kFixedPointDenominator;154 return saturated Subtraction(rawValue(), (kFixedPointDenominator / 2) - 1) / kFixedPointDenominator;153 return saturatedSum<int>(rawValue(), kFixedPointDenominator / 2) / kFixedPointDenominator; 154 return saturatedDifference<int>(rawValue(), (kFixedPointDenominator / 2) - 1) / kFixedPointDenominator; 155 155 } 156 156 … … 589 589 { 590 590 LayoutUnit returnVal; 591 returnVal.setRawValue(saturated Addition(a.rawValue(), b.rawValue()));591 returnVal.setRawValue(saturatedSum<int>(a.rawValue(), b.rawValue())); 592 592 return returnVal; 593 593 } … … 626 626 { 627 627 LayoutUnit returnVal; 628 returnVal.setRawValue(saturated Subtraction(a.rawValue(), b.rawValue()));628 returnVal.setRawValue(saturatedDifference<int>(a.rawValue(), b.rawValue())); 629 629 return returnVal; 630 630 } … … 692 692 inline LayoutUnit& operator+=(LayoutUnit& a, const LayoutUnit& b) 693 693 { 694 a.setRawValue(saturated Addition(a.rawValue(), b.rawValue()));694 a.setRawValue(saturatedSum<int>(a.rawValue(), b.rawValue())); 695 695 return a; 696 696 } … … 722 722 inline LayoutUnit& operator-=(LayoutUnit& a, const LayoutUnit& b) 723 723 { 724 a.setRawValue(saturated Subtraction(a.rawValue(), b.rawValue()));724 a.setRawValue(saturatedDifference<int>(a.rawValue(), b.rawValue())); 725 725 return a; 726 726 } -
trunk/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm
r274429 r277744 40 40 #import <wtf/cocoa/VectorCocoa.h> 41 41 #import <wtf/text/StringBuilder.h> 42 #import <wtf/text/cf/StringConcatenateCF.h> 42 43 43 44 @interface NSURL () … … 350 351 BEGIN_BLOCK_OBJC_EXCEPTIONS 351 352 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. 355 356 356 357 StringBuilder cookiesBuilder; … … 359 360 if (![[cookie name] length]) 360 361 continue; 361 362 362 if (!includeHTTPOnly && [cookie isHTTPOnly]) 363 363 continue; 364 365 364 if ([cookie isSecure]) { 366 365 didAccessSecureCookies = true; … … 368 367 continue; 369 368 } 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]); 377 370 } 378 371 return { cookiesBuilder.toString(), didAccessSecureCookies }; -
trunk/Source/WebCore/rendering/RenderCounter.cpp
r274580 r277744 188 188 189 189 if (directives.resetValue) 190 return CounterPlan { true, saturated Addition(*directives.resetValue, directives.incrementValue.valueOr(0)) };190 return CounterPlan { true, saturatedSum<int>(*directives.resetValue, directives.incrementValue.valueOr(0)) }; 191 191 if (directives.incrementValue) 192 192 return CounterPlan { false, *directives.incrementValue }; -
trunk/Source/WebCore/style/StyleBuilderCustom.h
r277580 r277744 1361 1361 directives.resetValue = value; 1362 1362 else 1363 directives.incrementValue = saturated Addition(directives.incrementValue.valueOr(0), value);1363 directives.incrementValue = saturatedSum<int>(directives.incrementValue.valueOr(0), value); 1364 1364 } 1365 1365 } -
trunk/Source/WebCore/svg/SVGPathStringBuilder.cpp
r254514 r277744 37 37 38 38 // Remove trailing space. 39 m_stringBuilder. resize(size - 1);39 m_stringBuilder.shrink(size - 1); 40 40 return m_stringBuilder.toString(); 41 41 } -
trunk/Source/WebCore/testing/Internals.cpp
r277584 r277744 4639 4639 string.append("IsNotPlaying"); 4640 4640 else 4641 string. resize(string.length() - 1);4641 string.shrink(string.length() - 1); 4642 4642 4643 4643 return string.toString(); -
trunk/Source/WebCore/xml/XSLTProcessorLibxslt.cpp
r270449 r277744 213 213 // Workaround for <http://bugzilla.gnome.org/show_bug.cgi?id=495668>: libxslt appends an extra line feed to the result. 214 214 if (resultBuilder.length() > 0 && resultBuilder[resultBuilder.length() - 1] == '\n') 215 resultBuilder. resize(resultBuilder.length() - 1);215 resultBuilder.shrink(resultBuilder.length() - 1); 216 216 217 217 resultString = resultBuilder.toString(); -
trunk/Source/WebKit/ChangeLog
r277743 r277744 1 2021-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 1 12 2021-05-19 Aditya Keerthi <akeerthi@apple.com> 2 13 -
trunk/Source/WebKit/UIProcess/WebsiteData/Cocoa/WebsiteDataStoreCocoa.mm
r277449 r277744 48 48 #import <wtf/URL.h> 49 49 #import <wtf/cocoa/Entitlements.h> 50 #import <wtf/text/ StringBuilder.h>50 #import <wtf/text/cf/StringConcatenateCF.h> 51 51 52 52 #if PLATFORM(IOS_FAMILY) … … 116 116 } 117 117 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) }; 127 122 if (url.isValid()) 128 123 resourceLoadStatisticsManualPrevalentResource = WebCore::RegistrableDomain { url }; -
trunk/Tools/ChangeLog
r277742 r277744 1 2021-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 1 61 2021-05-19 Aakash Jain <aakash_jain@apple.com> 2 62 -
trunk/Tools/TestWebKitAPI/Tests/WTF/SaturatedArithmeticOperations.cpp
r126509 r277744 1 1 /* 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. 3 4 * 4 5 * Redistribution and use in source and binary forms, with or without … … 30 31 31 32 #include "config.h" 32 #include "limits.h" 33 34 #include <limits.h> 33 35 #include <wtf/SaturatedArithmetic.h> 34 36 … … 37 39 TEST(WTF, SaturatedArithmeticAddition) 38 40 { 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)); 43 45 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)); 48 50 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)); 57 59 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)); 67 69 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)); 71 93 } 72 94 73 95 TEST(WTF, SaturatedArithmeticSubtraction) 74 96 { 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)); 79 101 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)); 84 106 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)); 94 116 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)); 99 121 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)); 103 125 } 104 126 -
trunk/Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp
r277437 r277744 216 216 // Resizing the StringBuilder should not affect the original result of toString(). 217 217 string1 = builder.toString(); 218 builder. resize(10);218 builder.shrink(10); 219 219 builder.append("###"); 220 220 EXPECT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1); … … 261 261 EXPECT_EQ(capacity, builder.capacity()); 262 262 EXPECT_EQ(string.characters8(), builder.characters8()); 263 builder. resize(10);263 builder.shrink(10); 264 264 builder.append("###"); 265 265 EXPECT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1); … … 289 289 StringBuilder builder; 290 290 builder.append("0123456789"); 291 builder. resize(10);291 builder.shrink(10); 292 292 EXPECT_EQ(10U, builder.length()); 293 293 expectBuilderContent("0123456789", builder); 294 builder. resize(8);294 builder.shrink(8); 295 295 EXPECT_EQ(8U, builder.length()); 296 296 expectBuilderContent("01234567", builder); 297 297 298 298 builder.toString(); 299 builder. resize(7);299 builder.shrink(7); 300 300 EXPECT_EQ(7U, builder.length()); 301 301 expectBuilderContent("0123456", builder); 302 builder. resize(0);302 builder.shrink(0); 303 303 expectEmpty(builder); 304 304 } … … 330 330 EXPECT_TRUE(builder1 != builder2); 331 331 332 builder2. resize(3);332 builder2.shrink(3); 333 333 EXPECT_TRUE(builder1 == builder2); 334 334 … … 337 337 } 338 338 339 TEST(StringBuilderTest, CanShrink)339 TEST(StringBuilderTest, ShouldShrinkToFit) 340 340 { 341 341 StringBuilder builder; 342 342 builder.reserveCapacity(256); 343 EXPECT_TRUE(builder. canShrink());343 EXPECT_TRUE(builder.shouldShrinkToFit()); 344 344 for (int i = 0; i < 256; i++) 345 345 builder.append('x'); 346 346 EXPECT_EQ(builder.length(), builder.capacity()); 347 EXPECT_FALSE(builder. canShrink());347 EXPECT_FALSE(builder.shouldShrinkToFit()); 348 348 } 349 349 … … 356 356 357 357 builder.reserveCapacity(256); 358 EXPECT_TRUE(builder. canShrink());358 EXPECT_TRUE(builder.shouldShrinkToFit()); 359 359 for (int i = builder.length(); i < 128; i++) 360 360 builder.append('x'); … … 368 368 EXPECT_EQ(128u, atomString1.length()); 369 369 370 EXPECT_FALSE(builder. canShrink());370 EXPECT_FALSE(builder.shouldShrinkToFit()); 371 371 String string = builder.toString(); 372 372 AtomString atomString2 = builder.toAtomString(); -
trunk/Tools/TestWebKitAPI/Tests/WebKit/GetUserMedia.mm
r276892 r277744 128 128 string.append("_WKMediaCaptureStateDeprecatedNone"); 129 129 else 130 string.resize(string.length() - 2); 131 130 string.shrink(string.length() - 2); 132 131 return string.toString(); 133 132 } -
trunk/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp
r277437 r277744 53 53 #include <wtf/text/StringBuilder.h> 54 54 55 #if USE(CF) 56 #include <wtf/text/cf/StringConcatenateCF.h> 57 #endif 58 55 59 #if USE(CF) && !PLATFORM(WIN_CAIRO) && !USE(DIRECT2D) 56 60 #include "WebArchiveDumpSupport.h" … … 58 62 59 63 using namespace std; 64 65 namespace WTF { 66 67 template<> class StringTypeAdapter<WKStringRef> { 68 public: 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 74 private: 75 WKStringRef m_string; 76 }; 77 78 inline StringTypeAdapter<WKStringRef>::StringTypeAdapter(WKStringRef string) 79 : m_string { string } 80 { 81 } 82 83 template<> inline void StringTypeAdapter<WKStringRef>::writeTo<LChar>(LChar*) const 84 { 85 } 86 87 template<> 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 } 60 94 61 95 namespace WTR { … … 90 124 } 91 125 92 static WTF::String rangeToStr(WKBundlePageRef page, WKBundleScriptWorldRef world, WKBundleRangeHandleRef rangeRef)126 static WTF::String string(WKBundlePageRef page, WKBundleScriptWorldRef world, WKBundleRangeHandleRef rangeRef) 93 127 { 94 128 if (!rangeRef) … … 131 165 } 132 166 133 static WTF::String styleDecToStr(WKBundleCSSStyleDeclarationRef style)167 static WTF::String styleDecToStr(WKBundleCSSStyleDeclarationRef) 134 168 { 135 169 // DumpRenderTree calls -[DOMCSSStyleDeclaration description], which just dumps class name and object address. 136 170 // No existing tests actually hit this code path at the time of this writing, because WebCore doesn't call 137 171 // 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; 141 173 } 142 174 143 175 static WTF::String string(WKSecurityOriginRef origin) 144 176 { 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 180 static WTF::String string(WKBundleFrameRef frame) 149 181 { 150 182 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(), '"'); 170 187 } 171 188 … … 211 228 stringBuilder.append(assignedUrlsCache().get(identifier)); 212 229 else 213 stringBuilder.append Literal("<unknown>");230 stringBuilder.append("<unknown>"); 214 231 } 215 232 … … 394 411 // Loader Client Callbacks 395 412 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 422 413 static void dumpLoadEvent(WKBundleFrameRef frame, const char* eventName) 423 414 { 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 418 static String string(WKURLRequestRef request) 433 419 { 434 420 auto url = adoptWK(WKURLRequestCopyURL(request)); 435 421 auto firstParty = adoptWK(WKURLRequestCopyFirstPartyForCookies(request)); 436 422 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 428 static String string(WKURLResponseRef response, bool shouldDumpResponseHeaders = false) 447 429 { 448 430 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>"); 457 440 } 458 441 459 442 #if !PLATFORM(COCOA) 460 // FIXME: Implement this for non cocoa ports. 461 // [GTK][WPE] https://bugs.webkit.org/show_bug.cgi?id=184295443 444 // FIXME: Implement this for non-Cocoa ports. [GTK][WPE] https://bugs.webkit.org/show_bug.cgi?id=184295 462 445 uint64_t InjectedBundlePage::responseHeaderCount(WKURLResponseRef response) 463 446 { 464 447 return 0; 465 448 } 449 466 450 #endif 467 451 … … 481 465 stringBuilder.append("<NSError domain ", errorDomain, ", code ", errorCode); 482 466 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(), '"'); 484 468 stringBuilder.append('>'); 485 469 } … … 701 685 return; 702 686 if (shouldIncludeFrameName) 703 stringBuilder.append("frame '", toWTFString(adoptWK(WKBundleFrameCopyName(frame))), "' ");687 stringBuilder.append("frame '", adoptWK(WKBundleFrameCopyName(frame)).get(), "' "); 704 688 stringBuilder.append("scrolled to ", x, ',', y, '\n'); 705 689 } … … 759 743 continue; 760 744 761 stringBuilder.appendLiteral("\n--------\nFrame: '"); 762 stringBuilder.append(toWTFString(subframeName)); 763 stringBuilder.appendLiteral("'\n--------\n"); 745 stringBuilder.append("\n--------\nFrame: '", subframeName.get(), "'\n--------\n"); 764 746 765 747 dumpFrameText(subframe, stringBuilder); … … 781 763 auto wkData = adoptWK(WKBundleFrameCopyWebArchive(frame)); 782 764 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()); 785 766 #endif 786 767 } … … 808 789 case WhatToDump::RenderTree: { 809 790 if (injectedBundle.testRunner()->isPrinting()) 810 stringBuilder.append( toWTFString(adoptWK(WKBundlePageCopyRenderTreeExternalRepresentationForPrinting(m_page)).get()));791 stringBuilder.append(adoptWK(WKBundlePageCopyRenderTreeExternalRepresentationForPrinting(m_page)).get()); 811 792 else 812 stringBuilder.append( toWTFString(adoptWK(WKBundlePageCopyRenderTreeExternalRepresentation(m_page, injectedBundle.testRunner()->renderTreeDumpOptions())).get()));793 stringBuilder.append(adoptWK(WKBundlePageCopyRenderTreeExternalRepresentation(m_page, injectedBundle.testRunner()->renderTreeDumpOptions())).get()); 813 794 break; 814 795 } … … 891 872 892 873 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"); 906 878 injectedBundle.outputText(stringBuilder.toString()); 907 879 } … … 952 924 return; 953 925 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')); 958 927 } 959 928 … … 983 952 984 953 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")); 986 955 } 987 956 … … 1050 1019 StringBuilder stringBuilder; 1051 1020 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'); 1057 1023 injectedBundle.outputText(stringBuilder.toString()); 1058 1024 } … … 1087 1053 } 1088 1054 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')); 1094 1056 return nullptr; 1095 1057 } … … 1118 1080 StringBuilder stringBuilder; 1119 1081 dumpResourceURL(identifier, stringBuilder); 1120 stringBuilder.appendLiteral(" - didReceiveResponse "); 1121 dumpResponseDescriptionSuitableForTestResult(response, stringBuilder); 1122 stringBuilder.append('\n'); 1082 stringBuilder.append(" - didReceiveResponse ", string(response), '\n'); 1123 1083 injectedBundle.outputText(stringBuilder.toString()); 1124 1084 } … … 1133 1093 1134 1094 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()); 1138 1096 1139 1097 String platformMimeType = platformResponseMimeType(response); 1140 1098 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); 1143 1100 } 1144 1101 … … 1163 1120 StringBuilder stringBuilder; 1164 1121 dumpResourceURL(identifier, stringBuilder); 1165 stringBuilder.append Literal(" - didFinishLoading\n");1122 stringBuilder.append(" - didFinishLoading\n"); 1166 1123 injectedBundle.outputText(stringBuilder.toString()); 1167 1124 } … … 1178 1135 StringBuilder stringBuilder; 1179 1136 dumpResourceURL(identifier, stringBuilder); 1180 stringBuilder.append Literal(" - didFailLoadingWithError: ");1137 stringBuilder.append(" - didFailLoadingWithError: "); 1181 1138 1182 1139 dumpErrorDescriptionSuitableForTestResult(error, stringBuilder); … … 1200 1157 } 1201 1158 1202 1203 1159 // Policy Client Callbacks 1204 1160 … … 1230 1186 1231 1187 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')); 1239 1191 } 1240 1192 … … 1246 1198 1247 1199 StringBuilder stringBuilder; 1248 stringBuilder.append Literal("Policy delegate: attempt to load ");1200 stringBuilder.append("Policy delegate: attempt to load "); 1249 1201 if (isLocalFileScheme(urlScheme.get())) 1250 stringBuilder.append( toWTFString(adoptWK(WKURLCopyLastPathComponent(url.get()))));1202 stringBuilder.append(adoptWK(WKURLCopyLastPathComponent(url.get())).get()); 1251 1203 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(), '\''); 1256 1206 auto hitTestResultRef = adoptWK(WKBundleNavigationActionCopyHitTestResult(navigationAction)); 1257 1207 if (hitTestResultRef) { 1258 1208 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())); 1261 1210 } 1262 1211 … … 1278 1227 auto& injectedBundle = InjectedBundle::singleton(); 1279 1228 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")); 1281 1230 } 1282 1231 … … 1368 1317 return; 1369 1318 1370 WTF::StringmessageString = toWTFString(message);1319 auto messageString = toWTFString(message); 1371 1320 size_t nullCharPos = messageString.find(UChar(0)); 1372 1321 if (nullCharPos != WTF::notFound) … … 1394 1343 return; 1395 1344 1396 injectedBundle.outputText(makeString("UI DELEGATE STATUS CALLBACK: setStatusText:", toWTFString(statusbarText), '\n'));1345 injectedBundle.outputText(makeString("UI DELEGATE STATUS CALLBACK: setStatusText:", statusbarText, '\n')); 1397 1346 } 1398 1347 … … 1417 1366 void InjectedBundlePage::willRunJavaScriptPrompt(WKStringRef message, WKStringRef defaultValue, WKBundleFrameRef) 1418 1367 { 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)))); 1420 1369 } 1421 1370 … … 1443 1392 auto& injectedBundle = InjectedBundle::singleton(); 1444 1393 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')); 1446 1395 1447 1396 uint64_t defaultQuota = 5 * 1024 * 1024; … … 1526 1475 1527 1476 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')); 1529 1478 return injectedBundle.testRunner()->shouldAllowEditing(); 1530 1479 } … … 1537 1486 1538 1487 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')); 1540 1489 return injectedBundle.testRunner()->shouldAllowEditing(); 1541 1490 } … … 1547 1496 return true; 1548 1497 1549 static const char* insertactionstring[] = {1498 static constexpr const char* insertactionstring[] = { 1550 1499 "WebViewInsertActionTyped", 1551 1500 "WebViewInsertActionPasted", … … 1554 1503 1555 1504 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')); 1565 1509 } 1566 1510 return injectedBundle.testRunner()->shouldAllowEditing(); … … 1573 1517 return true; 1574 1518 1575 static const char *insertactionstring[] = {1519 static constexpr const char* insertactionstring[] = { 1576 1520 "WebViewInsertActionTyped", 1577 1521 "WebViewInsertActionPasted", … … 1580 1524 1581 1525 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')); 1591 1530 } 1592 1531 return injectedBundle.testRunner()->shouldAllowEditing(); … … 1599 1538 return true; 1600 1539 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')); 1608 1542 return injectedBundle.testRunner()->shouldAllowEditing(); 1609 1543 } … … 1615 1549 return true; 1616 1550 1617 static const char *affinitystring[] = {1551 static constexpr const char* affinitystring[] = { 1618 1552 "NSSelectionAffinityUpstream", 1619 1553 "NSSelectionAffinityDownstream" 1620 1554 }; 1621 static const char *boolstring[] = {1622 "FALSE",1623 "TRUE"1624 };1625 1555 1626 1556 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')); 1638 1562 } 1639 1563 return injectedBundle.testRunner()->shouldAllowEditing(); … … 1647 1571 1648 1572 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')); 1656 1576 } 1657 1577 return injectedBundle.testRunner()->shouldAllowEditing(); … … 1666 1586 return; 1667 1587 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')); 1673 1589 } 1674 1590 … … 1681 1597 return; 1682 1598 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')); 1688 1600 } 1689 1601 … … 1696 1608 return; 1697 1609 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')); 1703 1611 } 1704 1612 … … 1711 1619 return; 1712 1620 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')); 1718 1622 } 1719 1623 … … 1784 1688 return makeString( 1785 1689 "\n============== Back Forward List ==============\n", 1786 toWTFString(adoptWK(WKBundlePageDumpHistoryForTesting(m_page, toWK("/LayoutTests/").get())).get()),1690 adoptWK(WKBundlePageDumpHistoryForTesting(m_page, toWK("/LayoutTests/").get())).get(), 1787 1691 "===============================================\n" 1788 1692 );
Note:
See TracChangeset
for help on using the changeset viewer.