Finish removing String::format
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 2 Mar 2019 05:45:11 +0000 (05:45 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 2 Mar 2019 05:45:11 +0000 (05:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=194893

Reviewed by Daniel Bates.
Source/JavaScriptCore:

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::nameForRegister): Use makeString instead of String::format,
using the new "pad" function.

Source/WebCore:

* dom/Document.cpp:
(WebCore::Document::lastModified const): Use makeString and pad.
* html/FTPDirectoryDocument.cpp:
(WebCore::processFileDateString): Ditto.

* mathml/MathMLElement.cpp:
(WebCore::convertToPercentageIfNeeded): Use makeString and FormattedNumber.

* page/cocoa/ResourceUsageOverlayCocoa.mm:
(WebCore::ResourceUsageOverlay::platformDraw): Use makeString and pad.

* page/linux/ResourceUsageOverlayLinux.cpp:
(WebCore::cpuUsageString): Use makeString, FormattedNumber, and pad.
(WebCore::gcTimerString): Use String::number.

* platform/DateComponents.cpp:
(WebCore::DateComponents::toStringForTime const): Use makeString and pad.
(WebCore::DateComponents::toString const): Ditto.

* platform/LocalizedStrings.cpp: Removed comment that mentioned String::format,
and that was also inaccurate.

* platform/audio/HRTFElevation.cpp:
(WebCore::HRTFElevation::calculateKernelsForAzimuthElevation):
Use makeString and pad.
* platform/mock/MockRealtimeVideoSource.cpp:
(WebCore::MockRealtimeVideoSource::drawText): Ditto.
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::logLayerInfo): Ditto.
* rendering/RenderTheme.cpp:
(WebCore::RenderTheme::formatMediaControlsTime const): Ditto.

Source/WebKit:

* UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm:
(WebKit::LocalAuthenticator::getAssertion): Use makeString, attempting to fix
a problem where we passed an NSData * to format with a "%s"."

Source/WebKitLegacy/win:

* FullscreenVideoController.cpp:
(timeToString): Use makeString and pad.

Source/WTF:

* wtf/Assertions.cpp:
(WTF::createWithFormatAndArguments): Moved this here from WTFString.cpp.
(WTFLog): Use WTF::createWithFormatAndArguments instead of String::format.

* wtf/HexNumber.h: Deleted unneeded toString function.

* wtf/text/StringConcatenate.h: Got rid of unneeded forward declaration of
StringTypeAdapter, since that's now in Forward.h. Tweaked formatting of templates
a bit. Use function templates for writeTo functions rather than having two of each.
Removed unused toString functions. Optimized case where we use have a UChar* and
a length of zero to not force the result to be 16-bit. Also gets rid of a small
NO_RETURN_DUE_TO_CRASH mess that we don't need. Refactored constructors to use some
static member helper functions to compute string lengths. Added the pad function
and the PaddingSpecification struct template, so we can add padding to anything
we can turn into a string. Got rid of the special case overload for single
arguments, since it only worked for things that the String constructor can handle.
Instead we will now use StringTypeAdapter, which works for more types. Possibly
less optimal for some special cases, which we could specialize for later if we like.
* wtf/text/StringConcatenateNumbers.h: Ditto.
* wtf/text/StringOperators.h: Ditto.
* wtf/text/StringView.h: Ditto.

* wtf/text/WTFString.cpp:
(WTF::createWithFormatAndArguments): Deleted.
(WTF::String::format): Deleted.
* wtf/text/WTFString.h: Deleted declaration of String::format.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@242308 268f45cc-cd09-0410-ab3c-d52691b4dbfc

29 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/WTF/ChangeLog
Source/WTF/wtf/Assertions.cpp
Source/WTF/wtf/HexNumber.h
Source/WTF/wtf/text/StringConcatenate.h
Source/WTF/wtf/text/StringConcatenateNumbers.h
Source/WTF/wtf/text/StringOperators.h
Source/WTF/wtf/text/StringView.h
Source/WTF/wtf/text/WTFString.cpp
Source/WTF/wtf/text/WTFString.h
Source/WebCore/ChangeLog
Source/WebCore/dom/Document.cpp
Source/WebCore/html/FTPDirectoryDocument.cpp
Source/WebCore/mathml/MathMLElement.cpp
Source/WebCore/page/cocoa/ResourceUsageOverlayCocoa.mm
Source/WebCore/page/linux/ResourceUsageOverlayLinux.cpp
Source/WebCore/platform/DateComponents.cpp
Source/WebCore/platform/LocalizedStrings.cpp
Source/WebCore/platform/audio/HRTFElevation.cpp
Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp
Source/WebCore/rendering/RenderLayerCompositor.cpp
Source/WebCore/rendering/RenderTheme.cpp
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm
Source/WebKitLegacy/win/ChangeLog
Source/WebKitLegacy/win/FullscreenVideoController.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WTF/StringConcatenate.cpp

index f99af92..200a049 100644 (file)
@@ -1,3 +1,14 @@
+2019-03-01  Darin Adler  <darin@apple.com>
+
+        Finish removing String::format
+        https://bugs.webkit.org/show_bug.cgi?id=194893
+
+        Reviewed by Daniel Bates.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::nameForRegister): Use makeString instead of String::format,
+        using the new "pad" function.
+
 2019-03-01  Christopher Reid  <chris.reid@sony.com>
 
         [PlayStation] Upstream playstation's remote inspector server
index 23527e4..ae7e813 100644 (file)
@@ -92,6 +92,7 @@
 #include <wtf/Forward.h>
 #include <wtf/SimpleStats.h>
 #include <wtf/StringPrintStream.h>
+#include <wtf/text/StringConcatenateNumbers.h>
 #include <wtf/text/UniquedStringImpl.h>
 
 #if ENABLE(ASSEMBLER)
@@ -2888,9 +2889,9 @@ String CodeBlock::nameForRegister(VirtualRegister virtualRegister)
     if (virtualRegister == thisRegister())
         return "this"_s;
     if (virtualRegister.isArgument())
-        return String::format("arguments[%3d]", virtualRegister.toArgument());
+        return makeString("arguments[", pad(' ', 3, virtualRegister.toArgument()), ']');
 
-    return "";
+    return emptyString();
 }
 
 ValueProfile* CodeBlock::tryGetValueProfileForBytecodeOffset(int bytecodeOffset)
index 5b86b5a..1978387 100644 (file)
@@ -1,3 +1,37 @@
+2019-03-01  Darin Adler  <darin@apple.com>
+
+        Finish removing String::format
+        https://bugs.webkit.org/show_bug.cgi?id=194893
+
+        Reviewed by Daniel Bates.
+
+        * wtf/Assertions.cpp:
+        (WTF::createWithFormatAndArguments): Moved this here from WTFString.cpp.
+        (WTFLog): Use WTF::createWithFormatAndArguments instead of String::format.
+
+        * wtf/HexNumber.h: Deleted unneeded toString function.
+
+        * wtf/text/StringConcatenate.h: Got rid of unneeded forward declaration of
+        StringTypeAdapter, since that's now in Forward.h. Tweaked formatting of templates
+        a bit. Use function templates for writeTo functions rather than having two of each.
+        Removed unused toString functions. Optimized case where we use have a UChar* and
+        a length of zero to not force the result to be 16-bit. Also gets rid of a small
+        NO_RETURN_DUE_TO_CRASH mess that we don't need. Refactored constructors to use some
+        static member helper functions to compute string lengths. Added the pad function
+        and the PaddingSpecification struct template, so we can add padding to anything
+        we can turn into a string. Got rid of the special case overload for single
+        arguments, since it only worked for things that the String constructor can handle.
+        Instead we will now use StringTypeAdapter, which works for more types. Possibly
+        less optimal for some special cases, which we could specialize for later if we like.
+        * wtf/text/StringConcatenateNumbers.h: Ditto.
+        * wtf/text/StringOperators.h: Ditto.
+        * wtf/text/StringView.h: Ditto.
+
+        * wtf/text/WTFString.cpp:
+        (WTF::createWithFormatAndArguments): Deleted.
+        (WTF::String::format): Deleted.
+        * wtf/text/WTFString.h: Deleted declaration of String::format.
+
 2019-03-01  Alex Christensen  <achristensen@webkit.org>
 
         Revert r241223, r241235, and r241287
index 25f2691..d78ab97 100644 (file)
 #include <unistd.h>
 #endif
 
+namespace WTF {
+
+WTF_ATTRIBUTE_PRINTF(1, 0) static String createWithFormatAndArguments(const char* format, va_list args)
+{
+    va_list argsCopy;
+    va_copy(argsCopy, args);
+
+    ALLOW_NONLITERAL_FORMAT_BEGIN
+
+#if USE(CF) && !OS(WINDOWS)
+    if (strstr(format, "%@")) {
+        auto cfFormat = adoptCF(CFStringCreateWithCString(kCFAllocatorDefault, format, kCFStringEncodingUTF8));
+        auto result = adoptCF(CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, nullptr, cfFormat.get(), args));
+        va_end(argsCopy);
+        return result.get();
+    }
+#endif
+
+    // Do the format once to get the length.
+#if COMPILER(MSVC)
+    int result = _vscprintf(format, args);
+#else
+    char ch;
+    int result = vsnprintf(&ch, 1, format, args);
+#endif
+
+    if (!result) {
+        va_end(argsCopy);
+        return emptyString();
+    }
+    if (result < 0) {
+        va_end(argsCopy);
+        return { };
+    }
+
+    Vector<char, 256> buffer;
+    unsigned length = result;
+    buffer.grow(length + 1);
+
+    // Now do the formatting again, guaranteed to fit.
+    vsnprintf(buffer.data(), buffer.size(), format, argsCopy);
+    va_end(argsCopy);
+
+    ALLOW_NONLITERAL_FORMAT_END
+
+    return StringImpl::create(reinterpret_cast<const LChar*>(buffer.data()), length);
+}
+
+}
+
 extern "C" {
 
 static void logToStderr(const char* buffer)
@@ -393,7 +443,7 @@ static void WTFLogVaList(WTFLogChannel* channel, const char* format, va_list arg
     ASSERT(channel->state == WTFLogChannelOnWithAccumulation);
 
     ALLOW_NONLITERAL_FORMAT_BEGIN
-    String loggingString = String::format(format, args);
+    String loggingString = WTF::createWithFormatAndArguments(format, args);
     ALLOW_NONLITERAL_FORMAT_END
 
     if (!loggingString.endsWith('\n'))
index 90ad90a..2012b8f 100644 (file)
@@ -102,7 +102,6 @@ public:
     unsigned length() const { return m_buffer.length; }
     bool is8Bit() const { return true; }
     template<typename CharacterType> void writeTo(CharacterType* destination) const { StringImpl::copyCharacters(destination, characters(), length()); }
-    String toString() const { return { characters(), length() }; }
 
 private:
     const LChar* characters() const { return &*(m_buffer.characters.end() - length()); }
index 19f2312..1c501ed 100644 (file)
@@ -25,7 +25,7 @@
 
 #pragma once
 
-#include <string.h>
+#include <cstring>
 #include <wtf/CheckedArithmetic.h>
 #include <wtf/text/AtomicString.h>
 #include <wtf/text/StringView.h>
 
 namespace WTF {
 
-template<typename StringType, typename>
-class StringTypeAdapter;
-
-template<>
-class StringTypeAdapter<char, void> {
+template<> class StringTypeAdapter<char, void> {
 public:
     StringTypeAdapter(char character)
-        : m_character(character)
+        : m_character { character }
     {
     }
 
     unsigned length() { return 1; }
     bool is8Bit() { return true; }
-
-    void writeTo(LChar* destination) const
-    {
-        *destination = m_character;
-    }
-
-    void writeTo(UChar* destination) const
-    {
-        *destination = m_character;
-    }
-
-    String toString() const { return String(&m_character, 1); }
+    template<typename CharacterType> void writeTo(CharacterType* destination) const { *destination = m_character; }
 
 private:
     char m_character;
 };
 
-template<>
-class StringTypeAdapter<UChar, void> {
+template<> class StringTypeAdapter<UChar, void> {
 public:
     StringTypeAdapter(UChar character)
-        : m_character(character)
+        : m_character { character }
     {
     }
 
     unsigned length() const { return 1; }
-    bool is8Bit() const { return m_character <= 0xff; }
+    bool is8Bit() const { return isLatin1(m_character); }
 
     void writeTo(LChar* destination) const
     {
         ASSERT(is8Bit());
-        *destination = static_cast<LChar>(m_character);
-    }
-
-    void writeTo(UChar* destination) const
-    {
         *destination = m_character;
     }
 
-    String toString() const { return String(&m_character, 1); }
+    void writeTo(UChar* destination) const { *destination = m_character; }
 
 private:
     UChar m_character;
 };
 
-template<>
-class StringTypeAdapter<const LChar*, void> {
+template<> class StringTypeAdapter<const LChar*, void> {
 public:
     StringTypeAdapter(const LChar* characters)
-        : m_characters(characters)
+        : m_characters { characters }
+        , m_length { computeLength(characters) }
     {
-        size_t length = strlen(reinterpret_cast<const char*>(characters));
-        RELEASE_ASSERT(length <= String::MaxLength);
-        m_length = static_cast<unsigned>(length);
     }
 
     unsigned length() const { return m_length; }
     bool is8Bit() const { return true; }
+    template<typename CharacterType> void writeTo(CharacterType* destination) const { StringImpl::copyCharacters(destination, m_characters, m_length); }
 
-    void writeTo(LChar* destination) const
-    {
-        StringView(m_characters, m_length).getCharactersWithUpconvert(destination);
-    }
-
-    void writeTo(UChar* destination) const
+private:
+    static unsigned computeLength(const LChar* characters)
     {
-        StringView(m_characters, m_length).getCharactersWithUpconvert(destination);
+        size_t length = std::strlen(reinterpret_cast<const char*>(characters));
+        RELEASE_ASSERT(length <= String::MaxLength);
+        return static_cast<unsigned>(length);
     }
 
-    String toString() const { return String(m_characters, m_length); }
-
-private:
     const LChar* m_characters;
     unsigned m_length;
 };
 
-template<>
-class StringTypeAdapter<const UChar*, void> {
+template<> class StringTypeAdapter<const UChar*, void> {
 public:
     StringTypeAdapter(const UChar* characters)
-        : m_characters(characters)
+        : m_characters { characters }
+        , m_length { computeLength(characters) }
     {
-        size_t length = 0;
-        while (m_characters[length])
-            ++length;
-        RELEASE_ASSERT(length <= String::MaxLength);
-        m_length = static_cast<unsigned>(length);
     }
 
     unsigned length() const { return m_length; }
-    bool is8Bit() const { return false; }
+    bool is8Bit() const { return !m_length; }
+    void writeTo(LChar*) const { ASSERT(!m_length); }
+    void writeTo(UChar* destination) const { StringImpl::copyCharacters(destination, m_characters, m_length); }
 
-    NO_RETURN_DUE_TO_CRASH void writeTo(LChar*) const
-    {
-        CRASH(); // FIXME make this a compile-time failure https://bugs.webkit.org/show_bug.cgi?id=165791
-    }
-
-    void writeTo(UChar* destination) const
+private:
+    static unsigned computeLength(const UChar* characters)
     {
-        memcpy(destination, m_characters, m_length * sizeof(UChar));
+        size_t length = 0;
+        while (characters[length])
+            ++length;
+        RELEASE_ASSERT(length <= String::MaxLength);
+        return static_cast<unsigned>(length);
     }
 
-    String toString() const { return String(m_characters, m_length); }
-
-private:
     const UChar* m_characters;
     unsigned m_length;
 };
 
-template<>
-class StringTypeAdapter<const char*, void> : public StringTypeAdapter<const LChar*, void> {
+template<> class StringTypeAdapter<const char*, void> : public StringTypeAdapter<const LChar*, void> {
 public:
     StringTypeAdapter(const char* characters)
-        : StringTypeAdapter<const LChar*, void>(reinterpret_cast<const LChar*>(characters))
+        : StringTypeAdapter<const LChar*, void> { reinterpret_cast<const LChar*>(characters) }
     {
     }
 };
 
-template<>
-class StringTypeAdapter<char*, void> : public StringTypeAdapter<const char*, void> {
+template<> class StringTypeAdapter<char*, void> : public StringTypeAdapter<const char*, void> {
 public:
     StringTypeAdapter(const char* characters)
-        : StringTypeAdapter<const char*, void>(characters)
+        : StringTypeAdapter<const char*, void> { characters }
     {
     }
 };
 
-template<>
-class StringTypeAdapter<ASCIILiteral, void> : public StringTypeAdapter<const char*, void> {
+template<> class StringTypeAdapter<ASCIILiteral, void> : public StringTypeAdapter<const char*, void> {
 public:
     StringTypeAdapter(ASCIILiteral characters)
-        : StringTypeAdapter<const char*, void>(characters)
+        : StringTypeAdapter<const char*, void> { characters }
     {
     }
 };
 
-template<>
-class StringTypeAdapter<Vector<char>, void> {
+template<> class StringTypeAdapter<Vector<char>, void> {
 public:
     StringTypeAdapter(const Vector<char>& vector)
-        : m_vector(vector)
+        : m_vector { vector }
     {
     }
 
     size_t length() const { return m_vector.size(); }
     bool is8Bit() const { return true; }
+    template<typename CharacterType> void writeTo(CharacterType* destination) const { StringImpl::copyCharacters(destination, characters(), length()); }
 
-    void writeTo(LChar* destination) const
-    {
-        StringView(reinterpret_cast<const LChar*>(m_vector.data()), m_vector.size()).getCharactersWithUpconvert(destination);
-    }
-
-    void writeTo(UChar* destination) const
+private:
+    const LChar* characters() const
     {
-        StringView(reinterpret_cast<const LChar*>(m_vector.data()), m_vector.size()).getCharactersWithUpconvert(destination);
+        return reinterpret_cast<const LChar*>(m_vector.data());
     }
 
-    String toString() const { return String(m_vector.data(), m_vector.size()); }
-
-private:
     const Vector<char>& m_vector;
 };
 
-template<>
-class StringTypeAdapter<String, void> {
+template<> class StringTypeAdapter<String, void> {
 public:
     StringTypeAdapter(const String& string)
-        : m_string(string)
+        : m_string { string }
     {
     }
 
     unsigned length() const { return m_string.length(); }
     bool is8Bit() const { return m_string.isNull() || m_string.is8Bit(); }
-
-    void writeTo(LChar* destination) const
-    {
-        StringView(m_string).getCharactersWithUpconvert(destination);
-        WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING();
-    }
-
-    void writeTo(UChar* destination) const
+    template<typename CharacterType> void writeTo(CharacterType* destination) const
     {
-        StringView(m_string).getCharactersWithUpconvert(destination);
+        StringView { m_string }.getCharactersWithUpconvert(destination);
         WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING();
     }
 
-    String toString() const { return m_string; }
-
 private:
     const String& m_string;
 };
 
-template<>
-class StringTypeAdapter<AtomicString, void> : public StringTypeAdapter<String, void> {
+template<> class StringTypeAdapter<AtomicString, void> : public StringTypeAdapter<String, void> {
 public:
     StringTypeAdapter(const AtomicString& string)
-        : StringTypeAdapter<String, void>(string.string())
+        : StringTypeAdapter<String, void> { string.string() }
     {
     }
 };
 
+template<typename UnderlyingElementType> struct PaddingSpecification {
+    LChar character;
+    unsigned length;
+    UnderlyingElementType underlyingElement;
+};
+
+template<typename UnderlyingElementType> PaddingSpecification<UnderlyingElementType> pad(char character, unsigned length, UnderlyingElementType element)
+{
+    return { static_cast<LChar>(character), length, element };
+}
+
+template<typename UnderlyingElementType> class StringTypeAdapter<PaddingSpecification<UnderlyingElementType>> {
+public:
+    StringTypeAdapter(const PaddingSpecification<UnderlyingElementType>& padding)
+        : m_padding { padding }
+        , m_underlyingAdapter { m_padding.underlyingElement }
+    {
+    }
+
+    unsigned length() const { return std::max(m_padding.length, m_underlyingAdapter.length()); }
+    bool is8Bit() const { return m_underlyingAdapter.is8Bit(); }
+    template<typename CharacterType> void writeTo(CharacterType* destination) const
+    {
+        unsigned underlyingLength = m_underlyingAdapter.length();
+        unsigned count = 0;
+        if (underlyingLength < m_padding.length) {
+            count = m_padding.length - underlyingLength;
+            for (unsigned i = 0; i < count; ++i)
+                destination[i] = m_padding.character;
+        }
+        m_underlyingAdapter.writeTo(destination + count);
+    }
+
+private:
+    const PaddingSpecification<UnderlyingElementType>& m_padding;
+    StringTypeAdapter<UnderlyingElementType> m_underlyingAdapter;
+};
+
 template<typename Adapter>
 inline bool are8Bit(Adapter adapter)
 {
@@ -314,13 +297,6 @@ String tryMakeString(StringTypes ...strings)
     return tryMakeStringFromAdapters(StringTypeAdapter<StringTypes>(strings)...);
 }
 
-// Convenience only.
-template<typename StringType>
-String makeString(StringType string)
-{
-    return String(string);
-}
-
 template<typename... StringTypes>
 String makeString(StringTypes... strings)
 {
@@ -333,6 +309,7 @@ String makeString(StringTypes... strings)
 } // namespace WTF
 
 using WTF::makeString;
+using WTF::pad;
 using WTF::tryMakeString;
 
 #include <wtf/text/StringOperators.h>
index a375ecc..6f4ef89 100644 (file)
@@ -42,7 +42,6 @@ public:
     unsigned length() const { return lengthOfNumberAsStringSigned(m_number); }
     bool is8Bit() const { return true; }
     template<typename CharacterType> void writeTo(CharacterType* destination) const { writeNumberToBufferSigned(m_number, destination); }
-    String toString() const { return String::number(m_number); }
 
 private:
     SignedInt m_number;
@@ -59,7 +58,6 @@ public:
     unsigned length() const { return lengthOfNumberAsStringUnsigned(m_number); }
     bool is8Bit() const { return true; }
     template<typename CharacterType> void writeTo(CharacterType* destination) const { writeNumberToBufferUnsigned(m_number, destination); }
-    String toString() const { return String::number(m_number); }
 
 private:
     UnsignedInt m_number;
@@ -71,13 +69,12 @@ public:
     StringTypeAdapter(FloatingPoint number)
     {
         numberToString(number, m_buffer);
-        m_length = strlen(m_buffer);
+        m_length = std::strlen(m_buffer);
     }
 
     unsigned length() const { return m_length; }
     bool is8Bit() const { return true; }
     template<typename CharacterType> void writeTo(CharacterType* destination) const { StringImpl::copyCharacters(destination, buffer(), m_length); }
-    String toString() const { return { buffer(), m_length }; }
 
 private:
     const LChar* buffer() const { return reinterpret_cast<const LChar*>(m_buffer); }
@@ -92,7 +89,7 @@ public:
     {
         FormattedNumber numberFormatter;
         numberToFixedPrecisionString(number, significantFigures, numberFormatter.m_buffer, trailingZerosTruncatingPolicy == TruncateTrailingZeros);
-        numberFormatter.m_length = strlen(numberFormatter.m_buffer);
+        numberFormatter.m_length = std::strlen(numberFormatter.m_buffer);
         return numberFormatter;
     }
 
@@ -100,7 +97,7 @@ public:
     {
         FormattedNumber numberFormatter;
         numberToFixedWidthString(number, decimalPlaces, numberFormatter.m_buffer);
-        numberFormatter.m_length = strlen(numberFormatter.m_buffer);
+        numberFormatter.m_length = std::strlen(numberFormatter.m_buffer);
         return numberFormatter;
     }
 
@@ -112,8 +109,7 @@ private:
     unsigned m_length;
 };
 
-template<>
-class StringTypeAdapter<FormattedNumber> {
+template<> class StringTypeAdapter<FormattedNumber> {
 public:
     StringTypeAdapter(const FormattedNumber& number)
         : m_number { number }
@@ -123,7 +119,6 @@ public:
     unsigned length() const { return m_number.length(); }
     bool is8Bit() const { return true; }
     template<typename CharacterType> void writeTo(CharacterType* destination) const { StringImpl::copyCharacters(destination, m_number.buffer(), m_number.length()); }
-    String toString() const { return { m_number.buffer(), m_number.length() }; }
 
 private:
     const FormattedNumber& m_number;
index 12e0826..743ee9f 100644 (file)
 
 namespace WTF {
 
-template<typename StringType1, typename StringType2>
-class StringAppend {
+template<typename StringType1, typename StringType2> class StringAppend {
 public:
     StringAppend(StringType1 string1, StringType2 string2)
-        : m_string1(string1)
-        , m_string2(string2)
+        : m_string1 { string1 }
+        , m_string2 { string2 }
     {
     }
 
@@ -85,18 +84,13 @@ template<typename StringType1, typename StringType2>
 class StringTypeAdapter<StringAppend<StringType1, StringType2>> {
 public:
     StringTypeAdapter<StringAppend<StringType1, StringType2>>(StringAppend<StringType1, StringType2>& buffer)
-        : m_buffer(buffer)
+        : m_buffer { buffer }
     {
     }
 
-    unsigned length() { return m_buffer.length(); }
-
-    bool is8Bit() { return m_buffer.is8Bit(); }
-
-    void writeTo(LChar* destination) { m_buffer.writeTo(destination); }
-    void writeTo(UChar* destination) { m_buffer.writeTo(destination); }
-
-    String toString() const { return m_buffer; }
+    unsigned length() const { return m_buffer.length(); }
+    bool is8Bit() const { return m_buffer.is8Bit(); }
+    template<typename CharacterType> void writeTo(CharacterType* destination) const { m_buffer.writeTo(destination); }
 
 private:
     StringAppend<StringType1, StringType2>& m_buffer;
index 701c55b..b3df3ae 100644 (file)
@@ -565,26 +565,23 @@ inline size_t StringView::reverseFind(UChar character, unsigned index) const
 }
 
 #if !CHECK_STRINGVIEW_LIFETIME
+
 inline void StringView::invalidate(const StringImpl&)
 {
 }
-#endif
 
-template<typename StringType, typename> class StringTypeAdapter;
+#endif
 
 template<> class StringTypeAdapter<StringView, void> {
 public:
     StringTypeAdapter(StringView string)
-        : m_string(string)
+        : m_string { string }
     {
     }
 
     unsigned length() { return m_string.length(); }
     bool is8Bit() { return m_string.is8Bit(); }
-    void writeTo(LChar* destination) { m_string.getCharactersWithUpconvert(destination); }
-    void writeTo(UChar* destination) { m_string.getCharactersWithUpconvert(destination); }
-
-    String toString() const { return m_string.toString(); }
+    template<typename CharacterType> void writeTo(CharacterType* destination) { m_string.getCharactersWithUpconvert(destination); }
 
 private:
     StringView m_string;
index 3f9b038..b2c0616 100644 (file)
@@ -449,61 +449,6 @@ Vector<UChar> String::charactersWithNullTermination() const
     return result;
 }
 
-WTF_ATTRIBUTE_PRINTF(1, 0) static String createWithFormatAndArguments(const char *format, va_list args)
-{
-    va_list argsCopy;
-    va_copy(argsCopy, args);
-
-    ALLOW_NONLITERAL_FORMAT_BEGIN
-
-#if USE(CF) && !OS(WINDOWS)
-    if (strstr(format, "%@")) {
-        auto cfFormat = adoptCF(CFStringCreateWithCString(kCFAllocatorDefault, format, kCFStringEncodingUTF8));
-        auto result = adoptCF(CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, nullptr, cfFormat.get(), args));
-        va_end(argsCopy);
-        return result.get();
-    }
-#endif
-
-    // Do the format once to get the length.
-#if COMPILER(MSVC)
-    int result = _vscprintf(format, args);
-#else
-    char ch;
-    int result = vsnprintf(&ch, 1, format, args);
-#endif
-
-    if (!result) {
-        va_end(argsCopy);
-        return emptyString();
-    }
-    if (result < 0) {
-        va_end(argsCopy);
-        return String();
-    }
-
-    Vector<char, 256> buffer;
-    unsigned len = result;
-    buffer.grow(len + 1);
-
-    // Now do the formatting again, guaranteed to fit.
-    vsnprintf(buffer.data(), buffer.size(), format, argsCopy);
-    va_end(argsCopy);
-
-    ALLOW_NONLITERAL_FORMAT_END
-
-    return StringImpl::create(reinterpret_cast<const LChar*>(buffer.data()), len);
-}
-
-String String::format(const char *format, ...)
-{
-    va_list args;
-    va_start(args, format);
-    String result = createWithFormatAndArguments(format, args);
-    va_end(args);
-    return result;
-}
-
 String String::number(int number)
 {
     return numberToStringSigned<String>(number);
index 7359174..14163cc 100644 (file)
@@ -261,8 +261,6 @@ public:
     // Use convertToASCIILowercase instead if ASCII case insensitive comparison is desired.
     WTF_EXPORT_PRIVATE String foldCase() const;
 
-    WTF_EXPORT_PRIVATE static String format(const char *, ...) WTF_ATTRIBUTE_PRINTF(1, 2);
-
     // Returns an uninitialized string. The characters needs to be written
     // into the buffer returned in data before the returned string is used.
     static String createUninitialized(unsigned length, UChar*& data) { return StringImpl::createUninitialized(length, data); }
index 81f6725..44c14cb 100644 (file)
@@ -1,3 +1,42 @@
+2019-03-01  Darin Adler  <darin@apple.com>
+
+        Finish removing String::format
+        https://bugs.webkit.org/show_bug.cgi?id=194893
+
+        Reviewed by Daniel Bates.
+
+        * dom/Document.cpp:
+        (WebCore::Document::lastModified const): Use makeString and pad.
+        * html/FTPDirectoryDocument.cpp:
+        (WebCore::processFileDateString): Ditto.
+
+        * mathml/MathMLElement.cpp:
+        (WebCore::convertToPercentageIfNeeded): Use makeString and FormattedNumber.
+
+        * page/cocoa/ResourceUsageOverlayCocoa.mm:
+        (WebCore::ResourceUsageOverlay::platformDraw): Use makeString and pad.
+
+        * page/linux/ResourceUsageOverlayLinux.cpp:
+        (WebCore::cpuUsageString): Use makeString, FormattedNumber, and pad.
+        (WebCore::gcTimerString): Use String::number.
+
+        * platform/DateComponents.cpp:
+        (WebCore::DateComponents::toStringForTime const): Use makeString and pad.
+        (WebCore::DateComponents::toString const): Ditto.
+
+        * platform/LocalizedStrings.cpp: Removed comment that mentioned String::format,
+        and that was also inaccurate.
+
+        * platform/audio/HRTFElevation.cpp:
+        (WebCore::HRTFElevation::calculateKernelsForAzimuthElevation):
+        Use makeString and pad.
+        * platform/mock/MockRealtimeVideoSource.cpp:
+        (WebCore::MockRealtimeVideoSource::drawText): Ditto.
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::logLayerInfo): Ditto.
+        * rendering/RenderTheme.cpp:
+        (WebCore::RenderTheme::formatMediaControlsTime const): Ditto.
+
 2019-03-01  Chris Dumez  <cdumez@apple.com>
 
         Do not attempt to set WAL Journal mode on a readonly SQLite database
index c60d5f6..ded0f9c 100644 (file)
@@ -4985,15 +4985,19 @@ String Document::lastModified() const
     else if (loader())
         dateTime = loader()->response().lastModified();
 
-    // FIXME: If this document came from the file system, the HTML5
-    // specification tells us to read the last modification date from the file
-    // system.
+    // FIXME: If this document came from the file system, the HTML specification tells
+    // us to read the last modification date from the file system.
     if (!dateTime)
         dateTime = WallTime::now();
 
     auto ctime = dateTime.value().secondsSinceEpoch().secondsAs<time_t>();
     auto localDateTime = std::localtime(&ctime);
-    return String::format("%02d/%02d/%04d %02d:%02d:%02d", localDateTime->tm_mon + 1, localDateTime->tm_mday, 1900 + localDateTime->tm_year, localDateTime->tm_hour, localDateTime->tm_min, localDateTime->tm_sec);
+    return makeString(pad('0', 2, localDateTime->tm_mon + 1), '/',
+        pad('0', 2, localDateTime->tm_mday), '/',
+        pad('0', 4, 1900 + localDateTime->tm_year), ' ',
+        pad('0', 2, localDateTime->tm_hour), ':',
+        pad('0', 2, localDateTime->tm_min), ':',
+        pad('0', 2, localDateTime->tm_sec));
 }
 
 void Document::setCookieURL(const URL& url)
index 6a89c79..36166f1 100644 (file)
@@ -210,12 +210,12 @@ static String processFileDateString(const FTPTime& fileTime)
         if (hour < 12) {
             if (hour == 0)
                 hour = 12;
-            timeOfDay = String::format(", %i:%02i AM", hour, fileTime.tm_min);
+            timeOfDay = makeString(", ", hour, ':', pad('0', 2, fileTime.tm_min), " AM");
         } else {
             hour = hour - 12;
             if (hour == 0)
                 hour = 12;
-            timeOfDay = String::format(", %i:%02i PM", hour, fileTime.tm_min);
+            timeOfDay = makeString(", ", hour, ':', pad('0', 2, fileTime.tm_min), " PM");
         }
     }
 
index 96d570a..99b16bc 100644 (file)
@@ -39,6 +39,7 @@
 #include "MouseEvent.h"
 #include "RenderTableCell.h"
 #include <wtf/IsoMallocInlines.h>
+#include <wtf/text/StringConcatenateNumbers.h>
 
 namespace WebCore {
 
@@ -99,11 +100,13 @@ bool MathMLElement::isPresentationAttribute(const QualifiedName& name) const
 
 static String convertToPercentageIfNeeded(const AtomicString& value)
 {
+    // FIXME: Might be better to use double than float.
+    // FIXME: Might be better to use "shortest" numeric formatting instead of fixed width.
     bool ok = false;
     float unitlessValue = value.toFloat(&ok);
-    if (ok)
-        return String::format("%.3f%%", unitlessValue * 100.0);
-    return value;
+    if (!ok)
+        return value;
+    return makeString(FormattedNumber::fixedWidth(unitlessValue * 100, 3), '%');
 }
 
 void MathMLElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStyleProperties& style)
@@ -116,7 +119,7 @@ void MathMLElement::collectStyleForPresentationAttribute(const QualifiedName& na
             addPropertyToPresentationAttributeStyle(style, CSSPropertyFontSize, convertToPercentageIfNeeded(value));
     } else if (name == mathcolorAttr)
         addPropertyToPresentationAttributeStyle(style, CSSPropertyColor, value);
-    // FIXME: deprecated attributes that should loose in a conflict with a non deprecated attribute
+    // FIXME: The following are deprecated attributes that should lose if there is a conflict with a non-deprecated attribute.
     else if (name == fontsizeAttr)
         addPropertyToPresentationAttributeStyle(style, CSSPropertyFontSize, value);
     else if (name == backgroundAttr)
@@ -134,8 +137,7 @@ void MathMLElement::collectStyleForPresentationAttribute(const QualifiedName& na
             addPropertyToPresentationAttributeStyle(style, CSSPropertyDirection, value);
     }  else {
         ASSERT(!isPresentationAttribute(name));
-        StyledElement::collectStyleForPresentationAttribute(name, value
-        , style);
+        StyledElement::collectStyleForPresentationAttribute(name, value, style);
     }
 }
 
index 198b298..56b65d6 100644 (file)
@@ -468,7 +468,7 @@ void ResourceUsageOverlay::platformDraw(CGContextRef context)
         size_t reclaimable = category.reclaimableSize.last();
         size_t external = category.externalSize.last();
         
-        String label = String::format("% 11s: %s", category.name.ascii().data(), formatByteNumber(dirty).ascii().data());
+        String label = makeString(pad(' ', 11, category.name), ": ", formatByteNumber(dirty));
         if (external)
             label = label + makeString(" + ", formatByteNumber(external));
         if (reclaimable)
index e78ffaa..9571d12 100644 (file)
@@ -46,7 +46,7 @@ static String cpuUsageString(float cpuUsage)
 {
     if (cpuUsage < 0)
         return "<unknown>"_s;
-    return String::format("%.1f%%", cpuUsage);
+    return makeString(FormattedNumber::fixedWidth(cpuUsage, 1), '%');
 }
 
 static String formatByteNumber(size_t number)
@@ -64,7 +64,7 @@ static String gcTimerString(MonotonicTime timerFireDate, MonotonicTime now)
 {
     if (std::isnan(timerFireDate))
         return "[not scheduled]"_s;
-    return String::format("%g", (timerFireDate - now).seconds());
+    return String::number((timerFireDate - now).seconds());
 }
 
 static const float gFontSize = 14;
index dd5adcb..9244e3d 100644 (file)
@@ -35,7 +35,7 @@
 #include <wtf/ASCIICType.h>
 #include <wtf/DateMath.h>
 #include <wtf/MathExtras.h>
-#include <wtf/text/WTFString.h>
+#include <wtf/text/StringConcatenateNumbers.h>
 
 namespace WebCore {
 
@@ -693,11 +693,11 @@ String DateComponents::toStringForTime(SecondFormat format) const
         FALLTHROUGH; // To None.
 #endif
     case None:
-        return String::format("%02d:%02d", m_hour, m_minute);
+        return makeString(pad('0', 2, m_hour), ':', pad('0', 2, m_minute));
     case Second:
-        return String::format("%02d:%02d:%02d", m_hour, m_minute, m_second);
+        return makeString(pad('0', 2, m_hour), ':', pad('0', 2, m_minute), ':', pad('0', 2, m_second));
     case Millisecond:
-        return String::format("%02d:%02d:%02d.%03d", m_hour, m_minute, m_second, m_millisecond);
+        return makeString(pad('0', 2, m_hour), ':', pad('0', 2, m_minute), ':', pad('0', 2, m_second), '.', pad('0', 3, m_millisecond));
     }
 }
 
@@ -705,19 +705,17 @@ String DateComponents::toString(SecondFormat format) const
 {
     switch (m_type) {
     case Date:
-        return String::format("%04d-%02d-%02d", m_year, m_month + 1, m_monthDay);
+        return makeString(pad('0', 4, m_year), '-', pad('0', 2, m_month + 1), '-', pad('0', 2, m_monthDay));
     case DateTime:
-        return String::format("%04d-%02d-%02dT", m_year, m_month + 1, m_monthDay)
-            + toStringForTime(format) + "Z"_str;
+        return makeString(pad('0', 4, m_year), '-', pad('0', 2, m_month + 1), '-', pad('0', 2, m_monthDay), 'T', toStringForTime(format), 'Z');
     case DateTimeLocal:
-        return String::format("%04d-%02d-%02dT", m_year, m_month + 1, m_monthDay)
-            + toStringForTime(format);
+        return makeString(pad('0', 4, m_year), '-', pad('0', 2, m_month + 1), '-', pad('0', 2, m_monthDay), 'T', toStringForTime(format));
     case Month:
-        return String::format("%04d-%02d", m_year, m_month + 1);
+        return makeString(pad('0', 4, m_year), '-', pad('0', 2, m_month + 1));
     case Time:
         return toStringForTime(format);
     case Week:
-        return String::format("%04d-W%02d", m_year, m_week);
+        return makeString(pad('0', 4, m_year), "-W", pad('0', 2, m_week));
     case Invalid:
         break;
     }
index 1bf4cd7..80e2e40 100644 (file)
 
 namespace WebCore {
 
-// We can't use String::format for two reasons:
-//  1) It doesn't handle non-ASCII characters in the format string.
-//  2) It doesn't handle the %2$d syntax.
-// Note that because |format| is used as the second parameter to va_start, it cannot be a reference
+// Because |format| is used as the second parameter to va_start, it cannot be a reference
 // type according to section 18.7/3 of the C++ N1905 standard.
 String formatLocalizedString(String format, ...)
 {
@@ -73,10 +70,12 @@ String formatLocalizedString(String format, ...)
 }
 
 #if !USE(CF)
+
 String localizedString(const char* key)
 {
     return String::fromUTF8(key, strlen(key));
 }
+
 #endif
 
 #if ENABLE(CONTEXT_MENUS)
index 9e71ae9..c84ab97 100644 (file)
@@ -176,7 +176,7 @@ bool HRTFElevation::calculateKernelsForAzimuthElevation(int azimuth, int elevati
     AudioChannel* leftEarImpulseResponse = response->channel(AudioBus::ChannelLeft);
     AudioChannel* rightEarImpulseResponse = response->channel(AudioBus::ChannelRight);
 #else
-    String resourceName = String::format("IRC_%s_C_R0195_T%03d_P%03d", subjectName.utf8().data(), azimuth, positiveElevation);
+    String resourceName = makeString("IRC_", subjectName, "_C_R0195_T", pad('0', 3, azimuth), "_P", pad('0', 3, positiveElevation));
 
     RefPtr<AudioBus> impulseResponse(AudioBus::loadPlatformResource(resourceName.utf8().data(), sampleRate));
 
index 0b9f190..f13c5b5 100644 (file)
@@ -350,10 +350,10 @@ void MockRealtimeVideoSource::drawText(GraphicsContext& context)
     FloatPoint timeLocation(captureSize.width() * .05, captureSize.height() * .15);
     context.setFillColor(Color::white);
     context.setTextDrawingMode(TextModeFill);
-    String string = String::format("%02u:%02u:%02u.%03u", hours, minutes, seconds, milliseconds % 1000);
+    String string = makeString(pad('0', 2, hours), ':', pad('0', 2, minutes), ':', pad('0', 2, seconds), '.', pad('0', 3, milliseconds % 1000));
     context.drawText(timeFont, TextRun((StringView(string))), timeLocation);
 
-    string = String::format("%06u", m_frameNumber++);
+    string = makeString(pad('0', 6, m_frameNumber++));
     timeLocation.move(0, m_baseFontSize);
     context.drawText(timeFont, TextRun((StringView(string))), timeLocation);
 
index 121b5c0..acadc78 100644 (file)
@@ -60,6 +60,7 @@
 #include "Settings.h"
 #include "TiledBacking.h"
 #include "TransformState.h"
+#include <wtf/HexNumber.h>
 #include <wtf/MemoryPressureHandler.h>
 #include <wtf/SetForScope.h>
 #include <wtf/text/CString.h>
@@ -1323,10 +1324,8 @@ void RenderLayerCompositor::logLayerInfo(const RenderLayer& layer, const char* p
     absoluteBounds.move(layer.offsetFromAncestor(m_renderView.layer()));
     
     StringBuilder logString;
-    logString.append(String::format("%*p id %" PRIu64 " (%.3f,%.3f-%.3f,%.3f) %.2fKB", 12 + depth * 2, &layer, backing->graphicsLayer()->primaryLayerID(),
-        absoluteBounds.x().toFloat(), absoluteBounds.y().toFloat(), absoluteBounds.maxX().toFloat(), absoluteBounds.maxY().toFloat(),
-        backing->backingStoreMemoryEstimate() / 1024));
-    
+    logString.append(makeString(pad(' ', 12 + depth * 2, hex(reinterpret_cast<uintptr_t>(&layer))), " id ", backing->graphicsLayer()->primaryLayerID(), " (", FormattedNumber::fixedWidth(absoluteBounds.x().toFloat(), 3), ',', FormattedNumber::fixedWidth(absoluteBounds.y().toFloat(), 3), '-', FormattedNumber::fixedWidth(absoluteBounds.maxX().toFloat(), 3), ',', FormattedNumber::fixedWidth(absoluteBounds.maxY().toFloat(), 3), ") ", FormattedNumber::fixedWidth(backing->backingStoreMemoryEstimate() / 1024, 2), "KB"));
+
     if (!layer.renderer().style().hasAutoZIndex())
         logString.append(makeString(" z-index: ", layer.renderer().style().zIndex()));
 
index 2a45f10..585ef88 100644 (file)
@@ -46,6 +46,7 @@
 #include "TextControlInnerElements.h"
 #include <wtf/FileSystem.h>
 #include <wtf/NeverDestroyed.h>
+#include <wtf/text/StringConcatenateNumbers.h>
 
 #if ENABLE(METER_ELEMENT)
 #include "HTMLMeterElement.h"
@@ -568,18 +569,14 @@ String RenderTheme::formatMediaControlsTime(float time) const
 {
     if (!std::isfinite(time))
         time = 0;
-    int seconds = (int)fabsf(time);
+    // FIXME: Seems like it would be better to use std::lround here.
+    int seconds = static_cast<int>(std::abs(time));
     int hours = seconds / (60 * 60);
     int minutes = (seconds / 60) % 60;
     seconds %= 60;
-    if (hours) {
-        if (hours > 9)
-            return String::format("%s%02d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
-
-        return String::format("%s%01d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
-    }
-
-    return String::format("%s%02d:%02d", (time < 0 ? "-" : ""), minutes, seconds);
+    if (hours)
+        return makeString((time < 0 ? "-" : ""), hours, ':', pad('0', 2, minutes), ':', pad('0', 2, seconds));
+    return makeString((time < 0 ? "-" : ""), pad('0', 2, minutes), ':', pad('0', 2, seconds));
 }
 
 String RenderTheme::formatMediaControlsCurrentTime(float currentTime, float /*duration*/) const
index f426cee..a03a9c8 100644 (file)
@@ -1,3 +1,14 @@
+2019-03-01  Darin Adler  <darin@apple.com>
+
+        Finish removing String::format
+        https://bugs.webkit.org/show_bug.cgi?id=194893
+
+        Reviewed by Daniel Bates.
+
+        * UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm:
+        (WebKit::LocalAuthenticator::getAssertion): Use makeString, attempting to fix
+        a problem where we passed an NSData * to format with a "%s"."
+
 2019-03-01  Chris Dumez  <cdumez@apple.com>
 
         Unreviewed Windows build fix after r242302.
index 0433c99..4e3d114 100644 (file)
@@ -400,8 +400,10 @@ void LocalAuthenticator::getAssertion()
 
         weakThis->continueGetAssertionAfterUserConsented(consent, context, credentialId, userhandle);
     };
+    NSData *idData = selectedCredentialAttributes[(id)kSecAttrApplicationTag];
+    StringView idStringView { static_cast<const LChar*>([idData bytes]), static_cast<unsigned>([idData length]) };
     m_connection->getUserConsent(
-        String::format("Log into %s with %s.", requestData().requestOptions.rpId.utf8().data(), selectedCredentialAttributes[(id)kSecAttrApplicationTag]),
+        makeString("Log into ", requestData().requestOptions.rpId, " with ", idStringView, '.'),
         (__bridge SecAccessControlRef)selectedCredentialAttributes[(id)kSecAttrAccessControl],
         WTFMove(callback));
 #endif // PLATFORM(IOS_FAMILY)
index d4a781c..26e1eaa 100644 (file)
@@ -1,3 +1,13 @@
+2019-02-20  Darin Adler  <darin@apple.com>
+
+        Finish removing String::format
+        https://bugs.webkit.org/show_bug.cgi?id=194893
+
+        Reviewed by Daniel Bates.
+
+        * FullscreenVideoController.cpp:
+        (timeToString): Use makeString and pad.
+
 2019-02-27  Simon Fraser  <simon.fraser@apple.com>
 
         Roll out r242014; it caused crashes in compositing logging (webkit.org/b/195141)
index ca50200..646e6ae 100644 (file)
@@ -41,6 +41,7 @@
 #include <WebCore/TextRun.h>
 #include <windowsx.h>
 #include <wtf/StdLibExtras.h>
+#include <wtf/text/StringConcatenateNumbers.h>
 
 #if USE(CA)
 #include <WebCore/PlatformCALayerClient.h>
@@ -470,14 +471,9 @@ static String timeToString(float time)
     int hours = seconds / (60 * 60);
     int minutes = (seconds / 60) % 60;
     seconds %= 60;
-
-    if (hours) {
-        if (hours > 9)
-            return String::format("%s%02d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
-        return String::format("%s%01d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
-    }
-
-    return String::format("%s%02d:%02d", (time < 0 ? "-" : ""), minutes, seconds);
+    if (hours)
+        return makeString((time < 0 ? "-" : ""), hours, ':', pad('0', 2, minutes), ':', pad('0', 2, seconds));
+    return makeString((time < 0 ? "-" : ""), pad('0', 2, minutes), ':', pad('0', 2, seconds));
 }
 
 void FullscreenVideoController::draw()
index 5b59fb4..4202322 100644 (file)
@@ -1,3 +1,12 @@
+2019-03-01  Darin Adler  <darin@apple.com>
+
+        Finish removing String::format
+        https://bugs.webkit.org/show_bug.cgi?id=194893
+
+        Reviewed by Daniel Bates.
+'
+        * Tools/TestWebKitAPI/Tests/WTF/StringConcatenate.cpp: Add tests for pad().
+
 2019-03-01  Alex Christensen  <achristensen@webkit.org>
 
         Add setters on WKWebsiteDataStore for sourceApplicationBundleIdentifier and sourceApplicationSecondaryIdentifier
index 1d2ee17..4b57c51 100644 (file)
 #include "config.h"
 
 #include "WTFStringUtilities.h"
-#include <wtf/text/StringConcatenate.h>
-#include <wtf/text/StringConcatenateNumbers.h>
 #include <cstddef>
 #include <cstdint>
 #include <unicode/uvernum.h>
+#include <wtf/HexNumber.h>
+#include <wtf/text/StringConcatenate.h>
+#include <wtf/text/StringConcatenateNumbers.h>
 
 namespace TestWebKitAPI {
 
@@ -156,4 +157,16 @@ TEST(WTF, StringConcatenate_FormattedDoubleFixedWidth)
     EXPECT_STREQ("hello 0.000 world", makeString("hello ", FormattedNumber::fixedWidth(0.0, 3) , " world").utf8().data());
 }
 
+TEST(WTF, StringConcatenate_Pad)
+{
+    EXPECT_STREQ("", makeString(pad('x', 0, "")).utf8().data());
+    EXPECT_STREQ("x", makeString(pad('x', 1, "")).utf8().data());
+    EXPECT_STREQ("y", makeString(pad('x', 1, "y")).utf8().data());
+    EXPECT_STREQ("xy", makeString(pad('x', 2, "y")).utf8().data());
+
+    EXPECT_STREQ("xxxxxxxxxxxxxxx1E240", makeString(pad('x', 20, hex(123456))).utf8().data());
+    EXPECT_STREQ("xxxxxxxxxxxxxxx1E2400.000", makeString(pad('x', 20, hex(123456)), FormattedNumber::fixedWidth(0.f, 3)).utf8().data());
+    EXPECT_STREQ(" B32AF0071F9 id 1231232312313231 (0.000,0.000-0.000,0.000) 0.00KB", makeString(pad(' ', 12, hex(12312312312313)), " id ", 1231232312313231, " (", FormattedNumber::fixedWidth(0.f, 3), ',', FormattedNumber::fixedWidth(0.f, 3), '-', FormattedNumber::fixedWidth(0.f, 3), ',', FormattedNumber::fixedWidth(0.f, 3), ") ", FormattedNumber::fixedWidth(0.f, 2), "KB").utf8().data());
+}
+
 }