diff --git a/Source/JavaScriptCore/API/JSScript.mm b/Source/JavaScriptCore/API/JSScript.mm index 03f595b3ed4ef..fa17449412aa5 100644 --- a/Source/JavaScriptCore/API/JSScript.mm +++ b/Source/JavaScriptCore/API/JSScript.mm @@ -146,7 +146,7 @@ + (instancetype)scriptOfType:(JSScriptType)type memoryMappedFromASCIIFile:(NSURL auto result = adoptNS([[JSScript alloc] init]); result->m_virtualMachine = vm; result->m_type = type; - result->m_source = String(StringImpl::createWithoutCopying(fileData.span())); + result->m_source = StringImpl::createWithoutCopying(byteCast(fileData.span())); result->m_mappedSource = WTFMove(fileData); result->m_sourceURL = sourceURL; result->m_cachePath = cachePath; diff --git a/Source/JavaScriptCore/API/JSStringRef.cpp b/Source/JavaScriptCore/API/JSStringRef.cpp index 7cbe58ff2157c..1640ffae6efca 100644 --- a/Source/JavaScriptCore/API/JSStringRef.cpp +++ b/Source/JavaScriptCore/API/JSStringRef.cpp @@ -38,19 +38,19 @@ WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN JSStringRef JSStringCreateWithCharacters(const JSChar* chars, size_t numChars) { JSC::initialize(); - return &OpaqueJSString::create({ reinterpret_cast(chars), numChars }).leakRef(); + return &OpaqueJSString::create({ reinterpret_cast(chars), numChars }).leakRef(); } JSStringRef JSStringCreateWithUTF8CString(const char* string) { JSC::initialize(); if (string) { - auto stringSpan = span8(string); - Vector buffer(stringSpan.size()); + auto stringSpan = byteCast(unsafeSpan(string)); + Vector buffer(stringSpan.size()); auto result = WTF::Unicode::convert(spanReinterpretCast(stringSpan), buffer.mutableSpan()); if (result.code == WTF::Unicode::ConversionResultCode::Success) { if (result.isAllASCII) - return &OpaqueJSString::create(stringSpan).leakRef(); + return &OpaqueJSString::create(byteCast(stringSpan)).leakRef(); return &OpaqueJSString::create(result.buffer).leakRef(); } } @@ -61,7 +61,7 @@ JSStringRef JSStringCreateWithUTF8CString(const char* string) JSStringRef JSStringCreateWithCharactersNoCopy(const JSChar* chars, size_t numChars) { JSC::initialize(); - return OpaqueJSString::tryCreate(StringImpl::createWithoutCopying({ reinterpret_cast(chars), numChars })).leakRef(); + return OpaqueJSString::tryCreate(StringImpl::createWithoutCopying({ reinterpret_cast(chars), numChars })).leakRef(); } JSStringRef JSStringRetain(JSStringRef string) diff --git a/Source/JavaScriptCore/API/JSStringRefCF.cpp b/Source/JavaScriptCore/API/JSStringRefCF.cpp index 58481e0eae917..e16b3e843d7a2 100644 --- a/Source/JavaScriptCore/API/JSStringRefCF.cpp +++ b/Source/JavaScriptCore/API/JSStringRefCF.cpp @@ -45,16 +45,16 @@ JSStringRef JSStringCreateWithCFString(CFStringRef string) if (!length) return &OpaqueJSString::create(""_span8).leakRef(); - Vector lcharBuffer(length); + Vector lcharBuffer(length); CFIndex usedBufferLength; - CFIndex convertedSize = CFStringGetBytes(string, CFRangeMake(0, length), kCFStringEncodingISOLatin1, 0, false, lcharBuffer.data(), length, &usedBufferLength); + CFIndex convertedSize = CFStringGetBytes(string, CFRangeMake(0, length), kCFStringEncodingISOLatin1, 0, false, byteCast(lcharBuffer.data()), length, &usedBufferLength); if (static_cast(convertedSize) == length && static_cast(usedBufferLength) == length) return &OpaqueJSString::create(lcharBuffer.span()).leakRef(); Vector buffer(length); CFStringGetCharacters(string, CFRangeMake(0, length), buffer.data()); - static_assert(sizeof(UniChar) == sizeof(UChar), "UniChar and UChar must be same size"); - return &OpaqueJSString::create({ reinterpret_cast(buffer.data()), length }).leakRef(); + static_assert(sizeof(UniChar) == sizeof(char16_t), "UniChar and char16_t must be same size"); + return &OpaqueJSString::create({ reinterpret_cast(buffer.data()), length }).leakRef(); } CFStringRef JSStringCopyCFString(CFAllocatorRef allocator, JSStringRef string) @@ -64,7 +64,7 @@ CFStringRef JSStringCopyCFString(CFAllocatorRef allocator, JSStringRef string) if (string->is8Bit()) { auto characters = string->span8(); - return CFStringCreateWithBytes(allocator, characters.data(), characters.size(), kCFStringEncodingISOLatin1, false); + return CFStringCreateWithBytes(allocator, byteCast(characters.data()), characters.size(), kCFStringEncodingISOLatin1, false); } auto characters = string->span16(); return CFStringCreateWithCharacters(allocator, reinterpret_cast(characters.data()), characters.size()); diff --git a/Source/JavaScriptCore/API/JSValue.mm b/Source/JavaScriptCore/API/JSValue.mm index ecd7bf0e53868..d8f7ec1b58942 100644 --- a/Source/JavaScriptCore/API/JSValue.mm +++ b/Source/JavaScriptCore/API/JSValue.mm @@ -1281,8 +1281,8 @@ - (JSValue *)initWithValue:(JSValueRef)value inContext:(JSContext *)context if (strcmp(idType, "@") != 0) return; { - auto type = adoptSystem(method_copyArgumentType(method, 2)); - structHandlers->add(StringImpl::createFromCString(type.get()), (StructTagHandler) { selector, 0 }); + auto type = adoptSystem(method_copyArgumentType(method, 2)); + structHandlers->add(byteCast(unsafeSpan(type.get()), (StructTagHandler) { selector, 0 }); } }); diff --git a/Source/JavaScriptCore/API/JSValueRef.cpp b/Source/JavaScriptCore/API/JSValueRef.cpp index b68dfcfc02c8d..fae8e64d71e88 100644 --- a/Source/JavaScriptCore/API/JSValueRef.cpp +++ b/Source/JavaScriptCore/API/JSValueRef.cpp @@ -697,10 +697,10 @@ JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string) JSLockHolder locker(globalObject); String str = string->string(); if (str.is8Bit()) { - LiteralParser parser(globalObject, str.span8(), StrictJSON); + LiteralParser parser(globalObject, str.span8(), StrictJSON); return toRef(globalObject, parser.tryLiteralParse()); } - LiteralParser parser(globalObject, str.span16(), StrictJSON); + LiteralParser parser(globalObject, str.span16(), StrictJSON); return toRef(globalObject, parser.tryLiteralParse()); } diff --git a/Source/JavaScriptCore/API/OpaqueJSString.cpp b/Source/JavaScriptCore/API/OpaqueJSString.cpp index 4e724eb6e729b..1d99da4ed35bd 100644 --- a/Source/JavaScriptCore/API/OpaqueJSString.cpp +++ b/Source/JavaScriptCore/API/OpaqueJSString.cpp @@ -52,7 +52,7 @@ RefPtr OpaqueJSString::tryCreate(String&& string) OpaqueJSString::~OpaqueJSString() { // m_characters is put in a local here to avoid an extra atomic load. - UChar* characters = m_characters; + char16_t* characters = m_characters; if (!characters) return; @@ -79,17 +79,17 @@ Identifier OpaqueJSString::identifier(VM* vm) const return Identifier::fromString(*vm, m_string.span16()); } -const UChar* OpaqueJSString::characters() +const char16_t* OpaqueJSString::characters() { // m_characters is put in a local here to avoid an extra atomic load. - UChar* characters = m_characters; + char16_t* characters = m_characters; if (characters) return characters; if (m_string.isNull()) return nullptr; - auto newCharacters = MallocSpan::malloc(m_string.length() * sizeof(UChar)); + auto newCharacters = MallocSpan::malloc(m_string.length() * sizeof(char16_t)); StringView { m_string }.getCharacters(newCharacters.mutableSpan()); if (!m_characters.compare_exchange_strong(characters, newCharacters.mutableSpan().data())) diff --git a/Source/JavaScriptCore/API/OpaqueJSString.h b/Source/JavaScriptCore/API/OpaqueJSString.h index d0c1e8334469a..b6c43f359340e 100644 --- a/Source/JavaScriptCore/API/OpaqueJSString.h +++ b/Source/JavaScriptCore/API/OpaqueJSString.h @@ -40,12 +40,12 @@ struct OpaqueJSString : public ThreadSafeRefCounted { return adoptRef(*new OpaqueJSString); } - static Ref create(std::span characters) + static Ref create(std::span characters) { return adoptRef(*new OpaqueJSString(characters)); } - static Ref create(std::span characters) + static Ref create(std::span characters) { return adoptRef(*new OpaqueJSString(characters)); } @@ -56,11 +56,11 @@ struct OpaqueJSString : public ThreadSafeRefCounted { JS_EXPORT_PRIVATE ~OpaqueJSString(); bool is8Bit() { return m_string.is8Bit(); } - std::span span8() { return m_string.span8(); } - std::span span16() { return m_string.span16(); } + std::span span8() LIFETIME_BOUND { return m_string.span8(); } + std::span span16() LIFETIME_BOUND { return m_string.span16(); } unsigned length() { return m_string.length(); } - const UChar* characters(); + const char16_t* characters() LIFETIME_BOUND; JS_EXPORT_PRIVATE String string() const; JSC::Identifier identifier(JSC::VM*) const; @@ -77,30 +77,30 @@ struct OpaqueJSString : public ThreadSafeRefCounted { OpaqueJSString(const String& string) : m_string(string.isolatedCopy()) - , m_characters(m_string.impl() && m_string.is8Bit() ? nullptr : const_cast(m_string.span16().data())) + , m_characters(m_string.impl() && m_string.is8Bit() ? nullptr : const_cast(m_string.span16().data())) { } explicit OpaqueJSString(String&& string) : m_string(WTFMove(string)) - , m_characters(m_string.impl() && m_string.is8Bit() ? nullptr : const_cast(m_string.span16().data())) + , m_characters(m_string.impl() && m_string.is8Bit() ? nullptr : const_cast(m_string.span16().data())) { } - OpaqueJSString(std::span characters) + OpaqueJSString(std::span characters) : m_string(characters) , m_characters(nullptr) { } - OpaqueJSString(std::span characters) + OpaqueJSString(std::span characters) : m_string(characters) - , m_characters(m_string.impl() && m_string.is8Bit() ? nullptr : const_cast(m_string.span16().data())) + , m_characters(m_string.impl() && m_string.is8Bit() ? nullptr : const_cast(m_string.span16().data())) { } String m_string; // This will be initialized on demand when characters() is called if the string needs up-conversion. - std::atomic m_characters; + std::atomic m_characters; }; diff --git a/Source/JavaScriptCore/API/glib/JSCCallbackFunction.cpp b/Source/JavaScriptCore/API/glib/JSCCallbackFunction.cpp index eaf0aca348534..d6446b82f0de5 100644 --- a/Source/JavaScriptCore/API/glib/JSCCallbackFunction.cpp +++ b/Source/JavaScriptCore/API/glib/JSCCallbackFunction.cpp @@ -228,7 +228,7 @@ JSObjectRef JSCCallbackFunction::construct(JSContextRef callerContext, size_t ar *exception = toRef(JSC::createTypeError(toJS(jsContext), "constructor returned null"_s)); break; default: - *exception = toRef(JSC::createTypeError(toJS(jsContext), makeString("invalid type "_s, span(g_type_name(G_VALUE_TYPE(&returnValue))), " returned by constructor"_s))); + *exception = toRef(JSC::createTypeError(toJS(jsContext), makeString("invalid type "_s, unsafeSpan(g_type_name(G_VALUE_TYPE(&returnValue))), " returned by constructor"_s))); break; } g_value_unset(&returnValue); diff --git a/Source/JavaScriptCore/API/glib/JSCContext.cpp b/Source/JavaScriptCore/API/glib/JSCContext.cpp index 31d780d52b1f1..005efdc6c6fcd 100644 --- a/Source/JavaScriptCore/API/glib/JSCContext.cpp +++ b/Source/JavaScriptCore/API/glib/JSCContext.cpp @@ -467,7 +467,7 @@ JSValueRef jscContextGValueToJSValue(JSCContext* context, const GValue* value, J break; } - *exception = toRef(JSC::createTypeError(globalObject, makeString("unsupported type "_s, span(g_type_name(G_VALUE_TYPE(value)))))); + *exception = toRef(JSC::createTypeError(globalObject, makeString("unsupported type "_s, unsafeSpan(g_type_name(G_VALUE_TYPE(value)))))); return JSValueMakeUndefined(priv->jsContext.get()); } @@ -587,7 +587,7 @@ void jscContextJSValueToGValue(JSCContext* context, JSValueRef jsValue, GType ty case G_TYPE_INTERFACE: case G_TYPE_VARIANT: default: - *exception = toRef(JSC::createTypeError(globalObject, makeString("unsupported type "_s, span(g_type_name(G_VALUE_TYPE(value)))))); + *exception = toRef(JSC::createTypeError(globalObject, makeString("unsupported type "_s, unsafeSpan(g_type_name(G_VALUE_TYPE(value)))))); break; } } diff --git a/Source/JavaScriptCore/API/glib/JSCValue.cpp b/Source/JavaScriptCore/API/glib/JSCValue.cpp index 48e5ad211e623..885eae6409c73 100644 --- a/Source/JavaScriptCore/API/glib/JSCValue.cpp +++ b/Source/JavaScriptCore/API/glib/JSCValue.cpp @@ -503,7 +503,7 @@ JSCValue* jsc_value_new_array(JSCContext* context, GType firstItemType, ...) G_VALUE_COLLECT_INIT(&item, itemType, args, G_VALUE_NOCOPY_CONTENTS, &error.outPtr()); WTF_ALLOW_UNSAFE_BUFFER_USAGE_END if (error) { - exception = toRef(JSC::createTypeError(globalObject, makeString("failed to collect array item: "_s, span(error.get())))); + exception = toRef(JSC::createTypeError(globalObject, makeString("failed to collect array item: "_s, unsafeSpan(error.get())))); jscContextHandleExceptionIfNeeded(context, exception); jsArray = nullptr; break; @@ -905,7 +905,7 @@ static GRefPtr jscValueCallFunction(JSCValue* value, JSObjectRef funct G_VALUE_COLLECT_INIT(¶meter, parameterType, args, G_VALUE_NOCOPY_CONTENTS, &error.outPtr()); WTF_ALLOW_UNSAFE_BUFFER_USAGE_END if (error) { - exception = toRef(JSC::createTypeError(globalObject, makeString("failed to collect function paramater: "_s, span(error.get())))); + exception = toRef(JSC::createTypeError(globalObject, makeString("failed to collect function paramater: "_s, unsafeSpan(error.get())))); jscContextHandleExceptionIfNeeded(priv->context.get(), exception); return adoptGRef(jsc_value_new_undefined(priv->context.get())); } @@ -2093,12 +2093,12 @@ JSCValue* jsc_value_new_from_json(JSCContext* context, const char* json) JSC::JSValue jsValue; String jsonString = String::fromUTF8(json); if (jsonString.is8Bit()) { - JSC::LiteralParser jsonParser(globalObject, jsonString.span8(), JSC::StrictJSON); + JSC::LiteralParser jsonParser(globalObject, jsonString.span8(), JSC::StrictJSON); jsValue = jsonParser.tryLiteralParse(); if (!jsValue) exception = toRef(JSC::createSyntaxError(globalObject, jsonParser.getErrorMessage())); } else { - JSC::LiteralParser jsonParser(globalObject, jsonString.span16(), JSC::StrictJSON); + JSC::LiteralParser jsonParser(globalObject, jsonString.span16(), JSC::StrictJSON); jsValue = jsonParser.tryLiteralParse(); if (!jsValue) exception = toRef(JSC::createSyntaxError(globalObject, jsonParser.getErrorMessage())); diff --git a/Source/JavaScriptCore/API/tests/JSONParseTest.cpp b/Source/JavaScriptCore/API/tests/JSONParseTest.cpp index 447c259ec0b4d..ddcd54ef021eb 100644 --- a/Source/JavaScriptCore/API/tests/JSONParseTest.cpp +++ b/Source/JavaScriptCore/API/tests/JSONParseTest.cpp @@ -48,7 +48,7 @@ int testJSONParse() JSValue v0 = JSONParse(globalObject, ""_s); JSValue v1 = JSONParse(globalObject, "#$%^"_s); JSValue v2 = JSONParse(globalObject, String()); - UChar emptyUCharArray[1] = { '\0' }; + char16_t emptyUCharArray[1] = { '\0' }; unsigned zeroLength = 0; JSValue v3 = JSONParse(globalObject, String({ emptyUCharArray, zeroLength })); JSValue v4; diff --git a/Source/JavaScriptCore/KeywordLookupGenerator.py b/Source/JavaScriptCore/KeywordLookupGenerator.py index b572954692058..af7d34070c361 100644 --- a/Source/JavaScriptCore/KeywordLookupGenerator.py +++ b/Source/JavaScriptCore/KeywordLookupGenerator.py @@ -185,27 +185,27 @@ def printAsC(self): print("") print("namespace JSC {") print("") - print("static ALWAYS_INLINE bool cannotBeIdentPartOrEscapeStart(LChar);") - print("static ALWAYS_INLINE bool cannotBeIdentPartOrEscapeStart(UChar);") + print("static ALWAYS_INLINE bool cannotBeIdentPartOrEscapeStart(Latin1Character);") + print("static ALWAYS_INLINE bool cannotBeIdentPartOrEscapeStart(char16_t);") # max length + 1 so we don't need to do any bounds checking at all print("static constexpr int maxTokenLength = %d;" % (self.maxLength() + 1)) print("") print("template <>") - print("template ALWAYS_INLINE JSTokenType Lexer::parseKeyword(JSTokenData* data)") + print("template ALWAYS_INLINE JSTokenType Lexer::parseKeyword(JSTokenData* data)") print("{") print(" ASSERT(m_codeEnd - m_code >= maxTokenLength);") print("") - print(" const UChar* code = m_code;") + print(" const char16_t* code = m_code;") self.printSubTreeAsC("UCHAR", 4) print(" return IDENT;") print("}") print("") print("template <>") - print("template ALWAYS_INLINE JSTokenType Lexer::parseKeyword(JSTokenData* data)") + print("template ALWAYS_INLINE JSTokenType Lexer::parseKeyword(JSTokenData* data)") print("{") print(" ASSERT(m_codeEnd - m_code >= maxTokenLength);") print("") - print(" const LChar* code = m_code;") + print(" const Latin1Character* code = m_code;") self.printSubTreeAsC("CHAR", 4) print(" return IDENT;") print("}") diff --git a/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp b/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp index 15676a8e82ede..45e245cba264e 100644 --- a/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp +++ b/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp @@ -128,7 +128,7 @@ UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const S continue; } else if (characters[i] == ',') ++commas; - else if (!Lexer::isWhiteSpace(characters[i])) + else if (!Lexer::isWhiteSpace(characters[i])) sawOneParam = true; if (i + 2 < view.length() && characters[i] == '.' && characters[i + 1] == '.' && characters[i + 2] == '.') { diff --git a/Source/JavaScriptCore/builtins/BuiltinNames.cpp b/Source/JavaScriptCore/builtins/BuiltinNames.cpp index 34376bf5018e0..45d1de8b9d843 100644 --- a/Source/JavaScriptCore/builtins/BuiltinNames.cpp +++ b/Source/JavaScriptCore/builtins/BuiltinNames.cpp @@ -93,8 +93,8 @@ BuiltinNames::BuiltinNames(VM& vm, CommonIdentifiers* commonIdentifiers) #undef INITIALIZE_WELL_KNOWN_SYMBOL_PUBLIC_TO_PRIVATE_ENTRY -using LCharBuffer = WTF::HashTranslatorCharBuffer; -using UCharBuffer = WTF::HashTranslatorCharBuffer; +using LCharBuffer = WTF::HashTranslatorCharBuffer; +using UCharBuffer = WTF::HashTranslatorCharBuffer; template struct CharBufferSeacher { @@ -132,13 +132,13 @@ static SymbolImpl* lookUpWellKnownSymbolImpl(const BuiltinNames::WellKnownSymbol return iterator->value; } -PrivateSymbolImpl* BuiltinNames::lookUpPrivateName(std::span characters) const +PrivateSymbolImpl* BuiltinNames::lookUpPrivateName(std::span characters) const { LCharBuffer buffer { characters }; return lookUpPrivateNameImpl(m_privateNameSet, buffer); } -PrivateSymbolImpl* BuiltinNames::lookUpPrivateName(std::span characters) const +PrivateSymbolImpl* BuiltinNames::lookUpPrivateName(std::span characters) const { UCharBuffer buffer { characters }; return lookUpPrivateNameImpl(m_privateNameSet, buffer); @@ -154,13 +154,13 @@ PrivateSymbolImpl* BuiltinNames::lookUpPrivateName(const String& string) const return lookUpPrivateNameImpl(m_privateNameSet, buffer); } -SymbolImpl* BuiltinNames::lookUpWellKnownSymbol(std::span characters) const +SymbolImpl* BuiltinNames::lookUpWellKnownSymbol(std::span characters) const { LCharBuffer buffer { characters }; return lookUpWellKnownSymbolImpl(m_wellKnownSymbolsMap, buffer); } -SymbolImpl* BuiltinNames::lookUpWellKnownSymbol(std::span characters) const +SymbolImpl* BuiltinNames::lookUpWellKnownSymbol(std::span characters) const { UCharBuffer buffer { characters }; return lookUpWellKnownSymbolImpl(m_wellKnownSymbolsMap, buffer); diff --git a/Source/JavaScriptCore/builtins/BuiltinNames.h b/Source/JavaScriptCore/builtins/BuiltinNames.h index 07aae9248fa57..880eb993aeb2c 100644 --- a/Source/JavaScriptCore/builtins/BuiltinNames.h +++ b/Source/JavaScriptCore/builtins/BuiltinNames.h @@ -246,13 +246,13 @@ class BuiltinNames { PrivateSymbolImpl* lookUpPrivateName(const Identifier&) const; PrivateSymbolImpl* lookUpPrivateName(const String&) const; - PrivateSymbolImpl* lookUpPrivateName(std::span) const; - PrivateSymbolImpl* lookUpPrivateName(std::span) const; + PrivateSymbolImpl* lookUpPrivateName(std::span) const; + PrivateSymbolImpl* lookUpPrivateName(std::span) const; SymbolImpl* lookUpWellKnownSymbol(const Identifier&) const; SymbolImpl* lookUpWellKnownSymbol(const String&) const; - SymbolImpl* lookUpWellKnownSymbol(std::span) const; - SymbolImpl* lookUpWellKnownSymbol(std::span) const; + SymbolImpl* lookUpWellKnownSymbol(std::span) const; + SymbolImpl* lookUpWellKnownSymbol(std::span) const; void appendExternalName(const Identifier& publicName, const Identifier& privateName); diff --git a/Source/JavaScriptCore/bytecode/CodeBlockHash.cpp b/Source/JavaScriptCore/bytecode/CodeBlockHash.cpp index c3e97874fd767..7ade2833a4ddb 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlockHash.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlockHash.cpp @@ -66,7 +66,7 @@ CodeBlockHash::CodeBlockHash(const SourceCode& sourceCode, CodeSpecializationKin sha1.addBytes(std::span { std::bit_cast(&length), sizeof(length) }); do { - UChar character = str[index]; + char16_t character = str[index]; sha1.addBytes(std::span { std::bit_cast(&character), sizeof(character) }); oldIndex = index; index += step; diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp index 8c3535f8d6dec..0c320516a57e7 100644 --- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp +++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp @@ -168,7 +168,7 @@ RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d if (regExp->isValid()) return generator.emitNewRegExp(generator.finalDestination(dst), regExp); - auto& message = generator.parserArena().identifierArena().makeIdentifier(generator.vm(), span8(regExp->errorMessage())); + auto& message = generator.parserArena().identifierArena().makeIdentifier(generator.vm(), byteCast(unsafeSpan(regExp->errorMessage()))); generator.emitThrowStaticError(ErrorTypeWithExtension::SyntaxError, message); return generator.emitLoad(generator.finalDestination(dst), jsUndefined()); } diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h index c1246c61294f8..ac6ed9618c498 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h +++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h @@ -1632,7 +1632,7 @@ bool AbstractInterpreter::executeEffects(unsigned clobberLimi if (const StringImpl* a = asString(string)->tryGetValueImpl()) { bool lower = true; for (unsigned index = 0; index < a->length(); ++index) { - UChar character = a->at(index); + char16_t character = a->at(index); if (!isASCII(character) || isASCIIUpper(character)) { lower = false; break; diff --git a/Source/JavaScriptCore/dfg/DFGLazyJSValue.cpp b/Source/JavaScriptCore/dfg/DFGLazyJSValue.cpp index 34516b078991d..77ac0e3ea1fb7 100644 --- a/Source/JavaScriptCore/dfg/DFGLazyJSValue.cpp +++ b/Source/JavaScriptCore/dfg/DFGLazyJSValue.cpp @@ -59,7 +59,7 @@ JSValue LazyJSValue::getValue(VM& vm) const return JSValue(); } -static TriState equalToSingleCharacter(JSValue value, UChar character) +static TriState equalToSingleCharacter(JSValue value, char16_t character) { if (!value.isString()) return TriState::False; diff --git a/Source/JavaScriptCore/dfg/DFGLazyJSValue.h b/Source/JavaScriptCore/dfg/DFGLazyJSValue.h index 65b96daf578ac..b490328429c6d 100644 --- a/Source/JavaScriptCore/dfg/DFGLazyJSValue.h +++ b/Source/JavaScriptCore/dfg/DFGLazyJSValue.h @@ -59,7 +59,7 @@ class LazyJSValue { u.value = value; } - static LazyJSValue singleCharacterString(UChar character) + static LazyJSValue singleCharacterString(char16_t character) { LazyJSValue result; result.m_kind = SingleCharacterString; @@ -95,7 +95,7 @@ class LazyJSValue { return u.value; } - UChar character() const + char16_t character() const { ASSERT(m_kind == SingleCharacterString); return u.character; @@ -123,7 +123,7 @@ class LazyJSValue { union { FrozenValue* value; - UChar character; + char16_t character; StringImpl* stringImpl; } u; LazinessKind m_kind; diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp index f971f0e32df51..2ad3574b0d8ff 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.cpp +++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp @@ -1901,7 +1901,7 @@ JSC_DEFINE_JIT_OPERATION(operationToNumberString, EncodedJSValue, (JSGlobalObjec unsigned size = view->length(); if (size == 1) { - UChar c = view[0]; + char16_t c = view[0]; if (isASCIIDigit(c)) OPERATION_RETURN(scope, JSValue::encode(jsNumber(static_cast(c - '0')))); if (isStrWhiteSpace(c)) @@ -1910,7 +1910,7 @@ JSC_DEFINE_JIT_OPERATION(operationToNumberString, EncodedJSValue, (JSGlobalObjec } if (size == 2 && view[0] == '-') { - UChar c = view[1]; + char16_t c = view[1]; if (c == '0') OPERATION_RETURN(scope, JSValue::encode(jsNumber(-0.0))); if (isASCIIDigit(c)) @@ -3091,7 +3091,7 @@ JSC_DEFINE_JIT_OPERATION(operationStringIndexOfWithOneChar, UCPUStrictInt32, (JS auto thisView = base->view(globalObject); OPERATION_RETURN_IF_EXCEPTION(scope, 0); - size_t result = thisView->find(static_cast(character)); + size_t result = thisView->find(static_cast(character)); if (result == notFound) OPERATION_RETURN(scope, toUCPUStrictInt32(-1)); OPERATION_RETURN(scope, toUCPUStrictInt32(result)); @@ -3144,7 +3144,7 @@ JSC_DEFINE_JIT_OPERATION(operationStringIndexOfWithIndexWithOneChar, UCPUStrictI if (static_cast(length) < 1 + pos) OPERATION_RETURN(scope, toUCPUStrictInt32(-1)); - size_t result = thisView->find(static_cast(character), pos); + size_t result = thisView->find(static_cast(character), pos); if (result == notFound) OPERATION_RETURN(scope, toUCPUStrictInt32(-1)); OPERATION_RETURN(scope, toUCPUStrictInt32(result)); @@ -3321,7 +3321,7 @@ JSC_DEFINE_JIT_OPERATION(operationSingleCharacterString, JSString*, (VM* vmPoint JITOperationPrologueCallFrameTracer tracer(vm, callFrame); auto scope = DECLARE_THROW_SCOPE(vm); - OPERATION_RETURN(scope, jsSingleCharacterString(vm, static_cast(character))); + OPERATION_RETURN(scope, jsSingleCharacterString(vm, static_cast(character))); } JSC_DEFINE_JIT_OPERATION(operationNewSymbol, Symbol*, (VM* vmPointer)) diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index 37af71aa90127..b42f48a0d656d 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -12198,7 +12198,7 @@ struct CharacterCase { return character < other.character; } - LChar character; + Latin1Character character; unsigned begin; unsigned end; }; @@ -16218,7 +16218,7 @@ void SpeculativeJIT::compileStringLocaleCompare(Node* node) void SpeculativeJIT::compileStringIndexOf(Node* node) { - std::optional character; + std::optional character; String searchString = node->child2()->tryGetString(m_graph); if (!!searchString) { if (searchString.length() == 1) diff --git a/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h b/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h index 3f2e27342f9ce..8f3e44391d862 100644 --- a/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h +++ b/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h @@ -194,8 +194,8 @@ namespace JSC { namespace FTL { macro(JSInternalFieldObjectImpl_internalFields, JSInternalFieldObjectImpl<>::offsetOfInternalFields(), sizeof(WriteBarrier)) \ macro(ScopedArguments_Storage_storage, 0, sizeof(EncodedJSValue)) \ macro(WriteBarrierBuffer_bufferContents, 0, sizeof(JSCell*)) \ - macro(characters8, 0, sizeof(LChar)) \ - macro(characters16, 0, sizeof(UChar)) \ + macro(characters8, 0, sizeof(Latin1Character)) \ + macro(characters16, 0, sizeof(char16_t)) \ macro(indexedInt32Properties, 0, sizeof(EncodedJSValue)) \ macro(indexedDoubleProperties, 0, sizeof(double)) \ macro(indexedContiguousProperties, 0, sizeof(EncodedJSValue)) \ diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp index 51d6c733e7d7c..cbef7dcc11548 100644 --- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp +++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp @@ -10401,7 +10401,7 @@ IGNORE_CLANG_WARNINGS_END void compileStringIndexOf() { - std::optional character; + std::optional character; String searchString = m_node->child2()->tryGetString(m_graph); if (!!searchString) { if (searchString.length() == 1) @@ -20178,7 +20178,7 @@ IGNORE_CLANG_WARNINGS_END { } - CharacterCase(LChar character, unsigned begin, unsigned end) + CharacterCase(Latin1Character character, unsigned begin, unsigned end) : character(character) , begin(begin) , end(end) @@ -20190,7 +20190,7 @@ IGNORE_CLANG_WARNINGS_END return character < other.character; } - LChar character; + Latin1Character character; unsigned begin; unsigned end; }; @@ -20282,7 +20282,7 @@ IGNORE_CLANG_WARNINGS_END Vector characterCases; CharacterCase currentCase(cases[begin].string->at(commonChars), begin, begin + 1); for (unsigned i = begin + 1; i < end; ++i) { - LChar currentChar = cases[i].string->at(commonChars); + Latin1Character currentChar = cases[i].string->at(commonChars); if (currentChar != currentCase.character) { currentCase.end = i; characterCases.append(currentCase); diff --git a/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp b/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp index c1901978968f7..0af51f64f7959 100644 --- a/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp +++ b/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp @@ -351,11 +351,6 @@ enum class NodeFlags { ObjectSubtype = 1 << 1, }; -static uint8_t edgeTypeToNumber(EdgeType type) -{ - return static_cast(type); -} - static ASCIILiteral edgeTypeToString(EdgeType type) { switch (type) { @@ -530,7 +525,7 @@ void HeapSnapshotBuilder::writeJson(Function&& a firstEdge = false; // , , , - json.append(edge.from.identifier, ',', edge.to.identifier, ',', edgeTypeToNumber(edge.type), ','); + json.append(edge.from.identifier, ',', edge.to.identifier, ',', edge.type, ','); switch (edge.type) { case EdgeType::Property: case EdgeType::Variable: { diff --git a/Source/JavaScriptCore/inspector/ContentSearchUtilities.cpp b/Source/JavaScriptCore/inspector/ContentSearchUtilities.cpp index ed6dfb592cab1..c727b9eb83daa 100644 --- a/Source/JavaScriptCore/inspector/ContentSearchUtilities.cpp +++ b/Source/JavaScriptCore/inspector/ContentSearchUtilities.cpp @@ -51,7 +51,7 @@ static String escapeStringForRegularExpressionSource(const String& text) StringBuilder result; for (unsigned i = 0; i < text.length(); i++) { - UChar character = text[i]; + char16_t character = text[i]; WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN if (isASCII(character) && strchr(regexSpecialCharacters, character)) result.append('\\'); diff --git a/Source/JavaScriptCore/inspector/remote/socket/RemoteInspectorSocket.cpp b/Source/JavaScriptCore/inspector/remote/socket/RemoteInspectorSocket.cpp index d7c5b88573fd1..da3fc0c052bd1 100644 --- a/Source/JavaScriptCore/inspector/remote/socket/RemoteInspectorSocket.cpp +++ b/Source/JavaScriptCore/inspector/remote/socket/RemoteInspectorSocket.cpp @@ -262,7 +262,7 @@ String RemoteInspector::backendCommands() const auto contents = FileSystem::readEntireFile(m_backendCommandsPath); - return contents ? String::adopt(WTFMove(*contents)) : emptyString(); + return contents ? String { byteCast(contents->span()) } : emptyString(); } // RemoteInspectorConnectionClient handlers diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp index 91f75c2a4e066..71fb363f95dfd 100644 --- a/Source/JavaScriptCore/interpreter/Interpreter.cpp +++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp @@ -186,12 +186,12 @@ JSValue eval(CallFrame* callFrame, JSValue thisValue, JSScope* callerScopeChain, if (!eval) { if (!(lexicallyScopedFeatures & StrictModeLexicallyScopedFeature)) { if (programSource.is8Bit()) { - LiteralParser preparser(globalObject, programSource.span8(), SloppyJSON, callerBaselineCodeBlock); + LiteralParser preparser(globalObject, programSource.span8(), SloppyJSON, callerBaselineCodeBlock); if (JSValue parsedObject = preparser.tryLiteralParse()) RELEASE_AND_RETURN(scope, parsedObject); } else { - LiteralParser preparser(globalObject, programSource.span16(), SloppyJSON, callerBaselineCodeBlock); + LiteralParser preparser(globalObject, programSource.span16(), SloppyJSON, callerBaselineCodeBlock); if (JSValue parsedObject = preparser.tryLiteralParse()) RELEASE_AND_RETURN(scope, parsedObject); @@ -1018,10 +1018,10 @@ JSValue Interpreter::executeProgram(const SourceCode& source, JSGlobalObject*, J if (programSource.isNull()) return jsUndefined(); if (programSource.is8Bit()) { - LiteralParser literalParser(globalObject, programSource.span8(), JSONP); + LiteralParser literalParser(globalObject, programSource.span8(), JSONP); parseResult = literalParser.tryJSONPParse(JSONPData, globalObject->globalObjectMethodTable()->supportsRichSourceInfo(globalObject)); } else { - LiteralParser literalParser(globalObject, programSource.span16(), JSONP); + LiteralParser literalParser(globalObject, programSource.span16(), JSONP); parseResult = literalParser.tryJSONPParse(JSONPData, globalObject->globalObjectMethodTable()->supportsRichSourceInfo(globalObject)); } diff --git a/Source/JavaScriptCore/jsc.cpp b/Source/JavaScriptCore/jsc.cpp index 1dfd6103d0089..7b676c5e5c8db 100644 --- a/Source/JavaScriptCore/jsc.cpp +++ b/Source/JavaScriptCore/jsc.cpp @@ -985,7 +985,7 @@ JSC_DEFINE_CUSTOM_SETTER(testCustomValueSetter, (JSGlobalObject* lexicalGlobalOb return GlobalObject::testCustomSetterImpl(lexicalGlobalObject, thisObject, encodedValue, "_testCustomValueSetter"_s); } -static UChar pathSeparator() +static char16_t pathSeparator() { #if OS(WINDOWS) return '\\'; diff --git a/Source/JavaScriptCore/parser/Lexer.cpp b/Source/JavaScriptCore/parser/Lexer.cpp index c18addf89e3ee..1eaf993aae1e7 100644 --- a/Source/JavaScriptCore/parser/Lexer.cpp +++ b/Source/JavaScriptCore/parser/Lexer.cpp @@ -359,7 +359,7 @@ static constexpr const CharacterType typesOfLatin1Characters[256] = { // This table provides the character that results from \X where X is the index in the table beginning // with SPACE. A table value of 0 means that more processing needs to be done. -static constexpr const LChar singleCharacterEscapeValuesForASCII[128] = { +static constexpr const Latin1Character singleCharacterEscapeValuesForASCII[128] = { /* 0 - Null */ 0, /* 1 - Start of Heading */ 0, /* 2 - Start of Text */ 0, @@ -739,29 +739,29 @@ static bool isNonLatin1IdentStart(char32_t c) template static ALWAYS_INLINE bool isIdentStart(CharacterType c) { - static_assert(std::is_same_v || std::is_same_v, "Call isSingleCharacterIdentStart for UChars that don't need to check for surrogate pairs"); + static_assert(std::is_same_v || std::is_same_v, "Call isSingleCharacterIdentStart for char16_ts that don't need to check for surrogate pairs"); if (!isLatin1(c)) return isNonLatin1IdentStart(c); - return typesOfLatin1Characters[static_cast(c)] == CharacterIdentifierStart; + return typesOfLatin1Characters[static_cast(c)] == CharacterIdentifierStart; } -static ALWAYS_INLINE UNUSED_FUNCTION bool isSingleCharacterIdentStart(UChar c) +static ALWAYS_INLINE UNUSED_FUNCTION bool isSingleCharacterIdentStart(char16_t c) { if (LIKELY(isLatin1(c))) - return isIdentStart(static_cast(c)); + return isIdentStart(static_cast(c)); return !U16_IS_SURROGATE(c) && isIdentStart(static_cast(c)); } -static ALWAYS_INLINE bool cannotBeIdentStart(LChar c) +static ALWAYS_INLINE bool cannotBeIdentStart(Latin1Character c) { return !isIdentStart(c) && c != '\\'; } -static ALWAYS_INLINE bool cannotBeIdentStart(UChar c) +static ALWAYS_INLINE bool cannotBeIdentStart(char16_t c) { if (LIKELY(isLatin1(c))) - return cannotBeIdentStart(static_cast(c)); - return Lexer::isWhiteSpace(c) || Lexer::isLineTerminator(c); + return cannotBeIdentStart(static_cast(c)); + return Lexer::isWhiteSpace(c) || Lexer::isLineTerminator(c); } static NEVER_INLINE bool isNonLatin1IdentPart(char32_t c) @@ -772,52 +772,52 @@ static NEVER_INLINE bool isNonLatin1IdentPart(char32_t c) template static ALWAYS_INLINE bool isIdentPart(CharacterType c) { - static_assert(std::is_same_v || std::is_same_v, "Call isSingleCharacterIdentPart for UChars that don't need to check for surrogate pairs"); + static_assert(std::is_same_v || std::is_same_v, "Call isSingleCharacterIdentPart for char16_ts that don't need to check for surrogate pairs"); if (!isLatin1(c)) return isNonLatin1IdentPart(c); // Character types are divided into two groups depending on whether they can be part of an // identifier or not. Those whose type value is less or equal than CharacterOtherIdentifierPart can be // part of an identifier. (See the CharacterType definition for more details.) - return typesOfLatin1Characters[static_cast(c)] <= CharacterOtherIdentifierPart; + return typesOfLatin1Characters[static_cast(c)] <= CharacterOtherIdentifierPart; } -static ALWAYS_INLINE bool isSingleCharacterIdentPart(UChar c) +static ALWAYS_INLINE bool isSingleCharacterIdentPart(char16_t c) { if (LIKELY(isLatin1(c))) - return isIdentPart(static_cast(c)); + return isIdentPart(static_cast(c)); return !U16_IS_SURROGATE(c) && isIdentPart(static_cast(c)); } -static ALWAYS_INLINE bool cannotBeIdentPartOrEscapeStart(LChar c) +static ALWAYS_INLINE bool cannotBeIdentPartOrEscapeStart(Latin1Character c) { return !isIdentPart(c) && c != '\\'; } // NOTE: This may give give false negatives (for non-ascii) but won't give false posititves. // This means it can be used to detect the end of a keyword (all keywords are ascii) -static ALWAYS_INLINE bool cannotBeIdentPartOrEscapeStart(UChar c) +static ALWAYS_INLINE bool cannotBeIdentPartOrEscapeStart(char16_t c) { if (LIKELY(isLatin1(c))) - return cannotBeIdentPartOrEscapeStart(static_cast(c)); - return Lexer::isWhiteSpace(c) || Lexer::isLineTerminator(c); + return cannotBeIdentPartOrEscapeStart(static_cast(c)); + return Lexer::isWhiteSpace(c) || Lexer::isLineTerminator(c); } template<> -ALWAYS_INLINE char32_t Lexer::currentCodePoint() const +ALWAYS_INLINE char32_t Lexer::currentCodePoint() const { return m_current; } template<> -ALWAYS_INLINE char32_t Lexer::currentCodePoint() const +ALWAYS_INLINE char32_t Lexer::currentCodePoint() const { ASSERT_WITH_MESSAGE(!isIdentStart(errorCodePoint), "error values shouldn't appear as a valid identifier start code point"); if (!U16_IS_SURROGATE(m_current)) return m_current; - UChar trail = peek(1); + char16_t trail = peek(1); if (UNLIKELY(!U16_IS_LEAD(m_current) || !U16_IS_SURROGATE_TRAIL(trail))) return errorCodePoint; @@ -848,7 +848,7 @@ static inline bool isASCIIOctalDigitOrSeparator(CharacterType character) return isASCIIOctalDigit(character) || character == '_'; } -static inline LChar singleEscape(int c) +static inline Latin1Character singleEscape(int c) { if (c < 128) { ASSERT(static_cast(c) < std::size(singleCharacterEscapeValuesForASCII)); @@ -861,7 +861,7 @@ template inline void Lexer::record8(int c) { ASSERT(isLatin1(c)); - m_buffer8.append(static_cast(c)); + m_buffer8.append(static_cast(c)); } template @@ -869,7 +869,7 @@ inline void Lexer::append8(std::span span) { size_t currentSize = m_buffer8.size(); m_buffer8.grow(currentSize + span.size()); - LChar* rawBuffer = m_buffer8.data() + currentSize; + Latin1Character* rawBuffer = m_buffer8.data() + currentSize; for (size_t i = 0; i < span.size(); i++) { T c = span[i]; @@ -879,11 +879,11 @@ inline void Lexer::append8(std::span span) } template -inline void Lexer::append16(std::span span) +inline void Lexer::append16(std::span span) { size_t currentSize = m_buffer16.size(); m_buffer16.grow(currentSize + span.size()); - UChar* rawBuffer = m_buffer16.data() + currentSize; + char16_t* rawBuffer = m_buffer16.data() + currentSize; for (size_t i = 0; i < span.size(); i++) rawBuffer[i] = span[i]; @@ -900,16 +900,16 @@ inline void Lexer::record16(int c) { ASSERT(c >= 0); ASSERT(c <= static_cast(USHRT_MAX)); - m_buffer16.append(static_cast(c)); + m_buffer16.append(static_cast(c)); } template inline void Lexer::recordUnicodeCodePoint(char32_t codePoint) { ASSERT(codePoint <= UCHAR_MAX_VALUE); if (U_IS_BMP(codePoint)) - record16(static_cast(codePoint)); + record16(static_cast(codePoint)); else { - UChar codeUnits[2] = { U16_LEAD(codePoint), U16_TRAIL(codePoint) }; + char16_t codeUnits[2] = { U16_LEAD(codePoint), U16_TRAIL(codePoint) }; append16(codeUnits); } } @@ -936,7 +936,7 @@ bool isSafeBuiltinIdentifier(VM& vm, const Identifier* ident) #endif // ASSERT_ENABLED template <> -template ALWAYS_INLINE JSTokenType Lexer::parseIdentifier(JSTokenData* tokenData, OptionSet lexerFlags, bool strictMode) +template ALWAYS_INLINE JSTokenType Lexer::parseIdentifier(JSTokenData* tokenData, OptionSet lexerFlags, bool strictMode) { tokenData->escaped = false; const ptrdiff_t remaining = m_codeEnd - m_code; @@ -960,7 +960,7 @@ template ALWAYS_INLINE JSTokenType Lexer::p } } - const LChar* identifierStart = currentSourcePtr(); + const Latin1Character* identifierStart = currentSourcePtr(); if (isPrivateName) shift(); @@ -1016,7 +1016,7 @@ template ALWAYS_INLINE JSTokenType Lexer::p } template <> -template ALWAYS_INLINE JSTokenType Lexer::parseIdentifier(JSTokenData* tokenData, OptionSet lexerFlags, bool strictMode) +template ALWAYS_INLINE JSTokenType Lexer::parseIdentifier(JSTokenData* tokenData, OptionSet lexerFlags, bool strictMode) { ASSERT(!m_parsingBuiltinFunction); tokenData->escaped = false; @@ -1030,12 +1030,12 @@ template ALWAYS_INLINE JSTokenType Lexer::p } bool isPrivateName = m_current == '#'; - const UChar* identifierStart = currentSourcePtr(); + const char16_t* identifierStart = currentSourcePtr(); if (isPrivateName) shift(); - UChar orAllChars = 0; + char16_t orAllChars = 0; ASSERT(isSingleCharacterIdentStart(m_current) || U16_IS_SURROGATE(m_current) || m_current == '\\'); while (isSingleCharacterIdentPart(m_current)) { orAllChars |= m_current; @@ -1172,12 +1172,12 @@ JSTokenType Lexer::parseIdentifierSlowCase(JSTokenData* tokenData return identType; } -static ALWAYS_INLINE bool characterRequiresParseStringSlowCase(LChar character) +static ALWAYS_INLINE bool characterRequiresParseStringSlowCase(Latin1Character character) { return character < 0xE; } -static ALWAYS_INLINE bool characterRequiresParseStringSlowCase(UChar character) +static ALWAYS_INLINE bool characterRequiresParseStringSlowCase(char16_t character) { return character < 0xE || !isLatin1(character); } @@ -1199,7 +1199,7 @@ template ALWAYS_INLINE typename Lexer::StringParseR append8({ stringStart, currentSourcePtr() }); shift(); - LChar escape = singleEscape(m_current); + Latin1Character escape = singleEscape(m_current); // Most common escape sequences first. if (escape) { @@ -1363,7 +1363,7 @@ template auto Lexer::parseStringSlowCase(JSTokenDat append16({ stringStart, currentSourcePtr() }); shift(); - LChar escape = singleEscape(m_current); + Latin1Character escape = singleEscape(m_current); // Most common escape sequences first if (escape) { @@ -1419,7 +1419,7 @@ typename Lexer::StringParseResult Lexer::parseTemplateLiteral(JSTokenData* append16({ stringStart, currentSourcePtr() }); shift(); - LChar escape = singleEscape(m_current); + Latin1Character escape = singleEscape(m_current); // Most common escape sequences first. if (escape) { @@ -1592,7 +1592,7 @@ ALWAYS_INLINE auto Lexer::parseBinary() -> std::optional int digit = maximumDigits - 1; // Temporary buffer for the digits. Makes easier // to reconstruct the input characters when needed. - LChar digits[maximumDigits]; + Latin1Character digits[maximumDigits]; do { if (m_current == '_') { @@ -1648,7 +1648,7 @@ ALWAYS_INLINE auto Lexer::parseOctal() -> std::optional int digit = maximumDigits - 1; // Temporary buffer for the digits. Makes easier // to reconstruct the input characters when needed. - LChar digits[maximumDigits]; + Latin1Character digits[maximumDigits]; do { if (m_current == '_') { @@ -1707,7 +1707,7 @@ ALWAYS_INLINE auto Lexer::parseDecimal() -> std::optional int digit = maximumDigits - 1; // Temporary buffer for the digits. Makes easier // to reconstruct the input characters when needed. - LChar digits[maximumDigits]; + Latin1Character digits[maximumDigits]; do { if (m_current == '_') { @@ -1842,10 +1842,10 @@ IGNORE_WARNINGS_BEGIN("unused-but-set-variable") template ALWAYS_INLINE String Lexer::parseCommentDirectiveValue() { skipWhitespace(); - UChar mergedCharacterBits = 0; + char16_t mergedCharacterBits = 0; auto stringStart = currentSourcePtr(); while (!isWhiteSpace(m_current) && !isLineTerminator(m_current) && m_current != '"' && m_current != '\'' && !atEnd()) { - if constexpr (std::is_same_v) + if constexpr (std::is_same_v) mergedCharacterBits |= m_current; shift(); } @@ -1855,7 +1855,7 @@ template ALWAYS_INLINE String Lexer::pars if (!isLineTerminator(m_current) && !atEnd()) return String(); - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { if (isLatin1(mergedCharacterBits)) return String::make8Bit(commentDirective); } @@ -2522,7 +2522,7 @@ JSTokenType Lexer::lexWithoutClearingLineTerminator(JSToken* tokenRecord, Opt bool isValidPrivateName; if (LIKELY(isLatin1(next))) - isValidPrivateName = typesOfLatin1Characters[static_cast(next)] == CharacterIdentifierStart || next == '\\'; + isValidPrivateName = typesOfLatin1Characters[static_cast(next)] == CharacterIdentifierStart || next == '\\'; else { ASSERT(m_code + 1 < m_codeEnd); char32_t codePoint; @@ -2605,26 +2605,26 @@ JSTokenType Lexer::lexWithoutClearingLineTerminator(JSToken* tokenRecord, Opt } template -static inline void orCharacter(UChar&, UChar); +static inline void orCharacter(char16_t&, char16_t); template <> -inline void orCharacter(UChar&, UChar) { } +inline void orCharacter(char16_t&, char16_t) { } template <> -inline void orCharacter(UChar& orAccumulator, UChar character) +inline void orCharacter(char16_t& orAccumulator, char16_t character) { orAccumulator |= character; } template -JSTokenType Lexer::scanRegExp(JSToken* tokenRecord, UChar patternPrefix) +JSTokenType Lexer::scanRegExp(JSToken* tokenRecord, char16_t patternPrefix) { JSTokenData* tokenData = &tokenRecord->m_data; ASSERT(m_buffer16.isEmpty()); bool lastWasEscape = false; bool inBrackets = false; - UChar charactersOredTogether = 0; + char16_t charactersOredTogether = 0; if (patternPrefix) { ASSERT(!isLineTerminator(patternPrefix)); @@ -2675,8 +2675,8 @@ JSTokenType Lexer::scanRegExp(JSToken* tokenRecord, UChar patternPrefix) m_buffer16.shrink(0); ASSERT(m_buffer8.isEmpty()); - while (LIKELY(isLatin1(m_current)) && isIdentPart(static_cast(m_current))) { - record8(static_cast(m_current)); + while (LIKELY(isLatin1(m_current)) && isIdentPart(static_cast(m_current))) { + record8(static_cast(m_current)); shift(); } @@ -2735,21 +2735,21 @@ void Lexer::clear() { m_arena = nullptr; - Vector newBuffer8; + Vector newBuffer8; m_buffer8.swap(newBuffer8); - Vector newBuffer16; + Vector newBuffer16; m_buffer16.swap(newBuffer16); - Vector newBufferForRawTemplateString16; + Vector newBufferForRawTemplateString16; m_bufferForRawTemplateString16.swap(newBufferForRawTemplateString16); m_isReparsingFunction = false; } // Instantiate the two flavors of Lexer we need instead of putting most of this file in Lexer.h -template class Lexer; -template class Lexer; +template class Lexer; +template class Lexer; } // namespace JSC diff --git a/Source/JavaScriptCore/parser/Lexer.h b/Source/JavaScriptCore/parser/Lexer.h index bb401c341bfd1..bc328e32f856b 100644 --- a/Source/JavaScriptCore/parser/Lexer.h +++ b/Source/JavaScriptCore/parser/Lexer.h @@ -58,7 +58,7 @@ class Lexer { static bool isWhiteSpace(T character); static bool isLineTerminator(T character); static unsigned char convertHex(int c1, int c2); - static UChar convertUnicode(int c1, int c2, int c3, int c4); + static char16_t convertUnicode(int c1, int c2, int c3, int c4); // Functions to set up parsing. void setCode(const SourceCode&, ParserArena*); @@ -80,7 +80,7 @@ class Lexer { void setLastLineNumber(int lastLineNumber) { m_lastLineNumber = lastLineNumber; } int lastLineNumber() const { return m_lastLineNumber; } bool hasLineTerminatorBeforeToken() const { return m_hasLineTerminatorBeforeToken; } - JSTokenType scanRegExp(JSToken*, UChar patternPrefix = 0); + JSTokenType scanRegExp(JSToken*, char16_t patternPrefix = 0); enum class RawStringsBuildMode { BuildRawStrings, DontBuildRawStrings }; JSTokenType scanTemplateString(JSToken*, RawStringsBuildMode); @@ -135,8 +135,8 @@ class Lexer { void record16(int); void record16(T); void recordUnicodeCodePoint(char32_t); - void append16(std::span); - void append16(std::span characters) { m_buffer16.append(characters); } + void append16(std::span); + void append16(std::span characters) { m_buffer16.append(characters); } static constexpr char32_t errorCodePoint = 0xFFFFFFFFu; char32_t currentCodePoint() const; @@ -158,10 +158,10 @@ class Lexer { template ALWAYS_INLINE const Identifier* makeIdentifier(std::span); - ALWAYS_INLINE const Identifier* makeLCharIdentifier(std::span); - ALWAYS_INLINE const Identifier* makeLCharIdentifier(std::span); - ALWAYS_INLINE const Identifier* makeRightSizedIdentifier(std::span, UChar orAllChars); - ALWAYS_INLINE const Identifier* makeIdentifierLCharFromUChar(std::span); + ALWAYS_INLINE const Identifier* makeLCharIdentifier(std::span); + ALWAYS_INLINE const Identifier* makeLCharIdentifier(std::span); + ALWAYS_INLINE const Identifier* makeRightSizedIdentifier(std::span, char16_t orAllChars); + ALWAYS_INLINE const Identifier* makeIdentifierLCharFromUChar(std::span); ALWAYS_INLINE const Identifier* makeEmptyIdentifier(); ALWAYS_INLINE bool lastTokenWasRestrKeyword() const; @@ -206,9 +206,9 @@ class Lexer { int m_lineNumber; int m_lastLineNumber; - Vector m_buffer8; - Vector m_buffer16; - Vector m_bufferForRawTemplateString16; + Vector m_buffer8; + Vector m_buffer16; + Vector m_bufferForRawTemplateString16; bool m_hasLineTerminatorBeforeToken; int m_lastToken; @@ -241,25 +241,25 @@ class Lexer { WTF_MAKE_TZONE_ALLOCATED_TEMPLATE_IMPL(template, Lexer); template <> -ALWAYS_INLINE bool Lexer::isWhiteSpace(LChar ch) +ALWAYS_INLINE bool Lexer::isWhiteSpace(Latin1Character ch) { return ch == ' ' || ch == '\t' || ch == 0xB || ch == 0xC || ch == 0xA0; } template <> -ALWAYS_INLINE bool Lexer::isWhiteSpace(UChar ch) +ALWAYS_INLINE bool Lexer::isWhiteSpace(char16_t ch) { - return isLatin1(ch) ? Lexer::isWhiteSpace(static_cast(ch)) : (u_charType(ch) == U_SPACE_SEPARATOR || ch == byteOrderMark); + return isLatin1(ch) ? Lexer::isWhiteSpace(static_cast(ch)) : (u_charType(ch) == U_SPACE_SEPARATOR || ch == byteOrderMark); } template <> -ALWAYS_INLINE bool Lexer::isLineTerminator(LChar ch) +ALWAYS_INLINE bool Lexer::isLineTerminator(Latin1Character ch) { return ch == '\r' || ch == '\n'; } template <> -ALWAYS_INLINE bool Lexer::isLineTerminator(UChar ch) +ALWAYS_INLINE bool Lexer::isLineTerminator(char16_t ch) { return ch == '\r' || ch == '\n' || (ch & ~1) == 0x2028; } @@ -271,7 +271,7 @@ inline unsigned char Lexer::convertHex(int c1, int c2) } template -inline UChar Lexer::convertUnicode(int c1, int c2, int c3, int c4) +inline char16_t Lexer::convertUnicode(int c1, int c2, int c3, int c4) { return (convertHex(c1, c2) << 8) | convertHex(c3, c4); } @@ -284,13 +284,13 @@ ALWAYS_INLINE const Identifier* Lexer::makeIdentifier(std::span -ALWAYS_INLINE const Identifier* Lexer::makeRightSizedIdentifier(std::span characters, UChar) +ALWAYS_INLINE const Identifier* Lexer::makeRightSizedIdentifier(std::span characters, char16_t) { return &m_arena->makeIdentifierLCharFromUChar(m_vm, characters); } template <> -ALWAYS_INLINE const Identifier* Lexer::makeRightSizedIdentifier(std::span characters, UChar orAllChars) +ALWAYS_INLINE const Identifier* Lexer::makeRightSizedIdentifier(std::span characters, char16_t orAllChars) { if (!(orAllChars & ~0xff)) return &m_arena->makeIdentifierLCharFromUChar(m_vm, characters); @@ -305,33 +305,33 @@ ALWAYS_INLINE const Identifier* Lexer::makeEmptyIdentifier() } template <> -ALWAYS_INLINE void Lexer::setCodeStart(StringView sourceString) +ALWAYS_INLINE void Lexer::setCodeStart(StringView sourceString) { ASSERT(sourceString.is8Bit()); m_codeStart = sourceString.span8().data(); } template <> -ALWAYS_INLINE void Lexer::setCodeStart(StringView sourceString) +ALWAYS_INLINE void Lexer::setCodeStart(StringView sourceString) { ASSERT(!sourceString.is8Bit()); m_codeStart = sourceString.span16().data(); } template -ALWAYS_INLINE const Identifier* Lexer::makeIdentifierLCharFromUChar(std::span characters) +ALWAYS_INLINE const Identifier* Lexer::makeIdentifierLCharFromUChar(std::span characters) { return &m_arena->makeIdentifierLCharFromUChar(m_vm, characters); } template -ALWAYS_INLINE const Identifier* Lexer::makeLCharIdentifier(std::span characters) +ALWAYS_INLINE const Identifier* Lexer::makeLCharIdentifier(std::span characters) { return &m_arena->makeIdentifier(m_vm, characters); } template -ALWAYS_INLINE const Identifier* Lexer::makeLCharIdentifier(std::span characters) +ALWAYS_INLINE const Identifier* Lexer::makeLCharIdentifier(std::span characters) { return &m_arena->makeIdentifierLCharFromUChar(m_vm, characters); } diff --git a/Source/JavaScriptCore/parser/Parser.cpp b/Source/JavaScriptCore/parser/Parser.cpp index 11016067e29cf..4d65b83f1f7e9 100644 --- a/Source/JavaScriptCore/parser/Parser.cpp +++ b/Source/JavaScriptCore/parser/Parser.cpp @@ -5755,7 +5755,7 @@ template void Parser::printUnexpectedTokenText(W } // Instantiate the two flavors of Parser we need instead of putting most of this file in Parser.h -template class Parser>; -template class Parser>; +template class Parser>; +template class Parser>; } // namespace JSC diff --git a/Source/JavaScriptCore/parser/Parser.h b/Source/JavaScriptCore/parser/Parser.h index f33c3b2867231..c525d8cac325b 100644 --- a/Source/JavaScriptCore/parser/Parser.h +++ b/Source/JavaScriptCore/parser/Parser.h @@ -2284,7 +2284,7 @@ std::unique_ptr parse( std::unique_ptr result; if (source.provider()->source().is8Bit()) { - Parser> parser(vm, source, implementationVisibility, builtinMode, lexicallyScopedFeatures, scriptMode, parseMode, functionMode, superBinding, constructorKind, derivedContextType, isEvalNode(), evalContextType, nullptr, isInsideOrdinaryFunction); + Parser> parser(vm, source, implementationVisibility, builtinMode, lexicallyScopedFeatures, scriptMode, parseMode, functionMode, superBinding, constructorKind, derivedContextType, isEvalNode(), evalContextType, nullptr, isInsideOrdinaryFunction); result = parser.parse(error, name, ParsingContext::Normal, std::nullopt, parentScopePrivateNames, classElementDefinitions); if (builtinMode == JSParserBuiltinMode::Builtin) { if (!result) { @@ -2294,7 +2294,7 @@ std::unique_ptr parse( } } } else { - Parser> parser(vm, source, implementationVisibility, builtinMode, lexicallyScopedFeatures, scriptMode, parseMode, functionMode, superBinding, constructorKind, derivedContextType, isEvalNode(), evalContextType, nullptr, isInsideOrdinaryFunction); + Parser> parser(vm, source, implementationVisibility, builtinMode, lexicallyScopedFeatures, scriptMode, parseMode, functionMode, superBinding, constructorKind, derivedContextType, isEvalNode(), evalContextType, nullptr, isInsideOrdinaryFunction); result = parser.parse(error, name, ParsingContext::Normal, std::nullopt, parentScopePrivateNames, classElementDefinitions); } @@ -2332,7 +2332,7 @@ std::unique_ptr parseRootNode( bool isInsideOrdinaryFunction = false; std::unique_ptr result; if (source.provider()->source().is8Bit()) { - Parser> parser(vm, source, implementationVisibility, builtinMode, lexicallyScopedFeatures, scriptMode, parseMode, FunctionMode::None, SuperBinding::NotNeeded, ConstructorKind::None, DerivedContextType::None, isEvalNode, EvalContextType::None, debuggerParseData, isInsideOrdinaryFunction); + Parser> parser(vm, source, implementationVisibility, builtinMode, lexicallyScopedFeatures, scriptMode, parseMode, FunctionMode::None, SuperBinding::NotNeeded, ConstructorKind::None, DerivedContextType::None, isEvalNode, EvalContextType::None, debuggerParseData, isInsideOrdinaryFunction); parser.overrideConstructorKindForTopLevelFunctionExpressions(constructorKindForTopLevelFunctionExpressions); result = parser.parse(error, name, ParsingContext::Normal); if (positionBeforeLastNewline) @@ -2340,7 +2340,7 @@ std::unique_ptr parseRootNode( } else { ASSERT_WITH_MESSAGE(!positionBeforeLastNewline, "BuiltinExecutables should always use a 8-bit string"); ASSERT_WITH_MESSAGE(constructorKindForTopLevelFunctionExpressions == ConstructorKind::None, "BuiltinExecutables' special constructors should always use a 8-bit string"); - Parser> parser(vm, source, implementationVisibility, builtinMode, lexicallyScopedFeatures, scriptMode, parseMode, FunctionMode::None, SuperBinding::NotNeeded, ConstructorKind::None, DerivedContextType::None, isEvalNode, EvalContextType::None, debuggerParseData, isInsideOrdinaryFunction); + Parser> parser(vm, source, implementationVisibility, builtinMode, lexicallyScopedFeatures, scriptMode, parseMode, FunctionMode::None, SuperBinding::NotNeeded, ConstructorKind::None, DerivedContextType::None, isEvalNode, EvalContextType::None, debuggerParseData, isInsideOrdinaryFunction); result = parser.parse(error, name, ParsingContext::Normal); } @@ -2368,12 +2368,12 @@ inline std::unique_ptr parseFunctionForFunctionConstructor(VM& vm, bool isEvalNode = false; std::unique_ptr result; if (source.provider()->source().is8Bit()) { - Parser> parser(vm, source, ImplementationVisibility::Public, JSParserBuiltinMode::NotBuiltin, lexicallyScopedFeatures, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, FunctionMode::None, SuperBinding::NotNeeded, ConstructorKind::None, DerivedContextType::None, isEvalNode, EvalContextType::None, nullptr); + Parser> parser(vm, source, ImplementationVisibility::Public, JSParserBuiltinMode::NotBuiltin, lexicallyScopedFeatures, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, FunctionMode::None, SuperBinding::NotNeeded, ConstructorKind::None, DerivedContextType::None, isEvalNode, EvalContextType::None, nullptr); result = parser.parse(error, name, ParsingContext::FunctionConstructor, functionConstructorParametersEndPosition); if (positionBeforeLastNewline) *positionBeforeLastNewline = parser.positionBeforeLastNewline(); } else { - Parser> parser(vm, source, ImplementationVisibility::Public, JSParserBuiltinMode::NotBuiltin, lexicallyScopedFeatures, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, FunctionMode::None, SuperBinding::NotNeeded, ConstructorKind::None, DerivedContextType::None, isEvalNode, EvalContextType::None, nullptr); + Parser> parser(vm, source, ImplementationVisibility::Public, JSParserBuiltinMode::NotBuiltin, lexicallyScopedFeatures, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, FunctionMode::None, SuperBinding::NotNeeded, ConstructorKind::None, DerivedContextType::None, isEvalNode, EvalContextType::None, nullptr); result = parser.parse(error, name, ParsingContext::FunctionConstructor, functionConstructorParametersEndPosition); if (positionBeforeLastNewline) *positionBeforeLastNewline = parser.positionBeforeLastNewline(); diff --git a/Source/JavaScriptCore/parser/ParserArena.h b/Source/JavaScriptCore/parser/ParserArena.h index 7ad52673c2a95..df9994a470330 100644 --- a/Source/JavaScriptCore/parser/ParserArena.h +++ b/Source/JavaScriptCore/parser/ParserArena.h @@ -50,7 +50,7 @@ namespace JSC { template ALWAYS_INLINE const Identifier& makeIdentifier(VM&, std::span characters); ALWAYS_INLINE const Identifier& makeEmptyIdentifier(VM&); - ALWAYS_INLINE const Identifier& makeIdentifierLCharFromUChar(VM&, std::span characters); + ALWAYS_INLINE const Identifier& makeIdentifierLCharFromUChar(VM&, std::span characters); ALWAYS_INLINE const Identifier& makeIdentifier(VM&, SymbolImpl*); const Identifier* makeBigIntDecimalIdentifier(VM&, const Identifier&, uint8_t radix); @@ -111,7 +111,7 @@ namespace JSC { return vm.propertyNames->emptyIdentifier; } - ALWAYS_INLINE const Identifier& IdentifierArena::makeIdentifierLCharFromUChar(VM& vm, std::span characters) + ALWAYS_INLINE const Identifier& IdentifierArena::makeIdentifierLCharFromUChar(VM& vm, std::span characters) { if (characters.empty()) return vm.propertyNames->emptyIdentifier; diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp index b6b5404c8949d..079d65cf62792 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -418,7 +418,7 @@ JSC_DEFINE_HOST_FUNCTION(arrayProtoFuncToString, (JSGlobalObject* globalObject, return JSValue::encode(earlyReturnValue); if (LIKELY(canUseFastJoin(thisArray))) { - const LChar comma = ','; + const Latin1Character comma = ','; bool isCoW = isCopyOnWrite(thisArray->indexingMode()); JSImmutableButterfly* immutableButterfly = nullptr; @@ -506,7 +506,7 @@ JSC_DEFINE_HOST_FUNCTION(arrayProtoFuncToLocaleString, (JSGlobalObject* globalOb // 3. Let separator be the String value for the list-separator String appropriate for // the host environment's current locale (this is derived in an implementation-defined way). - const LChar comma = ','; + const Latin1Character comma = ','; JSString* separator = jsSingleCharacterString(vm, comma); // 4. Let R be the empty String. @@ -628,7 +628,7 @@ JSC_DEFINE_HOST_FUNCTION(arrayProtoFuncJoin, (JSGlobalObject* globalObject, Call // 3. If separator is undefined, let separator be the single-element String ",". JSValue separatorValue = callFrame->argument(0); if (separatorValue.isUndefined()) { - const LChar comma = ','; + const Latin1Character comma = ','; if (UNLIKELY(length > std::numeric_limits::max() || !canUseFastJoin(thisObject))) { JSString* jsSeparator = jsSingleCharacterString(vm, comma); @@ -1057,14 +1057,14 @@ static unsigned sortBucketSort(std::span sorted, unsigned dst, S return dst; } - StdMap buckets; + StdMap buckets; for (const auto& entry : bucket) { if (std::get<1>(entry).length() == depth) { sorted[dst++] = JSValue::encode(std::get<0>(entry)); continue; } - UChar character = std::get<1>(entry).characterAt(depth); + char16_t character = std::get<1>(entry).characterAt(depth); buckets.insert(std::pair { character, SortEntryVector { } }).first->second.append(entry); } diff --git a/Source/JavaScriptCore/runtime/CachedTypes.cpp b/Source/JavaScriptCore/runtime/CachedTypes.cpp index 57e0226fa35dd..11b491d120a9b 100644 --- a/Source/JavaScriptCore/runtime/CachedTypes.cpp +++ b/Source/JavaScriptCore/runtime/CachedTypes.cpp @@ -781,8 +781,8 @@ class CachedUniquedStringImplBase : public VariableLengthObject { return m_is8Bit ? create(span8()) : create(span16()); } - std::span span8() const { return { this->template buffer(), m_length }; } - std::span span16() const { return { this->template buffer(), m_length }; } + std::span span8() const { return { this->template buffer(), m_length }; } + std::span span16() const { return { this->template buffer(), m_length }; } private: bool m_is8Bit : 1; diff --git a/Source/JavaScriptCore/runtime/Error.cpp b/Source/JavaScriptCore/runtime/Error.cpp index 3c996f9770088..11f6ce03162d9 100644 --- a/Source/JavaScriptCore/runtime/Error.cpp +++ b/Source/JavaScriptCore/runtime/Error.cpp @@ -291,13 +291,13 @@ JSObject* createTypeErrorCopy(JSGlobalObject* globalObject, JSValue error) String makeDOMAttributeGetterTypeErrorMessage(const char* interfaceName, const String& attributeName) { - auto interfaceNameSpan = span(interfaceName); + auto interfaceNameSpan = unsafeSpan(interfaceName); return makeString("The "_s, interfaceNameSpan, '.', attributeName, " getter can only be used on instances of "_s, interfaceNameSpan); } String makeDOMAttributeSetterTypeErrorMessage(const char* interfaceName, const String& attributeName) { - auto interfaceNameSpan = span(interfaceName); + auto interfaceNameSpan = unsafeSpan(interfaceName); return makeString("The "_s, interfaceNameSpan, '.', attributeName, " setter can only be used on instances of "_s, interfaceNameSpan); } diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp index 2c757fdb44ae8..dd8d0e6dbc8b9 100644 --- a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp +++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp @@ -125,7 +125,7 @@ static StringView functionCallBase(StringView sourceText) // Note that we're scanning text right to left instead of the more common left to right, // so syntax detection is backwards. while (parenStack && idx) { - UChar curChar = sourceText[idx]; + char16_t curChar = sourceText[idx]; if (isInMultiLineComment) { if (curChar == '*' && sourceText[idx - 1] == '/') { isInMultiLineComment = false; diff --git a/Source/JavaScriptCore/runtime/FuzzerPredictions.cpp b/Source/JavaScriptCore/runtime/FuzzerPredictions.cpp index 9e80d7df7c939..f2f5dce33c01a 100644 --- a/Source/JavaScriptCore/runtime/FuzzerPredictions.cpp +++ b/Source/JavaScriptCore/runtime/FuzzerPredictions.cpp @@ -39,7 +39,7 @@ static String readFileIntoString(const char* fileName) RELEASE_ASSERT(bufferCapacity != -1); RELEASE_ASSERT(fseek(file, 0, SEEK_SET) != -1); - std::span buffer; + std::span buffer; auto bufferData = buffer.data(); String string = String::createUninitialized(bufferCapacity, bufferData); WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN diff --git a/Source/JavaScriptCore/runtime/ISO8601.cpp b/Source/JavaScriptCore/runtime/ISO8601.cpp index 7057653a9e11a..cf06caa0f2e71 100644 --- a/Source/JavaScriptCore/runtime/ISO8601.cpp +++ b/Source/JavaScriptCore/runtime/ISO8601.cpp @@ -80,7 +80,7 @@ static void handleFraction(Duration& duration, int factor, StringView fractionSt ASSERT(fractionLength && fractionLength <= 9 && fractionString.containsOnlyASCII()); ASSERT(fractionType == TemporalUnit::Hour || fractionType == TemporalUnit::Minute || fractionType == TemporalUnit::Second); - Vector padded(9, '0'); + Vector padded(9, '0'); for (unsigned i = 0; i < fractionLength; i++) padded[i] = fractionString[i]; @@ -363,7 +363,7 @@ static std::optional parseTimeSpec(StringParsingBuffer if (!digits) return std::nullopt; - Vector padded(9, '0'); + Vector padded(9, '0'); for (size_t i = 0; i < digits; ++i) padded[i] = buffer[i]; buffer.advanceBy(digits); @@ -539,7 +539,7 @@ static bool canBeCalendar(const StringParsingBuffer& buffer) template static bool canBeTimeZone(const StringParsingBuffer& buffer, CharacterType character) { - switch (static_cast(character)) { + switch (static_cast(character)) { // UTCDesignator // https://tc39.es/proposal-temporal/#prod-UTCDesignator case 'z': @@ -566,7 +566,7 @@ static bool canBeTimeZone(const StringParsingBuffer& buffer, Char } template -static std::optional, int64_t>> parseTimeZoneAnnotation(StringParsingBuffer& buffer) +static std::optional, int64_t>> parseTimeZoneAnnotation(StringParsingBuffer& buffer) { // https://tc39.es/proposal-temporal/#prod-TimeZoneAnnotation // TimeZoneAnnotation : @@ -585,7 +585,7 @@ static std::optional, int64_t>> parseTimeZoneAnnotati if (*buffer == '!') buffer.advance(); - switch (static_cast(*buffer)) { + switch (static_cast(*buffer)) { case '+': case '-': { auto offset = parseUTCOffset(buffer, false); @@ -700,7 +700,7 @@ static std::optional, int64_t>> parseTimeZoneAnnotati if (!isValidComponent(currentNameComponentStartIndex, nameLength)) return std::nullopt; - Vector result(buffer.consume(nameLength)); + Vector result(buffer.consume(nameLength)); if (buffer.atEnd()) return std::nullopt; @@ -717,7 +717,7 @@ static std::optional parseTimeZone(StringParsingBuffer(*buffer)) { + switch (static_cast(*buffer)) { // UTCDesignator // https://tc39.es/proposal-temporal/#prod-UTCDesignator case 'z': @@ -836,7 +836,7 @@ static std::optional parseCalendar(StringParsingBuffer result(buffer.consume(nameLength)); + Vector result(buffer.consume(nameLength)); if (buffer.atEnd()) return std::nullopt; @@ -1297,7 +1297,7 @@ String formatTimeZoneOffsetString(int64_t offset) if (nanoseconds) { // Since nsPerSecond is 1000000000, stringified nanoseconds takes at most 9 characters (999999999). - auto fraction = numberToStringUnsigned>(nanoseconds); + auto fraction = numberToStringUnsigned>(nanoseconds); unsigned paddingLength = 9 - fraction.size(); unsigned index = fraction.size(); std::optional validLength; @@ -1332,7 +1332,7 @@ String temporalTimeToString(PlainTime plainTime, std::tuple if (precisionType == Precision::Auto) { if (!fractionNanoseconds) return makeString(pad('0', 2, plainTime.hour()), ':', pad('0', 2, plainTime.minute()), ':', pad('0', 2, plainTime.second())); - auto fraction = numberToStringUnsigned>(fractionNanoseconds); + auto fraction = numberToStringUnsigned>(fractionNanoseconds); unsigned paddingLength = 9 - fraction.size(); unsigned index = fraction.size(); std::optional validLength; @@ -1350,7 +1350,7 @@ String temporalTimeToString(PlainTime plainTime, std::tuple } if (!precisionValue) return makeString(pad('0', 2, plainTime.hour()), ':', pad('0', 2, plainTime.minute()), ':', pad('0', 2, plainTime.second())); - auto fraction = numberToStringUnsigned>(fractionNanoseconds); + auto fraction = numberToStringUnsigned>(fractionNanoseconds); unsigned paddingLength = 9 - fraction.size(); paddingLength = std::min(paddingLength, precisionValue); precisionValue -= paddingLength; diff --git a/Source/JavaScriptCore/runtime/ISO8601.h b/Source/JavaScriptCore/runtime/ISO8601.h index 4e542d227a524..92fc6fb0974c8 100644 --- a/Source/JavaScriptCore/runtime/ISO8601.h +++ b/Source/JavaScriptCore/runtime/ISO8601.h @@ -178,7 +178,7 @@ class ExactTime { { if (value > 9) asStringImpl(builder, value / 10); - builder.append(static_cast(static_cast(value % 10) + '0')); + builder.append(static_cast(static_cast(value % 10) + '0')); } static Int128 round(Int128 quantity, unsigned increment, TemporalUnit, RoundingMode); @@ -261,13 +261,13 @@ using TimeZone = std::variant; struct TimeZoneRecord { bool m_z { false }; std::optional m_offset; - std::variant, int64_t> m_nameOrOffset; + std::variant, int64_t> m_nameOrOffset; }; static constexpr unsigned minCalendarLength = 3; static constexpr unsigned maxCalendarLength = 8; struct CalendarRecord { - Vector m_name; + Vector m_name; }; // https://tc39.es/proposal-temporal/#sup-isvalidtimezonename diff --git a/Source/JavaScriptCore/runtime/Identifier.cpp b/Source/JavaScriptCore/runtime/Identifier.cpp index 5700e3dc3e8ba..bbd568bd8ca62 100644 --- a/Source/JavaScriptCore/runtime/Identifier.cpp +++ b/Source/JavaScriptCore/runtime/Identifier.cpp @@ -27,10 +27,10 @@ namespace JSC { -Ref Identifier::add8(VM& vm, std::span s) +Ref Identifier::add8(VM& vm, std::span s) { if (s.size() == 1) { - UChar c = s.front(); + char16_t c = s.front(); ASSERT(isLatin1(c)); if (canUseSingleCharacterString(c)) return vm.smallStrings.singleCharacterStringRep(c); diff --git a/Source/JavaScriptCore/runtime/Identifier.h b/Source/JavaScriptCore/runtime/Identifier.h index 568931a639ef3..5632283dc1ea9 100644 --- a/Source/JavaScriptCore/runtime/Identifier.h +++ b/Source/JavaScriptCore/runtime/Identifier.h @@ -112,8 +112,8 @@ class Identifier { // Use fromUid when constructing Identifier from StringImpl* which may represent symbols. static Identifier fromString(VM&, ASCIILiteral); - static Identifier fromString(VM&, std::span); - static Identifier fromString(VM&, std::span); + static Identifier fromString(VM&, std::span); + static Identifier fromString(VM&, std::span); static Identifier fromString(VM&, const String&); static Identifier fromString(VM&, AtomStringImpl*); static Identifier fromString(VM&, Ref&&); @@ -125,7 +125,7 @@ class Identifier { static Identifier fromUid(const PrivateName&); static Identifier fromUid(SymbolImpl&); - static Identifier createLCharFromUChar(VM& vm, std::span string) { return Identifier(vm, add8(vm, string)); } + static Identifier createLCharFromUChar(VM& vm, std::span string) { return Identifier(vm, add8(vm, string)); } JS_EXPORT_PRIVATE static Identifier from(VM&, unsigned y); JS_EXPORT_PRIVATE static Identifier from(VM&, int y); @@ -144,13 +144,9 @@ class Identifier { bool isPrivateName() const { return isSymbol() && static_cast(impl())->isPrivate(); } friend bool operator==(const Identifier&, const Identifier&); - friend bool operator==(const Identifier&, const LChar*); - friend bool operator==(const Identifier&, const char*); - static bool equal(const StringImpl*, const LChar*); - static inline bool equal(const StringImpl* a, const char* b) { return Identifier::equal(a, byteCast(b)); }; - static bool equal(const StringImpl*, std::span); - static bool equal(const StringImpl*, std::span); + static bool equal(const StringImpl*, std::span); + static bool equal(const StringImpl*, std::span); static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); } void dump(PrintStream&) const; @@ -158,8 +154,8 @@ class Identifier { private: AtomString m_string; - Identifier(VM& vm, std::span string) : m_string(add(vm, string)) { ASSERT(m_string.impl()->isAtom()); } - Identifier(VM& vm, std::span string) : m_string(add(vm, string)) { ASSERT(m_string.impl()->isAtom()); } + Identifier(VM& vm, std::span string) : m_string(add(vm, string)) { ASSERT(m_string.impl()->isAtom()); } + Identifier(VM& vm, std::span string) : m_string(add(vm, string)) { ASSERT(m_string.impl()->isAtom()); } ALWAYS_INLINE Identifier(VM& vm, ASCIILiteral literal) : m_string(add(vm, literal)) { ASSERT(m_string.impl()->isAtom()); } Identifier(VM&, AtomStringImpl*); Identifier(VM&, const AtomString&); @@ -175,10 +171,9 @@ class Identifier { { } static bool equal(const Identifier& a, const Identifier& b) { return a.m_string.impl() == b.m_string.impl(); } - static bool equal(const Identifier& a, const LChar* b) { return equal(a.m_string.impl(), b); } template static Ref add(VM&, std::span); - static Ref add8(VM&, std::span); + static Ref add8(VM&, std::span); template ALWAYS_INLINE static constexpr bool canUseSingleCharacterString(T); static Ref add(VM&, StringImpl*); @@ -191,13 +186,13 @@ class Identifier { #endif }; -template <> ALWAYS_INLINE constexpr bool Identifier::canUseSingleCharacterString(LChar) +template <> ALWAYS_INLINE constexpr bool Identifier::canUseSingleCharacterString(Latin1Character) { static_assert(maxSingleCharacterString == 0xff); return true; } -template <> ALWAYS_INLINE constexpr bool Identifier::canUseSingleCharacterString(UChar c) +template <> ALWAYS_INLINE constexpr bool Identifier::canUseSingleCharacterString(char16_t c) { return (c <= maxSingleCharacterString); } @@ -228,27 +223,12 @@ inline bool operator==(const Identifier& a, const Identifier& b) return Identifier::equal(a, b); } -inline bool operator==(const Identifier& a, const LChar* b) -{ - return Identifier::equal(a, b); -} - -inline bool operator==(const Identifier& a, const char* b) -{ - return Identifier::equal(a, byteCast(b)); -} - -inline bool Identifier::equal(const StringImpl* r, const LChar* s) -{ - return WTF::equal(r, s); -} - -inline bool Identifier::equal(const StringImpl* r, std::span s) +inline bool Identifier::equal(const StringImpl* r, std::span s) { return WTF::equal(r, s); } -inline bool Identifier::equal(const StringImpl* r, std::span s) +inline bool Identifier::equal(const StringImpl* r, std::span s) { return WTF::equal(r, s); } diff --git a/Source/JavaScriptCore/runtime/IdentifierInlines.h b/Source/JavaScriptCore/runtime/IdentifierInlines.h index 05dc8f0231f30..69e876ef06e34 100644 --- a/Source/JavaScriptCore/runtime/IdentifierInlines.h +++ b/Source/JavaScriptCore/runtime/IdentifierInlines.h @@ -85,12 +85,12 @@ ALWAYS_INLINE Identifier Identifier::fromString(VM& vm, ASCIILiteral s) return Identifier(vm, s); } -inline Identifier Identifier::fromString(VM& vm, std::span s) +inline Identifier Identifier::fromString(VM& vm, std::span s) { return Identifier(vm, s); } -inline Identifier Identifier::fromString(VM& vm, std::span s) +inline Identifier Identifier::fromString(VM& vm, std::span s) { return Identifier(vm, s); } diff --git a/Source/JavaScriptCore/runtime/IntlCache.cpp b/Source/JavaScriptCore/runtime/IntlCache.cpp index 0941a7278e2a0..d099acc9f2f4b 100644 --- a/Source/JavaScriptCore/runtime/IntlCache.cpp +++ b/Source/JavaScriptCore/runtime/IntlCache.cpp @@ -43,25 +43,25 @@ UDateTimePatternGenerator* IntlCache::cacheSharedPatternGenerator(const CString& return m_cachedDateTimePatternGenerator.get(); } -Vector IntlCache::getBestDateTimePattern(const CString& locale, std::span skeleton, UErrorCode& status) +Vector IntlCache::getBestDateTimePattern(const CString& locale, std::span skeleton, UErrorCode& status) { // Always use ICU date format generator, rather than our own pattern list and matcher. auto sharedGenerator = getSharedPatternGenerator(locale, status); if (U_FAILURE(status)) return { }; - Vector patternBuffer; + Vector patternBuffer; status = callBufferProducingFunction(udatpg_getBestPatternWithOptions, sharedGenerator, skeleton.data(), skeleton.size(), UDATPG_MATCH_HOUR_FIELD_LENGTH, patternBuffer); if (U_FAILURE(status)) return { }; return patternBuffer; } -Vector IntlCache::getFieldDisplayName(const CString& locale, UDateTimePatternField field, UDateTimePGDisplayWidth width, UErrorCode& status) +Vector IntlCache::getFieldDisplayName(const CString& locale, UDateTimePatternField field, UDateTimePGDisplayWidth width, UErrorCode& status) { auto sharedGenerator = getSharedPatternGenerator(locale, status); if (U_FAILURE(status)) return { }; - Vector buffer; + Vector buffer; status = callBufferProducingFunction(udatpg_getFieldDisplayName, sharedGenerator, field, width, buffer); if (U_FAILURE(status)) return { }; diff --git a/Source/JavaScriptCore/runtime/IntlCache.h b/Source/JavaScriptCore/runtime/IntlCache.h index 4c818fd59424f..2b31dc1bdd9c6 100644 --- a/Source/JavaScriptCore/runtime/IntlCache.h +++ b/Source/JavaScriptCore/runtime/IntlCache.h @@ -39,8 +39,8 @@ class IntlCache { public: IntlCache() = default; - Vector getBestDateTimePattern(const CString& locale, std::span skeleton, UErrorCode&); - Vector getFieldDisplayName(const CString& locale, UDateTimePatternField, UDateTimePGDisplayWidth, UErrorCode&); + Vector getBestDateTimePattern(const CString& locale, std::span skeleton, UErrorCode&); + Vector getFieldDisplayName(const CString& locale, UDateTimePatternField, UDateTimePGDisplayWidth, UErrorCode&); private: UDateTimePatternGenerator* getSharedPatternGenerator(const CString& locale, UErrorCode& status) diff --git a/Source/JavaScriptCore/runtime/IntlCollator.cpp b/Source/JavaScriptCore/runtime/IntlCollator.cpp index d9073a65bdcd2..6cbeb03aed285 100644 --- a/Source/JavaScriptCore/runtime/IntlCollator.cpp +++ b/Source/JavaScriptCore/runtime/IntlCollator.cpp @@ -444,10 +444,10 @@ void IntlCollator::checkICULocaleInvariants(const LocaleSet& locales) bool allAreGood = true; for (unsigned x = 0; x < 128; ++x) { for (unsigned y = 0; y < 128; ++y) { - if (canUseASCIIUCADUCETComparison(static_cast(x)) && canUseASCIIUCADUCETComparison(static_cast(y))) { + if (canUseASCIIUCADUCETComparison(static_cast(x)) && canUseASCIIUCADUCETComparison(static_cast(y))) { UErrorCode status = U_ZERO_ERROR; - UChar xstring[] = { static_cast(x), 0 }; - UChar ystring[] = { static_cast(y), 0 }; + char16_t xstring[] = { static_cast(x), 0 }; + char16_t ystring[] = { static_cast(y), 0 }; auto resultICU = ucol_strcoll(&collator, xstring, 1, ystring, 1); ASSERT(U_SUCCESS(status)); auto resultJSC = compareASCIIWithUCADUCET(span(*xstring), span(*ystring)); @@ -489,7 +489,7 @@ void IntlCollator::checkICULocaleInvariants(const LocaleSet& locales) // Contractions and Expansions are defined as a rule. If there is no tailoring rule, then they should be UCA DUCET's default. auto ensureNotIncludingASCII = [&](USet& set) { - Vector buffer; + Vector buffer; for (int32_t index = 0, count = uset_getItemCount(&set); index < count; ++index) { // start and end are inclusive. UChar32 start = 0; diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp index 2f23716496678..2963594bc77bc 100644 --- a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp +++ b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp @@ -118,8 +118,8 @@ static String canonicalizeTimeZoneName(const String& timeZoneName) do { status = U_ZERO_ERROR; int32_t ianaTimeZoneLength; - // Time zone names are represented as UChar[] in all related ICU APIs. - const UChar* ianaTimeZone = uenum_unext(timeZones, &ianaTimeZoneLength, &status); + // Time zone names are represented as char16_t[] in all related ICU APIs. + const char16_t* ianaTimeZone = uenum_unext(timeZones, &ianaTimeZoneLength, &status); ASSERT(U_SUCCESS(status)); // End of enumeration. @@ -135,7 +135,7 @@ static String canonicalizeTimeZoneName(const String& timeZoneName) // 1. Let ianaTimeZone be the Zone or Link name of the IANA Time Zone Database such that timeZone, converted to upper case as described in 6.1, is equal to ianaTimeZone, converted to upper case as described in 6.1. // 2. If ianaTimeZone is a Link name, then let ianaTimeZone be the corresponding Zone name as specified in the “backward” file of the IANA Time Zone Database. - Vector buffer; + Vector buffer; auto status = callBufferProducingFunction(ucal_getCanonicalTimeZoneID, ianaTimeZone, ianaTimeZoneLength, buffer, nullptr); ASSERT_UNUSED(status, U_SUCCESS(status)); canonical = String(buffer); @@ -371,7 +371,7 @@ IntlDateTimeFormat::HourCycle IntlDateTimeFormat::parseHourCycle(const String& h return HourCycle::None; } -inline IntlDateTimeFormat::HourCycle IntlDateTimeFormat::hourCycleFromSymbol(UChar symbol) +inline IntlDateTimeFormat::HourCycle IntlDateTimeFormat::hourCycleFromSymbol(char16_t symbol) { switch (symbol) { case 'K': @@ -386,7 +386,7 @@ inline IntlDateTimeFormat::HourCycle IntlDateTimeFormat::hourCycleFromSymbol(UCh return HourCycle::None; } -IntlDateTimeFormat::HourCycle IntlDateTimeFormat::hourCycleFromPattern(const Vector& pattern) +IntlDateTimeFormat::HourCycle IntlDateTimeFormat::hourCycleFromPattern(const Vector& pattern) { for (unsigned i = 0, length = pattern.size(); i < length; ++i) { auto character = pattern[i]; @@ -407,9 +407,9 @@ IntlDateTimeFormat::HourCycle IntlDateTimeFormat::hourCycleFromPattern(const Vec return HourCycle::None; } -inline void IntlDateTimeFormat::replaceHourCycleInSkeleton(Vector& skeleton, bool isHour12) +inline void IntlDateTimeFormat::replaceHourCycleInSkeleton(Vector& skeleton, bool isHour12) { - UChar skeletonCharacter = 'H'; + char16_t skeletonCharacter = 'H'; if (isHour12) skeletonCharacter = 'h'; for (unsigned i = 0, length = skeleton.size(); i < length; ++i) { @@ -432,9 +432,9 @@ inline void IntlDateTimeFormat::replaceHourCycleInSkeleton(Vector& sk } } -inline void IntlDateTimeFormat::replaceHourCycleInPattern(Vector& pattern, HourCycle hourCycle) +inline void IntlDateTimeFormat::replaceHourCycleInPattern(Vector& pattern, HourCycle hourCycle) { - UChar hourFromHourCycle = 'H'; + char16_t hourFromHourCycle = 'H'; switch (hourCycle) { case HourCycle::H11: hourFromHourCycle = 'K'; @@ -558,7 +558,7 @@ String IntlDateTimeFormat::buildSkeleton(Weekday weekday, Era era, Year year, Mo // > hourCycle = h23: "H", plus modifying the resolved pattern to use the hour symbol "H". // > hourCycle = h24: "H", plus modifying the resolved pattern to use the hour symbol "k". // - UChar skeletonCharacter = 'j'; + char16_t skeletonCharacter = 'j'; if (hour12 == TriState::Indeterminate) { switch (hourCycle) { case HourCycle::None: @@ -810,7 +810,7 @@ void IntlDateTimeFormat::initializeDateTimeFormat(JSGlobalObject* globalObject, m_timeStyle = intlOption(globalObject, options, vm.propertyNames->timeStyle, { { "full"_s, DateTimeStyle::Full }, { "long"_s, DateTimeStyle::Long }, { "medium"_s, DateTimeStyle::Medium }, { "short"_s, DateTimeStyle::Short } }, "timeStyle must be \"full\", \"long\", \"medium\", or \"short\""_s, DateTimeStyle::None); RETURN_IF_EXCEPTION(scope, void()); - Vector patternBuffer; + Vector patternBuffer; if (m_dateStyle != DateTimeStyle::None || m_timeStyle != DateTimeStyle::None) { // 30. For each row in Table 1, except the header row, do // i. Let prop be the name given in the Property column of the row. @@ -887,7 +887,7 @@ void IntlDateTimeFormat::initializeDateTimeFormat(JSGlobalObject* globalObject, specifiedHour12 = isHour12(hourCycle); HourCycle extractedHourCycle = hourCycleFromPattern(patternBuffer); if (extractedHourCycle != HourCycle::None && isHour12(extractedHourCycle) != specifiedHour12) { - Vector skeleton; + Vector skeleton; auto status = callBufferProducingFunction(udatpg_getSkeleton, nullptr, patternBuffer.data(), patternBuffer.size(), skeleton); if (U_FAILURE(status)) { throwTypeError(globalObject, scope, "failed to initialize DateTimeFormat"_s); @@ -1264,7 +1264,7 @@ JSValue IntlDateTimeFormat::format(JSGlobalObject* globalObject, double value) c if (!std::isfinite(value)) return throwRangeError(globalObject, scope, "date value is not finite in DateTimeFormat format()"_s); - Vector result; + Vector result; auto status = callBufferProducingFunction(udat_format, m_dateFormat.get(), value, result, nullptr); if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "failed to format date value"_s); @@ -1352,7 +1352,7 @@ JSValue IntlDateTimeFormat::formatToParts(JSGlobalObject* globalObject, double v if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "failed to open field position iterator"_s); - Vector result; + Vector result; status = callBufferProducingFunction(udat_formatForFields, m_dateFormat.get(), value, result, fields.get()); if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "failed to format date value"_s); @@ -1412,7 +1412,7 @@ UDateIntervalFormat* IntlDateTimeFormat::createDateIntervalFormatIfNecessary(JSG if (m_dateIntervalFormat) return m_dateIntervalFormat.get(); - Vector pattern; + Vector pattern; { auto status = callBufferProducingFunction(udat_toPattern, m_dateFormat.get(), false, pattern); if (U_FAILURE(status)) { @@ -1421,7 +1421,7 @@ UDateIntervalFormat* IntlDateTimeFormat::createDateIntervalFormatIfNecessary(JSG } } - Vector skeleton; + Vector skeleton; { auto status = callBufferProducingFunction(udatpg_getSkeleton, nullptr, pattern.data(), pattern.size(), skeleton); if (U_FAILURE(status)) { @@ -1579,12 +1579,12 @@ JSValue IntlDateTimeFormat::formatRange(JSGlobalObject* globalObject, double sta RELEASE_AND_RETURN(scope, format(globalObject, startDate)); int32_t formattedStringLength = 0; - const UChar* formattedStringPointer = ufmtval_getString(formattedValue, &formattedStringLength, &status); + const char16_t* formattedStringPointer = ufmtval_getString(formattedValue, &formattedStringLength, &status); if (U_FAILURE(status)) { throwTypeError(globalObject, scope, "Failed to format date interval"_s); return { }; } - Vector buffer(std::span { formattedStringPointer, static_cast(formattedStringLength) }); + Vector buffer(std::span { formattedStringPointer, static_cast(formattedStringLength) }); replaceNarrowNoBreakSpaceOrThinSpaceWithNormalSpace(buffer); return jsString(vm, String(WTFMove(buffer))); @@ -1695,12 +1695,12 @@ JSValue IntlDateTimeFormat::formatRangeToParts(JSGlobalObject* globalObject, dou } int32_t formattedStringLength = 0; - const UChar* formattedStringPointer = ufmtval_getString(formattedValue, &formattedStringLength, &status); + const char16_t* formattedStringPointer = ufmtval_getString(formattedValue, &formattedStringLength, &status); if (U_FAILURE(status)) { throwTypeError(globalObject, scope, "Failed to format date interval"_s); return { }; } - Vector buffer(std::span { formattedStringPointer, static_cast(formattedStringLength) }); + Vector buffer(std::span { formattedStringPointer, static_cast(formattedStringLength) }); replaceNarrowNoBreakSpaceOrThinSpaceWithNormalSpace(buffer); StringView resultStringView(buffer.span()); diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h index b5f4f5d505b52..ba574586b67c1 100644 --- a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h +++ b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h @@ -85,7 +85,7 @@ class IntlDateTimeFormat final : public JSNonFinalObject { static IntlDateTimeFormat* unwrapForOldFunctions(JSGlobalObject*, JSValue); enum class HourCycle : uint8_t { None, H11, H12, H23, H24 }; - static HourCycle hourCycleFromPattern(const Vector&); + static HourCycle hourCycleFromPattern(const Vector&); private: IntlDateTimeFormat(VM&, Structure*); @@ -124,10 +124,10 @@ class IntlDateTimeFormat final : public JSNonFinalObject { static ASCIILiteral timeZoneNameString(TimeZoneName); static ASCIILiteral formatStyleString(DateTimeStyle); - static HourCycle hourCycleFromSymbol(UChar); + static HourCycle hourCycleFromSymbol(char16_t); static HourCycle parseHourCycle(const String&); - static void replaceHourCycleInSkeleton(Vector&, bool hour12); - static void replaceHourCycleInPattern(Vector&, HourCycle); + static void replaceHourCycleInSkeleton(Vector&, bool hour12); + static void replaceHourCycleInPattern(Vector&, HourCycle); static String buildSkeleton(Weekday, Era, Year, Month, Day, TriState, HourCycle, Hour, DayPeriod, Minute, Second, unsigned, TimeZoneName); using UDateFormatDeleter = ICUDeleter; diff --git a/Source/JavaScriptCore/runtime/IntlDisplayNames.cpp b/Source/JavaScriptCore/runtime/IntlDisplayNames.cpp index 8fd61d6cfbc8d..f95cd47f0c3e9 100644 --- a/Source/JavaScriptCore/runtime/IntlDisplayNames.cpp +++ b/Source/JavaScriptCore/runtime/IntlDisplayNames.cpp @@ -189,7 +189,7 @@ JSValue IntlDisplayNames::of(JSGlobalObject* globalObject, JSValue codeValue) co return { }; }; - Vector buffer; + Vector buffer; UErrorCode status = U_ZERO_ERROR; CString canonicalCode; switch (m_type) { @@ -249,7 +249,7 @@ JSValue IntlDisplayNames::of(JSGlobalObject* globalObject, JSValue codeValue) co } // 6. Let code be the result of mapping code to upper case as described in 6.1. - const UChar currency[4] = { + const char16_t currency[4] = { toASCIIUpper(code[0]), toASCIIUpper(code[1]), toASCIIUpper(code[2]), @@ -258,14 +258,14 @@ JSValue IntlDisplayNames::of(JSGlobalObject* globalObject, JSValue codeValue) co // The result of ucurr_getName is static string so that we do not need to free the result. int32_t length = 0; UBool isChoiceFormat = false; // We need to pass this, otherwise, we will see crash in ICU 64. - const UChar* result = ucurr_getName(currency, m_localeCString.data(), style, &isChoiceFormat, &length, &status); + const char16_t* result = ucurr_getName(currency, m_localeCString.data(), style, &isChoiceFormat, &length, &status); if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "Failed to query a display name."_s); // ucurr_getName returns U_USING_DEFAULT_WARNING if the display-name is not found. But U_USING_DEFAULT_WARNING is returned even if // narrow and short results are the same: narrow "USD" is "$" with U_USING_DEFAULT_WARNING since short "USD" is also "$". We need to check // result == currency to check whether ICU actually failed to find the corresponding display-name. This pointer comparison is ensured by // ICU API document. - // > Returns pointer to display string of 'len' UChars. If the resource data contains no entry for 'currency', then 'currency' itself is returned. + // > Returns pointer to display string of 'len' char16_ts. If the resource data contains no entry for 'currency', then 'currency' itself is returned. if (status == U_USING_DEFAULT_WARNING && result == currency) return (m_fallback == Fallback::None) ? jsUndefined() : jsString(vm, StringView({ currency, 3 })); return jsString(vm, String({ result, static_cast(length) })); diff --git a/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp b/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp index 78e9106ee0a4a..f7d35b8e39015 100644 --- a/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp +++ b/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp @@ -305,7 +305,7 @@ static String retrieveSeparator(const CString& locale, const String& numberingSy return fallbackTimeSeparator; int32_t length = 0; - const UChar* data = ures_getStringByKey(symbolsBundle.get(), "timeSeparator", &length, &status); + const char16_t* data = ures_getStringByKey(symbolsBundle.get(), "timeSeparator", &length, &status); if (U_FAILURE(status)) return fallbackTimeSeparator; @@ -345,7 +345,7 @@ static DurationSignType getDurationSign(ISO8601::Duration duration) static String int128ToString(Int128 value) { - Vector resultString; + Vector resultString; bool isNegative = value < 0; if (isNegative) value = -value; @@ -489,7 +489,7 @@ static Vector collectElements(JSGlobalObject* globalObject, const IntlD auto scope = DECLARE_THROW_SCOPE(vm); UErrorCode status = U_ZERO_ERROR; - Vector buffer; + Vector buffer; status = callBufferProducingFunction(unumf_resultToString, formattedNumber, buffer); if (U_FAILURE(status)) { throwTypeError(globalObject, scope, "Failed to format a number."_s); @@ -688,7 +688,7 @@ JSValue IntlDurationFormat::format(JSGlobalObject* globalObject, ISO8601::Durati ListFormatInput input(WTFMove(stringList)); - Vector result; + Vector result; auto status = callBufferProducingFunction(ulistfmt_format, m_listFormat.get(), input.stringPointers(), input.stringLengths(), input.size(), result); if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "failed to format list of strings"_s); @@ -766,7 +766,7 @@ JSValue IntlDurationFormat::formatToParts(JSGlobalObject* globalObject, ISO8601: return throwOutOfMemoryError(globalObject, scope); int32_t formattedStringLength = 0; - const UChar* formattedStringPointer = ufmtval_getString(formattedValue, &formattedStringLength, &status); + const char16_t* formattedStringPointer = ufmtval_getString(formattedValue, &formattedStringLength, &status); if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "failed to format list of strings"_s); StringView resultStringView(std::span(formattedStringPointer, formattedStringLength)); diff --git a/Source/JavaScriptCore/runtime/IntlListFormat.cpp b/Source/JavaScriptCore/runtime/IntlListFormat.cpp index c25cc5f9e90fa..c24073ce31711 100644 --- a/Source/JavaScriptCore/runtime/IntlListFormat.cpp +++ b/Source/JavaScriptCore/runtime/IntlListFormat.cpp @@ -185,7 +185,7 @@ JSValue IntlListFormat::format(JSGlobalObject* globalObject, JSValue list) const ListFormatInput input(WTFMove(stringList)); - Vector result; + Vector result; auto status = callBufferProducingFunction(ulistfmt_format, m_listFormat.get(), input.stringPointers(), input.stringLengths(), input.size(), result); if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "failed to format list of strings"_s); @@ -229,7 +229,7 @@ JSValue IntlListFormat::formatToParts(JSGlobalObject* globalObject, JSValue list return throwOutOfMemoryError(globalObject, scope); int32_t formattedStringLength = 0; - const UChar* formattedStringPointer = ufmtval_getString(formattedValue, &formattedStringLength, &status); + const char16_t* formattedStringPointer = ufmtval_getString(formattedValue, &formattedStringLength, &status); if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "failed to format list of strings"_s); StringView resultStringView(std::span(formattedStringPointer, formattedStringLength)); diff --git a/Source/JavaScriptCore/runtime/IntlLocale.cpp b/Source/JavaScriptCore/runtime/IntlLocale.cpp index 60b7402ef1801..b65a7a9533bb5 100644 --- a/Source/JavaScriptCore/runtime/IntlLocale.cpp +++ b/Source/JavaScriptCore/runtime/IntlLocale.cpp @@ -180,7 +180,7 @@ bool LocaleIDBuilder::setKeywordValue(ASCIILiteral key, StringView value) ASSERT(value.containsOnlyASCII()); Vector rawValue(value.length() + 1); - value.getCharacters(byteCast(rawValue.mutableSpan())); + value.getCharacters(byteCast(rawValue.mutableSpan())); rawValue[value.length()] = '\0'; UErrorCode status = U_ZERO_ERROR; @@ -676,8 +676,8 @@ JSArray* IntlLocale::hourCycles(JSGlobalObject* globalObject) } // Use "j" skeleton and parse pattern to retrieve the configured hour-cycle information. - constexpr const UChar skeleton[] = { 'j', 0 }; - Vector pattern; + constexpr const char16_t skeleton[] = { 'j', 0 }; + Vector pattern; status = callBufferProducingFunction(udatpg_getBestPatternWithOptions, generator.get(), skeleton, 1, UDATPG_MATCH_HOUR_FIELD_LENGTH, pattern); if (!U_SUCCESS(status)) { throwTypeError(globalObject, scope, "invalid locale"_s); diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp b/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp index 1f0aa041c2018..efdcfcf626aed 100644 --- a/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp +++ b/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp @@ -694,7 +694,7 @@ JSValue IntlNumberFormat::format(JSGlobalObject* globalObject, double value) con value = purifyNaN(value); - Vector buffer; + Vector buffer; #if HAVE(ICU_U_NUMBER_FORMATTER) ASSERT(m_numberFormatter); UErrorCode status = U_ZERO_ERROR; @@ -725,7 +725,7 @@ JSValue IntlNumberFormat::format(JSGlobalObject* globalObject, IntlMathematicalV value.ensureNonDouble(); const auto& string = value.getString(); - Vector buffer; + Vector buffer; #if HAVE(ICU_U_NUMBER_FORMATTER) ASSERT(m_numberFormatter); UErrorCode status = U_ZERO_ERROR; @@ -772,7 +772,7 @@ JSValue IntlNumberFormat::formatRange(JSGlobalObject* globalObject, double start return throwTypeError(globalObject, scope, "failed to format a range"_s); int32_t length = 0; - const UChar* string = ufmtval_getString(formattedValue, &length, &status); + const char16_t* string = ufmtval_getString(formattedValue, &length, &status); if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "failed to format a range"_s); @@ -809,7 +809,7 @@ JSValue IntlNumberFormat::formatRange(JSGlobalObject* globalObject, IntlMathemat return throwTypeError(globalObject, scope, "failed to format a range"_s); int32_t length = 0; - const UChar* string = ufmtval_getString(formattedValue, &length, &status); + const char16_t* string = ufmtval_getString(formattedValue, &length, &status); if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "failed to format a range"_s); @@ -955,7 +955,7 @@ void IntlNumberFormat::formatRangeToPartsInternal(JSGlobalObject* globalObject, UErrorCode status = U_ZERO_ERROR; int32_t formattedStringLength = 0; - const UChar* formattedStringPointer = ufmtval_getString(formattedValue, &formattedStringLength, &status); + const char16_t* formattedStringPointer = ufmtval_getString(formattedValue, &formattedStringLength, &status); if (U_FAILURE(status)) { throwTypeError(globalObject, scope, "Failed to format number range"_s); return; @@ -1467,7 +1467,7 @@ JSValue IntlNumberFormat::formatToParts(JSGlobalObject* globalObject, double val if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "failed to open field position iterator"_s); - Vector result; + Vector result; #if HAVE(ICU_U_NUMBER_FORMATTER) ASSERT(m_numberFormatter); auto formattedNumber = std::unique_ptr>(unumf_openResult(&status)); @@ -1517,7 +1517,7 @@ JSValue IntlNumberFormat::formatToParts(JSGlobalObject* globalObject, IntlMathem if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "failed to open field position iterator"_s); - Vector result; + Vector result; ASSERT(m_numberFormatter); auto formattedNumber = std::unique_ptr>(unumf_openResult(&status)); if (U_FAILURE(status)) diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormatInlines.h b/Source/JavaScriptCore/runtime/IntlNumberFormatInlines.h index 980da4e3c74ab..cb0f52aa00ec7 100644 --- a/Source/JavaScriptCore/runtime/IntlNumberFormatInlines.h +++ b/Source/JavaScriptCore/runtime/IntlNumberFormatInlines.h @@ -235,7 +235,7 @@ void appendNumberFormatDigitOptionsToSkeleton(IntlType* intlInstance, StringBuil if (intlInstance->m_roundingIncrement != 1) { skeletonBuilder.append(" precision-increment/"_s); - auto string = numberToStringUnsigned>(intlInstance->m_roundingIncrement); + auto string = numberToStringUnsigned>(intlInstance->m_roundingIncrement); if (intlInstance->m_maximumFractionDigits >= string.size()) { skeletonBuilder.append("0."_s); for (unsigned i = 0; i < (intlInstance->m_maximumFractionDigits - string.size()); ++i) diff --git a/Source/JavaScriptCore/runtime/IntlObject.cpp b/Source/JavaScriptCore/runtime/IntlObject.cpp index 51dbe4447db38..4bc596c168e50 100644 --- a/Source/JavaScriptCore/runtime/IntlObject.cpp +++ b/Source/JavaScriptCore/runtime/IntlObject.cpp @@ -1145,9 +1145,9 @@ static VariantCode parseVariantCode(StringView string) ASSERT(string.length() <= 8); ASSERT(string.length() >= 1); struct Code { - LChar characters[8] { }; + Latin1Character characters[8] { }; }; - static_assert(std::is_unsigned_v); + static_assert(std::is_unsigned_v); static_assert(sizeof(VariantCode) == sizeof(Code)); Code code { }; for (unsigned index = 0; index < string.length(); ++index) @@ -1158,7 +1158,7 @@ static VariantCode parseVariantCode(StringView string) return result; } -static unsigned convertToUnicodeSingletonIndex(UChar singleton) +static unsigned convertToUnicodeSingletonIndex(char16_t singleton) { ASSERT(isASCIIAlphanumeric(singleton)); singleton = toASCIILower(singleton); @@ -1445,7 +1445,7 @@ bool LanguageTagParser::parseExtensionsAndPUExtensions() while (true) { if (m_current.length() != 1) return true; - UChar prefixCode = m_current[0]; + char16_t prefixCode = m_current[0]; if (!isASCIIAlphanumeric(prefixCode)) return true; diff --git a/Source/JavaScriptCore/runtime/IntlObjectInlines.h b/Source/JavaScriptCore/runtime/IntlObjectInlines.h index 90e3ffae62c0b..775a26f8379d1 100644 --- a/Source/JavaScriptCore/runtime/IntlObjectInlines.h +++ b/Source/JavaScriptCore/runtime/IntlObjectInlines.h @@ -198,17 +198,17 @@ ResultType intlStringOrBooleanOption(JSGlobalObject* globalObject, JSObject* opt return { }; } -ALWAYS_INLINE bool canUseASCIIUCADUCETComparison(UChar character) +ALWAYS_INLINE bool canUseASCIIUCADUCETComparison(char16_t character) { return isASCII(character) && ducetLevel1Weights[character]; } -ALWAYS_INLINE bool canUseASCIIUCADUCETComparison(LChar character) +ALWAYS_INLINE bool canUseASCIIUCADUCETComparison(Latin1Character character) { return ducetLevel1Weights[character]; } -ALWAYS_INLINE bool followedByNonLatinCharacter(std::span characters, size_t index) +ALWAYS_INLINE bool followedByNonLatinCharacter(std::span characters, size_t index) { size_t nextIndex = index + 1; if (characters.size() > nextIndex) @@ -216,7 +216,7 @@ ALWAYS_INLINE bool followedByNonLatinCharacter(std::span characters return false; } -ALWAYS_INLINE bool followedByNonLatinCharacter(std::span, size_t) +ALWAYS_INLINE bool followedByNonLatinCharacter(std::span, size_t) { return false; } @@ -363,12 +363,12 @@ class ListFormatInput { } int32_t size() const { return m_stringPointers.size(); } - const UChar* const* stringPointers() const { return m_stringPointers.data(); } + const char16_t* const* stringPointers() const { return m_stringPointers.data(); } const int32_t* stringLengths() const { return m_stringLengths.data(); } private: Vector m_strings; - Vector m_stringPointers; + Vector m_stringPointers; Vector m_stringLengths; }; diff --git a/Source/JavaScriptCore/runtime/IntlPluralRules.cpp b/Source/JavaScriptCore/runtime/IntlPluralRules.cpp index af58373c78e81..801b7fcada51e 100644 --- a/Source/JavaScriptCore/runtime/IntlPluralRules.cpp +++ b/Source/JavaScriptCore/runtime/IntlPluralRules.cpp @@ -267,7 +267,7 @@ JSValue IntlPluralRules::select(JSGlobalObject* globalObject, double value) cons unumf_formatDouble(m_numberFormatter.get(), value, formattedNumber.get(), &status); if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "failed to select plural value"_s); - Vector buffer; + Vector buffer; status = callBufferProducingFunction(uplrules_selectFormatted, m_pluralRules.get(), formattedNumber.get(), buffer); if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "failed to select plural value"_s); @@ -302,7 +302,7 @@ JSValue IntlPluralRules::selectRange(JSGlobalObject* globalObject, double start, if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "failed to select range of plural value"_s); - Vector buffer; + Vector buffer; status = callBufferProducingFunction(uplrules_selectForRange, m_pluralRules.get(), range.get(), buffer); if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "failed to select plural value"_s); diff --git a/Source/JavaScriptCore/runtime/IntlRelativeTimeFormat.cpp b/Source/JavaScriptCore/runtime/IntlRelativeTimeFormat.cpp index d1ee95fc6a6c5..fd547b47e71ae 100644 --- a/Source/JavaScriptCore/runtime/IntlRelativeTimeFormat.cpp +++ b/Source/JavaScriptCore/runtime/IntlRelativeTimeFormat.cpp @@ -246,7 +246,7 @@ String IntlRelativeTimeFormat::formatInternal(JSGlobalObject* globalObject, doub auto formatRelativeTime = m_numeric ? ureldatefmt_formatNumeric : ureldatefmt_format; - Vector result; + Vector result; auto status = callBufferProducingFunction(formatRelativeTime, m_relativeDateTimeFormatter.get(), value, unitType.value(), result); if (UNLIKELY(U_FAILURE(status))) { throwTypeError(globalObject, scope, "failed to format relative time"_s); @@ -283,7 +283,7 @@ JSValue IntlRelativeTimeFormat::formatToParts(JSGlobalObject* globalObject, doub double absValue = std::abs(value); - Vector buffer; + Vector buffer; status = callBufferProducingFunction(unum_formatDoubleForFields, m_numberFormat.get(), absValue, buffer, iterator.get()); if (U_FAILURE(status)) return throwTypeError(globalObject, scope, "failed to format relative time"_s); diff --git a/Source/JavaScriptCore/runtime/IntlSegmentIterator.cpp b/Source/JavaScriptCore/runtime/IntlSegmentIterator.cpp index a0363f8e7fc8e..f854f52b0338f 100644 --- a/Source/JavaScriptCore/runtime/IntlSegmentIterator.cpp +++ b/Source/JavaScriptCore/runtime/IntlSegmentIterator.cpp @@ -37,7 +37,7 @@ namespace JSC { const ClassInfo IntlSegmentIterator::s_info = { "Object"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(IntlSegmentIterator) }; -IntlSegmentIterator* IntlSegmentIterator::create(VM& vm, Structure* structure, std::unique_ptr&& segmenter, Box> buffer, JSString* string, IntlSegmenter::Granularity granularity) +IntlSegmentIterator* IntlSegmentIterator::create(VM& vm, Structure* structure, std::unique_ptr&& segmenter, Box> buffer, JSString* string, IntlSegmenter::Granularity granularity) { auto* object = new (NotNull, allocateCell(vm)) IntlSegmentIterator(vm, structure, WTFMove(segmenter), WTFMove(buffer), granularity, string); object->finishCreation(vm); @@ -49,7 +49,7 @@ Structure* IntlSegmentIterator::createStructure(VM& vm, JSGlobalObject* globalOb return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } -IntlSegmentIterator::IntlSegmentIterator(VM& vm, Structure* structure, std::unique_ptr&& segmenter, Box>&& buffer, IntlSegmenter::Granularity granularity, JSString* string) +IntlSegmentIterator::IntlSegmentIterator(VM& vm, Structure* structure, std::unique_ptr&& segmenter, Box>&& buffer, IntlSegmenter::Granularity granularity, JSString* string) : Base(vm, structure) , m_segmenter(WTFMove(segmenter)) , m_buffer(WTFMove(buffer)) diff --git a/Source/JavaScriptCore/runtime/IntlSegmentIterator.h b/Source/JavaScriptCore/runtime/IntlSegmentIterator.h index a491ea48bedde..86638dfaf7384 100644 --- a/Source/JavaScriptCore/runtime/IntlSegmentIterator.h +++ b/Source/JavaScriptCore/runtime/IntlSegmentIterator.h @@ -47,7 +47,7 @@ class IntlSegmentIterator final : public JSNonFinalObject { return vm.intlSegmentIteratorSpace(); } - static IntlSegmentIterator* create(VM&, Structure*, std::unique_ptr&&, Box>, JSString*, IntlSegmenter::Granularity); + static IntlSegmentIterator* create(VM&, Structure*, std::unique_ptr&&, Box>, JSString*, IntlSegmenter::Granularity); static Structure* createStructure(VM&, JSGlobalObject*, JSValue); DECLARE_INFO; @@ -57,12 +57,12 @@ class IntlSegmentIterator final : public JSNonFinalObject { DECLARE_VISIT_CHILDREN; private: - IntlSegmentIterator(VM&, Structure*, std::unique_ptr&&, Box>&&, IntlSegmenter::Granularity, JSString*); + IntlSegmentIterator(VM&, Structure*, std::unique_ptr&&, Box>&&, IntlSegmenter::Granularity, JSString*); DECLARE_DEFAULT_FINISH_CREATION; std::unique_ptr m_segmenter; - Box> m_buffer; + Box> m_buffer; WriteBarrier m_string; IntlSegmenter::Granularity m_granularity; }; diff --git a/Source/JavaScriptCore/runtime/IntlSegmenter.cpp b/Source/JavaScriptCore/runtime/IntlSegmenter.cpp index ac04023761b90..fe9be8bfe37cc 100644 --- a/Source/JavaScriptCore/runtime/IntlSegmenter.cpp +++ b/Source/JavaScriptCore/runtime/IntlSegmenter.cpp @@ -123,7 +123,7 @@ JSValue IntlSegmenter::segment(JSGlobalObject* globalObject, JSValue stringValue return { }; } - auto upconvertedCharacters = Box>::create(expectedCharacters.value()); + auto upconvertedCharacters = Box>::create(expectedCharacters.value()); UErrorCode status = U_ZERO_ERROR; auto segmenter = std::unique_ptr(cloneUBreakIterator(m_segmenter.get(), &status)); diff --git a/Source/JavaScriptCore/runtime/IntlSegments.cpp b/Source/JavaScriptCore/runtime/IntlSegments.cpp index cac69283bc6e4..4244ff4096204 100644 --- a/Source/JavaScriptCore/runtime/IntlSegments.cpp +++ b/Source/JavaScriptCore/runtime/IntlSegments.cpp @@ -39,7 +39,7 @@ namespace JSC { const ClassInfo IntlSegments::s_info = { "Object"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(IntlSegments) }; -IntlSegments* IntlSegments::create(VM& vm, Structure* structure, std::unique_ptr&& segmenter, Box>&& buffer, JSString* string, IntlSegmenter::Granularity granularity) +IntlSegments* IntlSegments::create(VM& vm, Structure* structure, std::unique_ptr&& segmenter, Box>&& buffer, JSString* string, IntlSegmenter::Granularity granularity) { auto* object = new (NotNull, allocateCell(vm)) IntlSegments(vm, structure, WTFMove(segmenter), WTFMove(buffer), granularity, string); object->finishCreation(vm); @@ -51,7 +51,7 @@ Structure* IntlSegments::createStructure(VM& vm, JSGlobalObject* globalObject, J return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } -IntlSegments::IntlSegments(VM& vm, Structure* structure, std::unique_ptr&& segmenter, Box>&& buffer, IntlSegmenter::Granularity granularity, JSString* string) +IntlSegments::IntlSegments(VM& vm, Structure* structure, std::unique_ptr&& segmenter, Box>&& buffer, IntlSegmenter::Granularity granularity, JSString* string) : Base(vm, structure) , m_segmenter(WTFMove(segmenter)) , m_buffer(WTFMove(buffer)) diff --git a/Source/JavaScriptCore/runtime/IntlSegments.h b/Source/JavaScriptCore/runtime/IntlSegments.h index 750da050409c1..f062546867b23 100644 --- a/Source/JavaScriptCore/runtime/IntlSegments.h +++ b/Source/JavaScriptCore/runtime/IntlSegments.h @@ -46,7 +46,7 @@ class IntlSegments final : public JSNonFinalObject { return vm.intlSegmentsSpace(); } - static IntlSegments* create(VM&, Structure*, std::unique_ptr&&, Box>&&, JSString*, IntlSegmenter::Granularity); + static IntlSegments* create(VM&, Structure*, std::unique_ptr&&, Box>&&, JSString*, IntlSegmenter::Granularity); static Structure* createStructure(VM&, JSGlobalObject*, JSValue); DECLARE_INFO; @@ -57,12 +57,12 @@ class IntlSegments final : public JSNonFinalObject { DECLARE_VISIT_CHILDREN; private: - IntlSegments(VM&, Structure*, std::unique_ptr&&, Box>&&, IntlSegmenter::Granularity, JSString*); + IntlSegments(VM&, Structure*, std::unique_ptr&&, Box>&&, IntlSegmenter::Granularity, JSString*); DECLARE_DEFAULT_FINISH_CREATION; std::unique_ptr m_segmenter; - Box> m_buffer; + Box> m_buffer; WriteBarrier m_string; IntlSegmenter::Granularity m_granularity; }; diff --git a/Source/JavaScriptCore/runtime/JSBigInt.cpp b/Source/JavaScriptCore/runtime/JSBigInt.cpp index ac791318eff86..4e88511314ba9 100644 --- a/Source/JavaScriptCore/runtime/JSBigInt.cpp +++ b/Source/JavaScriptCore/runtime/JSBigInt.cpp @@ -2273,7 +2273,7 @@ String JSBigInt::toStringBasePowerOfTwo(VM& vm, JSGlobalObject* nullOrGlobalObje return String(); } - Vector resultString(charsRequired); + Vector resultString(charsRequired); Digit digit = 0; // Keeps track of how many unprocessed bits there are in {digit}. unsigned availableBits = 0; @@ -2312,7 +2312,7 @@ String JSBigInt::toStringGeneric(VM& vm, JSGlobalObject* nullOrGlobalObjectForOO { // FIXME: [JSC] Revisit usage of Vector into JSBigInt::toString // https://bugs.webkit.org/show_bug.cgi?id=180671 - Vector resultString; + Vector resultString; ASSERT(radix >= 2 && radix <= 36); ASSERT(!x->isZero()); diff --git a/Source/JavaScriptCore/runtime/JSDateMath.cpp b/Source/JavaScriptCore/runtime/JSDateMath.cpp index 1eb8995b135cb..ce82f6138ae8c 100644 --- a/Source/JavaScriptCore/runtime/JSDateMath.cpp +++ b/Source/JavaScriptCore/runtime/JSDateMath.cpp @@ -501,13 +501,13 @@ String DateCache::timeZoneDisplayName(bool isDST) auto& timeZoneCache = *this->timeZoneCache(); CString language = defaultLanguage().utf8(); { - Vector standardDisplayNameBuffer; + Vector standardDisplayNameBuffer; auto status = callBufferProducingFunction(ucal_getTimeZoneDisplayName, timeZoneCache.m_calendar.get(), UCAL_STANDARD, language.data(), standardDisplayNameBuffer); if (U_SUCCESS(status)) m_timeZoneStandardDisplayNameCache = String::adopt(WTFMove(standardDisplayNameBuffer)); } { - Vector dstDisplayNameBuffer; + Vector dstDisplayNameBuffer; auto status = callBufferProducingFunction(ucal_getTimeZoneDisplayName, timeZoneCache.m_calendar.get(), UCAL_DST, language.data(), dstDisplayNameBuffer); if (U_SUCCESS(status)) m_timeZoneDSTDisplayNameCache = String::adopt(WTFMove(dstDisplayNameBuffer)); @@ -555,10 +555,10 @@ DateCache::DateCache() #endif } -static std::tuple> retrieveTimeZoneInformation() +static std::tuple> retrieveTimeZoneInformation() { Locker locker { timeZoneCacheLock }; - static NeverDestroyed, uint64_t>> globalCache; + static NeverDestroyed, uint64_t>> globalCache; bool isCacheStale = true; uint64_t currentID = 0; @@ -567,7 +567,7 @@ static std::tuple> retrieveTimeZoneInformation() isCacheStale = std::get<2>(globalCache.get()) != currentID; #endif if (isCacheStale) { - Vector timeZoneID; + Vector timeZoneID; getTimeZoneOverride(timeZoneID); String canonical; UErrorCode status = U_ZERO_ERROR; @@ -576,7 +576,7 @@ static std::tuple> retrieveTimeZoneInformation() ASSERT_UNUSED(status, U_SUCCESS(status)); } if (U_SUCCESS(status)) { - Vector canonicalBuffer; + Vector canonicalBuffer; auto status = callBufferProducingFunction(ucal_getCanonicalTimeZoneID, timeZoneID.data(), timeZoneID.size(), canonicalBuffer, nullptr); if (U_SUCCESS(status)) canonical = String(canonicalBuffer); diff --git a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructor.cpp b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructor.cpp index 4ecd99085db8e..2e3a8857df684 100644 --- a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructor.cpp +++ b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructor.cpp @@ -199,12 +199,12 @@ inline static WARN_UNUSED_RETURN size_t decodeHexImpl(std::span s return WTF::notFound; } -WARN_UNUSED_RETURN size_t decodeHex(std::span span, std::span result) +WARN_UNUSED_RETURN size_t decodeHex(std::span span, std::span result) { return decodeHexImpl(span, result); } -WARN_UNUSED_RETURN size_t decodeHex(std::span span, std::span result) +WARN_UNUSED_RETURN size_t decodeHex(std::span span, std::span result) { return decodeHexImpl(span, result); } diff --git a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructor.h b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructor.h index 363ab192da243..4d04dc54471f1 100644 --- a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructor.h +++ b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructor.h @@ -150,7 +150,7 @@ class JSGenericTypedArrayViewConstructor final : public InternalFunction { JSC_DECLARE_HOST_FUNCTION(uint8ArrayConstructorFromBase64); JSC_DECLARE_HOST_FUNCTION(uint8ArrayConstructorFromHex); -WARN_UNUSED_RETURN size_t decodeHex(std::span, std::span result); -WARN_UNUSED_RETURN size_t decodeHex(std::span, std::span result); +WARN_UNUSED_RETURN size_t decodeHex(std::span, std::span result); +WARN_UNUSED_RETURN size_t decodeHex(std::span, std::span result); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototype.cpp b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototype.cpp index 8f0f14c3a4f2d..042161661de6b 100644 --- a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototype.cpp +++ b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototype.cpp @@ -231,9 +231,8 @@ JSC_DEFINE_HOST_FUNCTION(uint8ArrayPrototypeToHex, (JSGlobalObject* globalObject return { }; } - std::span buffer; + std::span buffer; auto result = StringImpl::createUninitialized(length * 2, buffer); - LChar* bufferEnd = std::to_address(buffer.end()); constexpr size_t stride = 8; // Because loading uint8x8_t. if (length >= stride) { auto encodeVector = [&](auto input) { @@ -259,11 +258,10 @@ JSC_DEFINE_HOST_FUNCTION(uint8ArrayPrototypeToHex, (JSGlobalObject* globalObject }; const auto* cursor = data; - auto* output = buffer.data(); - for (; cursor + stride <= end; cursor += stride, output += stride * 2) + for (auto* output = byteCast(buffer.data()); cursor + stride <= end; cursor += stride, output += stride * 2) simde_vst1q_u8(output, encodeVector(simde_vld1_u8(cursor))); if (cursor < end) - simde_vst1q_u8(bufferEnd - stride * 2, encodeVector(simde_vld1_u8(end - stride))); + simde_vst1q_u8(byteCast(std::to_address(buffer.end())) - stride * 2, encodeVector(simde_vld1_u8(end - stride))); } else { const auto* cursor = data; auto* output = buffer.data(); diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp index eeb703b22585f..162cf03e9cbef 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp @@ -91,7 +91,7 @@ static JSValue encode(JSGlobalObject* globalObject, const WTF::BitSet<256>& doNo if (character < doNotEscape.size() && doNotEscape.get(character)) { // 4-c-i. Let S be a String containing only the code unit C. // 4-c-ii. Let R be a new String value computed by concatenating the previous value of R and S. - builder.append(static_cast(character)); + builder.append(static_cast(character)); continue; } @@ -125,7 +125,7 @@ static JSValue encode(JSGlobalObject* globalObject, const WTF::BitSet<256>& doNo } // 4-d-iv. Let Octets be the array of octets resulting by applying the UTF-8 transformation to V, and let L be the array size. - LChar utf8OctetsBuffer[U8_MAX_LENGTH]; + Latin1Character utf8OctetsBuffer[U8_MAX_LENGTH]; unsigned utf8Length = 0; // We can use U8_APPEND_UNSAFE here since codePoint is either // 1. non surrogate one, correct code point. @@ -166,7 +166,7 @@ static JSValue decode(JSGlobalObject* globalObject, std::span ch StringBuilder builder(OverflowPolicy::RecordOverflow); size_t k = 0; - UChar u = 0; + char16_t u = 0; while (k < characters.size()) { const CharType* p = characters.data() + k; CharType c = *p; @@ -201,7 +201,7 @@ static JSValue decode(JSGlobalObject* globalObject, std::span ch u = U16_TRAIL(character); } else { ASSERT(!U_IS_SURROGATE(character)); - u = static_cast(character); + u = static_cast(character); } } } @@ -215,10 +215,10 @@ static JSValue decode(JSGlobalObject* globalObject, std::span ch && isASCIIHexDigit(p[2]) && isASCIIHexDigit(p[3]) && isASCIIHexDigit(p[4]) && isASCIIHexDigit(p[5])) { charLen = 6; - u = Lexer::convertUnicode(p[2], p[3], p[4], p[5]); + u = Lexer::convertUnicode(p[2], p[3], p[4], p[5]); } } - if (charLen && (u >= 128 || !doNotUnescape.get(static_cast(u)))) { + if (charLen && (u >= 128 || !doNotUnescape.get(static_cast(u)))) { builder.append(u); k += charLen; continue; @@ -428,7 +428,7 @@ double jsToNumber(StringView s) static double parseFloat(StringView s) { if (s.length() == 1) { - UChar c = s[0]; + char16_t c = s[0]; if (isASCIIDigit(c)) return c - '0'; return PNaN; @@ -506,10 +506,10 @@ JSC_DEFINE_HOST_FUNCTION(globalFuncEval, (JSGlobalObject* globalObject, CallFram JSValue parsedObject; if (programSource.is8Bit()) { - LiteralParser preparser(globalObject, programSource.span8(), SloppyJSON, nullptr); + LiteralParser preparser(globalObject, programSource.span8(), SloppyJSON, nullptr); parsedObject = preparser.tryLiteralParse(); } else { - LiteralParser preparser(globalObject, programSource.span16(), SloppyJSON, nullptr); + LiteralParser preparser(globalObject, programSource.span16(), SloppyJSON, nullptr); parsedObject = preparser.tryLiteralParse(); } RETURN_IF_EXCEPTION(scope, encodedJSValue()); @@ -630,7 +630,7 @@ JSC_DEFINE_HOST_FUNCTION(globalFuncEscape, (JSGlobalObject* globalObject, CallFr for (auto character : view.span16()) { if (character >= doNotEscape.size()) builder.append("%u"_s, hex(static_cast(character >> 8), 2), hex(static_cast(character), 2)); - else if (doNotEscape.get(static_cast(character))) + else if (doNotEscape.get(static_cast(character))) builder.append(character); else builder.append('%', hex(character, 2)); @@ -661,17 +661,17 @@ JSC_DEFINE_HOST_FUNCTION(globalFuncUnescape, (JSGlobalObject* globalObject, Call if (view.is8Bit()) { auto characters = view.span8(); - LChar convertedLChar; + Latin1Character convertedLChar; while (k < length) { auto c = characters.subspan(k); if (c[0] == '%' && k <= length - 6 && c[1] == 'u') { if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) { - builder.append(Lexer::convertUnicode(c[2], c[3], c[4], c[5])); + builder.append(Lexer::convertUnicode(c[2], c[3], c[4], c[5])); k += 6; continue; } } else if (c[0] == '%' && k <= length - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) { - convertedLChar = LChar(Lexer::convertHex(c[1], c[2])); + convertedLChar = Latin1Character(Lexer::convertHex(c[1], c[2])); c = span(convertedLChar); k += 2; } @@ -683,15 +683,15 @@ JSC_DEFINE_HOST_FUNCTION(globalFuncUnescape, (JSGlobalObject* globalObject, Call while (k < length) { auto c = characters.subspan(k); - UChar convertedUChar; + char16_t convertedUChar; if (c[0] == '%' && k <= length - 6 && c[1] == 'u') { if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) { - convertedUChar = Lexer::convertUnicode(c[2], c[3], c[4], c[5]); + convertedUChar = Lexer::convertUnicode(c[2], c[3], c[4], c[5]); c = span(convertedUChar); k += 5; } } else if (c[0] == '%' && k <= length - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) { - convertedUChar = UChar(Lexer::convertHex(c[1], c[2])); + convertedUChar = char16_t(Lexer::convertHex(c[1], c[2])); c = span(convertedUChar); k += 2; } diff --git a/Source/JavaScriptCore/runtime/JSImmutableButterfly.cpp b/Source/JavaScriptCore/runtime/JSImmutableButterfly.cpp index 0456efb2297b8..974a711db864a 100644 --- a/Source/JavaScriptCore/runtime/JSImmutableButterfly.cpp +++ b/Source/JavaScriptCore/runtime/JSImmutableButterfly.cpp @@ -182,15 +182,15 @@ JSImmutableButterfly* JSImmutableButterfly::createFromString(JSGlobalObject* glo return result; } - auto forEachCodePointViaStringIteratorProtocol = [](std::span characters, auto func) { + auto forEachCodePointViaStringIteratorProtocol = [](std::span characters, auto func) { for (size_t i = 0; i < characters.size(); ++i) { - UChar character = characters[i]; + char16_t character = characters[i]; if (!U16_IS_LEAD(character) || (i + 1) == characters.size()) { if (func(i, 1) == IterationStatus::Done) return; continue; } - UChar second = characters[i + 1]; + char16_t second = characters[i + 1]; if (!U16_IS_TRAIL(second)) { if (func(i, 1) == IterationStatus::Done) return; @@ -224,7 +224,7 @@ JSImmutableButterfly* JSImmutableButterfly::createFromString(JSGlobalObject* glo value = jsSingleCharacterString(vm, characters[index]); else { ASSERT(size == 2); - const UChar string[2] = { + const char16_t string[2] = { characters[index], characters[index + 1], }; diff --git a/Source/JavaScriptCore/runtime/JSONAtomStringCache.h b/Source/JavaScriptCore/runtime/JSONAtomStringCache.h index f6f0c5e5f5552..6f5b72c915772 100644 --- a/Source/JavaScriptCore/runtime/JSONAtomStringCache.h +++ b/Source/JavaScriptCore/runtime/JSONAtomStringCache.h @@ -37,8 +37,8 @@ class JSONAtomStringCache { static constexpr auto capacity = 256; struct Slot { - UChar m_buffer[maxStringLengthForCache] { }; - UChar m_length { 0 }; + char16_t m_buffer[maxStringLengthForCache] { }; + char16_t m_length { 0 }; RefPtr m_impl; }; static_assert(sizeof(Slot) <= 64); @@ -62,7 +62,7 @@ class JSONAtomStringCache { template Ref make(std::span); - ALWAYS_INLINE Slot& cacheSlot(UChar firstCharacter, UChar lastCharacter, UChar length) + ALWAYS_INLINE Slot& cacheSlot(char16_t firstCharacter, char16_t lastCharacter, char16_t length) { unsigned hash = (firstCharacter << 6) ^ ((lastCharacter << 14) ^ firstCharacter); hash += (hash >> 14) + (length << 14); diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp index cf9d46506a1db..798e0957fb17b 100644 --- a/Source/JavaScriptCore/runtime/JSONObject.cpp +++ b/Source/JavaScriptCore/runtime/JSONObject.cpp @@ -829,7 +829,7 @@ inline unsigned FastStringifier::usableBufferSize(unsigned // to limit recursion. Hence, we need to compute an appropriate m_capacity value. // // To do this, we empirically measured the worst case stack usage incurred by 1 recursion - // of any of the append methods. Assuming each call to append() only consumes 1 LChar in + // of any of the append methods. Assuming each call to append() only consumes 1 Latin1Character in // m_buffer, the amount of buffer size that FastStringifier is allowed to run with can be // estimated as: // @@ -1128,12 +1128,12 @@ static ALWAYS_INLINE bool stringCopySameType(std::span span, Cha return false; } -static ALWAYS_INLINE bool stringCopyUpconvert(std::span span, UChar* cursor) +static ALWAYS_INLINE bool stringCopyUpconvert(std::span span, char16_t* cursor) { #if (CPU(ARM64) || CPU(X86_64)) && COMPILER(CLANG) - constexpr size_t stride = SIMD::stride; + constexpr size_t stride = SIMD::stride; if (span.size() >= stride) { - using UnsignedType = std::make_unsigned_t; + using UnsignedType = std::make_unsigned_t; using BulkType = decltype(SIMD::load(static_cast(nullptr))); constexpr auto quoteMask = SIMD::splat('"'); constexpr auto escapeMask = SIMD::splat('\\'); @@ -1490,21 +1490,21 @@ static NEVER_INLINE String stringify(JSGlobalObject& globalObject, JSValue value if (LIKELY(std::bit_cast(currentStackPointer()) >= stackLimit)) { std::optional failureReason; failureReason = std::nullopt; - if (String result = FastStringifier::stringify(globalObject, value, replacer, space, failureReason); !result.isNull()) + if (String result = FastStringifier::stringify(globalObject, value, replacer, space, failureReason); !result.isNull()) return result; if (failureReason == FailureReason::Found16BitEarly) { failureReason = std::nullopt; - if (String result = FastStringifier::stringify(globalObject, value, replacer, space, failureReason); !result.isNull()) + if (String result = FastStringifier::stringify(globalObject, value, replacer, space, failureReason); !result.isNull()) return result; if (failureReason == FailureReason::BufferFull) { failureReason = std::nullopt; - if (String result = FastStringifier::stringify(globalObject, value, replacer, space, failureReason); !result.isNull()) + if (String result = FastStringifier::stringify(globalObject, value, replacer, space, failureReason); !result.isNull()) return result; } } else if (failureReason == FailureReason::BufferFull) { failureReason = std::nullopt; - if (String result = FastStringifier::stringify(globalObject, value, replacer, space, failureReason); !result.isNull()) + if (String result = FastStringifier::stringify(globalObject, value, replacer, space, failureReason); !result.isNull()) return result; } } @@ -1812,7 +1812,7 @@ static NEVER_INLINE JSValue jsonParseSlow(JSGlobalObject* globalObject, JSString JSONRanges ranges; JSValue unfiltered; if (view.is8Bit()) { - LiteralParser jsonParser(globalObject, view.span8(), StrictJSON); + LiteralParser jsonParser(globalObject, view.span8(), StrictJSON); unfiltered = jsonParser.tryLiteralParse(Options::useJSONSourceTextAccess() ? &ranges : nullptr); EXCEPTION_ASSERT(!scope.exception() || !unfiltered); if (!unfiltered) { @@ -1821,7 +1821,7 @@ static NEVER_INLINE JSValue jsonParseSlow(JSGlobalObject* globalObject, JSString return { }; } } else { - LiteralParser jsonParser(globalObject, view.span16(), StrictJSON); + LiteralParser jsonParser(globalObject, view.span16(), StrictJSON); unfiltered = jsonParser.tryLiteralParse(Options::useJSONSourceTextAccess() ? &ranges : nullptr); EXCEPTION_ASSERT(!scope.exception() || !unfiltered); if (!unfiltered) { @@ -1854,7 +1854,7 @@ JSC_DEFINE_HOST_FUNCTION(jsonProtoFuncParse, (JSGlobalObject* globalObject, Call } if (view->is8Bit()) { - LiteralParser jsonParser(globalObject, view->span8(), StrictJSON); + LiteralParser jsonParser(globalObject, view->span8(), StrictJSON); JSValue unfiltered = jsonParser.tryLiteralParse(); EXCEPTION_ASSERT(!scope.exception() || !unfiltered); if (!unfiltered) { @@ -1864,7 +1864,7 @@ JSC_DEFINE_HOST_FUNCTION(jsonProtoFuncParse, (JSGlobalObject* globalObject, Call return JSValue::encode(unfiltered); } - LiteralParser jsonParser(globalObject, view->span16(), StrictJSON); + LiteralParser jsonParser(globalObject, view->span16(), StrictJSON); JSValue unfiltered = jsonParser.tryLiteralParse(); EXCEPTION_ASSERT(!scope.exception() || !unfiltered); if (!unfiltered) { @@ -1887,11 +1887,11 @@ JSValue JSONParse(JSGlobalObject* globalObject, StringView json) return JSValue(); if (json.is8Bit()) { - LiteralParser jsonParser(globalObject, json.span8(), StrictJSON); + LiteralParser jsonParser(globalObject, json.span8(), StrictJSON); return jsonParser.tryLiteralParse(); } - LiteralParser jsonParser(globalObject, json.span16(), StrictJSON); + LiteralParser jsonParser(globalObject, json.span16(), StrictJSON); return jsonParser.tryLiteralParse(); } @@ -1904,7 +1904,7 @@ JSValue JSONParseWithException(JSGlobalObject* globalObject, StringView json) return JSValue(); if (json.is8Bit()) { - LiteralParser jsonParser(globalObject, json.span8(), StrictJSON); + LiteralParser jsonParser(globalObject, json.span8(), StrictJSON); JSValue result = jsonParser.tryLiteralParse(); RETURN_IF_EXCEPTION(scope, { }); if (!result) @@ -1912,7 +1912,7 @@ JSValue JSONParseWithException(JSGlobalObject* globalObject, StringView json) return result; } - LiteralParser jsonParser(globalObject, json.span16(), StrictJSON); + LiteralParser jsonParser(globalObject, json.span16(), StrictJSON); JSValue result = jsonParser.tryLiteralParse(); RETURN_IF_EXCEPTION(scope, { }); if (!result) @@ -1946,7 +1946,7 @@ JSC_DEFINE_HOST_FUNCTION(jsonProtoFuncRawJSON, (JSGlobalObject* globalObject, Ca JSString* jsString = callFrame->argument(0).toString(globalObject); RETURN_IF_EXCEPTION(scope, { }); - auto isJSONWhitespace = [](UChar character) { + auto isJSONWhitespace = [](char16_t character) { return character == 0x0009 || character == 0x000A || character == 0x000D || character == 0x0020; }; @@ -1957,13 +1957,13 @@ JSC_DEFINE_HOST_FUNCTION(jsonProtoFuncRawJSON, (JSGlobalObject* globalObject, Ca return { }; } - UChar firstCharacter = string[0]; + char16_t firstCharacter = string[0]; if (UNLIKELY(isJSONWhitespace(firstCharacter))) { throwSyntaxError(globalObject, scope, makeString("JSON.rawJSON cannot accept string starting with '"_s, firstCharacter, "'"_s)); return { }; } - UChar lastCharacter = string[string.length() - 1]; + char16_t lastCharacter = string[string.length() - 1]; if (UNLIKELY(isJSONWhitespace(lastCharacter))) { throwSyntaxError(globalObject, scope, makeString("JSON.rawJSON cannot accept string ending with '"_s, lastCharacter, "'"_s)); return { }; @@ -1972,7 +1972,7 @@ JSC_DEFINE_HOST_FUNCTION(jsonProtoFuncRawJSON, (JSGlobalObject* globalObject, Ca { JSValue result; if (string.is8Bit()) { - LiteralParser jsonParser(globalObject, string.span8(), StrictJSON); + LiteralParser jsonParser(globalObject, string.span8(), StrictJSON); result = jsonParser.tryLiteralParsePrimitiveValue(); RETURN_IF_EXCEPTION(scope, { }); if (UNLIKELY(!result)) { @@ -1980,7 +1980,7 @@ JSC_DEFINE_HOST_FUNCTION(jsonProtoFuncRawJSON, (JSGlobalObject* globalObject, Ca return { }; } } else { - LiteralParser jsonParser(globalObject, string.span16(), StrictJSON); + LiteralParser jsonParser(globalObject, string.span16(), StrictJSON); result = jsonParser.tryLiteralParsePrimitiveValue(); RETURN_IF_EXCEPTION(scope, { }); if (UNLIKELY(!result)) { diff --git a/Source/JavaScriptCore/runtime/JSString.cpp b/Source/JavaScriptCore/runtime/JSString.cpp index e76be7f41078b..85c7f08bb6a52 100644 --- a/Source/JavaScriptCore/runtime/JSString.cpp +++ b/Source/JavaScriptCore/runtime/JSString.cpp @@ -169,13 +169,13 @@ AtomString JSRopeString::resolveRopeToAtomString(JSGlobalObject* globalObject) c uint8_t* stackLimit = std::bit_cast(vm.softStackLimit()); if (!isSubstring()) { if (is8Bit()) { - std::array buffer; + std::array buffer; resolveRopeInternalNoSubstring(std::span { buffer }.first(length()), stackLimit); - atomString = std::span { buffer }.first(length()); + atomString = std::span { buffer }.first(length()); } else { - std::array buffer; + std::array buffer; resolveRopeInternalNoSubstring(std::span { buffer }.first(length()), stackLimit); - atomString = std::span { buffer }.first(length()); + atomString = std::span { buffer }.first(length()); } } else atomString = StringView { substringBase()->valueInternal() }.substring(substringOffset(), length()).toAtomString(); @@ -209,11 +209,11 @@ RefPtr JSRopeString::resolveRopeToExistingAtomString(JSGlobalObj if (!isSubstring()) { uint8_t* stackLimit = std::bit_cast(vm.softStackLimit()); if (is8Bit()) { - std::array buffer; + std::array buffer; resolveRopeInternalNoSubstring(std::span { buffer }.first(length()), stackLimit); existingAtomString = AtomStringImpl::lookUp(std::span { buffer }.first(length())); } else { - std::array buffer; + std::array buffer; resolveRopeInternalNoSubstring(std::span { buffer }.first(length()), stackLimit); existingAtomString = AtomStringImpl::lookUp(std::span { buffer }.first(length())); } @@ -239,7 +239,7 @@ const String& JSRopeString::resolveRopeWithFunction(JSGlobalObject* nullOrGlobal } if (is8Bit()) { - std::span buffer; + std::span buffer; auto newImpl = StringImpl::tryCreateUninitialized(length(), buffer); if (!newImpl) { outOfMemory(nullOrGlobalObjectForOOM); @@ -255,7 +255,7 @@ const String& JSRopeString::resolveRopeWithFunction(JSGlobalObject* nullOrGlobal return valueInternal(); } - std::span buffer; + std::span buffer; auto newImpl = StringImpl::tryCreateUninitialized(length(), buffer); if (!newImpl) { outOfMemory(nullOrGlobalObjectForOOM); diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h index 3e6da6a20a60b..b11eba876594d 100644 --- a/Source/JavaScriptCore/runtime/JSString.h +++ b/Source/JavaScriptCore/runtime/JSString.h @@ -60,8 +60,8 @@ JSString* jsString(VM&, RefPtr&&); JSString* jsString(VM&, Ref&&); JSString* jsString(VM&, Ref&&); -JSString* jsSingleCharacterString(VM&, UChar); -JSString* jsSingleCharacterString(VM&, LChar); +JSString* jsSingleCharacterString(VM&, char16_t); +JSString* jsSingleCharacterString(VM&, Latin1Character); JSString* jsSubstring(VM&, const String&, unsigned offset, unsigned length); // Non-trivial strings are two or more characters long. @@ -272,7 +272,7 @@ class JSString : public JSCell { bool is8Bit() const; - ALWAYS_INLINE JSString* tryReplaceOneChar(JSGlobalObject*, UChar, JSString* replacement); + ALWAYS_INLINE JSString* tryReplaceOneChar(JSGlobalObject*, char16_t, JSString* replacement); bool isSubstring() const; protected: @@ -281,7 +281,7 @@ class JSString : public JSCell { JS_EXPORT_PRIVATE bool equalSlowCase(JSGlobalObject*, JSString* other) const; - inline JSString* tryReplaceOneCharImpl(JSGlobalObject*, UChar search, JSString* replacement, uint8_t* stackLimit, bool& found); + inline JSString* tryReplaceOneCharImpl(JSGlobalObject*, char16_t search, JSString* replacement, uint8_t* stackLimit, bool& found); uintptr_t fiberConcurrently() const { return m_fiber; } @@ -302,8 +302,8 @@ class JSString : public JSCell { friend JSString* jsString(JSGlobalObject*, JSString*, JSString*, JSString*); friend JSString* jsString(JSGlobalObject*, const String&, const String&, const String&); friend JS_EXPORT_PRIVATE JSString* jsStringWithCacheSlowCase(VM&, StringImpl&); - friend JSString* jsSingleCharacterString(VM&, UChar); - friend JSString* jsSingleCharacterString(VM&, LChar); + friend JSString* jsSingleCharacterString(VM&, char16_t); + friend JSString* jsSingleCharacterString(VM&, Latin1Character); friend JSString* jsNontrivialString(VM&, const String&); friend JSString* jsNontrivialString(VM&, String&&); friend JSString* jsSubstring(VM&, const String&, unsigned, unsigned); @@ -791,7 +791,7 @@ inline JSString* jsEmptyString(VM& vm) return vm.smallStrings.emptyString(); } -ALWAYS_INLINE JSString* jsSingleCharacterString(VM& vm, UChar c) +ALWAYS_INLINE JSString* jsSingleCharacterString(VM& vm, char16_t c) { if constexpr (validateDFGDoesGC) vm.verifyCanGC(); @@ -800,7 +800,7 @@ ALWAYS_INLINE JSString* jsSingleCharacterString(VM& vm, UChar c) return JSString::create(vm, StringImpl::create(std::span { &c, 1 })); } -ALWAYS_INLINE JSString* jsSingleCharacterString(VM& vm, LChar c) +ALWAYS_INLINE JSString* jsSingleCharacterString(VM& vm, Latin1Character c) { if constexpr (validateDFGDoesGC) vm.verifyCanGC(); diff --git a/Source/JavaScriptCore/runtime/JSStringInlines.h b/Source/JavaScriptCore/runtime/JSStringInlines.h index 4f67502e72474..5a9824745a03c 100644 --- a/Source/JavaScriptCore/runtime/JSStringInlines.h +++ b/Source/JavaScriptCore/runtime/JSStringInlines.h @@ -73,7 +73,7 @@ ALWAYS_INLINE bool JSString::equalInline(JSGlobalObject* globalObject, JSString* return WTF::equal(str1, str2, length); } -JSString* JSString::tryReplaceOneCharImpl(JSGlobalObject* globalObject, UChar search, JSString* replacement, uint8_t* stackLimit, bool& found) +JSString* JSString::tryReplaceOneCharImpl(JSGlobalObject* globalObject, char16_t search, JSString* replacement, uint8_t* stackLimit, bool& found) { VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); @@ -150,7 +150,7 @@ JSString* JSString::tryReplaceOneCharImpl(JSGlobalObject* globalObject, UChar se RELEASE_AND_RETURN(scope, jsString(globalObject, left, replacement, right)); } -JSString* JSString::tryReplaceOneChar(JSGlobalObject* globalObject, UChar search, JSString* replacement) +JSString* JSString::tryReplaceOneChar(JSGlobalObject* globalObject, char16_t search, JSString* replacement) { uint8_t* stackLimit = std::bit_cast(globalObject->vm().softStackLimit()); bool found = false; @@ -409,11 +409,11 @@ inline JSString* jsAtomString(JSGlobalObject* globalObject, VM& vm, JSString* st }; if (string->valueInternal().is8Bit()) { - WTF::HashTranslatorCharBuffer buffer { string->valueInternal().span8(), string->valueInternal().hash() }; + WTF::HashTranslatorCharBuffer buffer { string->valueInternal().span8(), string->valueInternal().hash() }; return vm.keyAtomStringCache.make(vm, buffer, createFromNonRope); } - WTF::HashTranslatorCharBuffer buffer { string->valueInternal().span16(), string->valueInternal().hash() }; + WTF::HashTranslatorCharBuffer buffer { string->valueInternal().span16(), string->valueInternal().hash() }; return vm.keyAtomStringCache.make(vm, buffer, createFromNonRope); } @@ -434,23 +434,23 @@ inline JSString* jsAtomString(JSGlobalObject* globalObject, VM& vm, JSString* st JSString* fiber1 = ropeString->fiber1(); JSString* fiber2 = ropeString->fiber2(); if (ropeString->is8Bit()) { - std::array characters; + std::array characters; JSRopeString::resolveToBuffer(fiber0, fiber1, fiber2, std::span { characters }.first(length), stackLimit); - WTF::HashTranslatorCharBuffer buffer { std::span { characters }.first(length) }; + WTF::HashTranslatorCharBuffer buffer { std::span { characters }.first(length) }; return vm.keyAtomStringCache.make(vm, buffer, createFromRope); } - std::array characters; + std::array characters; JSRopeString::resolveToBuffer(fiber0, fiber1, fiber2, std::span { characters }.first(length), stackLimit); - WTF::HashTranslatorCharBuffer buffer { std::span { characters }.first(length) }; + WTF::HashTranslatorCharBuffer buffer { std::span { characters }.first(length) }; return vm.keyAtomStringCache.make(vm, buffer, createFromRope); } auto view = StringView { ropeString->substringBase()->valueInternal() }.substring(ropeString->substringOffset(), length); if (view.is8Bit()) { - WTF::HashTranslatorCharBuffer buffer { view.span8() }; + WTF::HashTranslatorCharBuffer buffer { view.span8() }; return vm.keyAtomStringCache.make(vm, buffer, createFromRope); } - WTF::HashTranslatorCharBuffer buffer { view.span16() }; + WTF::HashTranslatorCharBuffer buffer { view.span16() }; return vm.keyAtomStringCache.make(vm, buffer, createFromRope); } @@ -523,14 +523,14 @@ inline JSString* jsAtomString(JSGlobalObject* globalObject, VM& vm, JSString* s1 }; if (s1->is8Bit() && s2->is8Bit()) { - LChar characters[KeyAtomStringCache::maxStringLengthForCache]; + Latin1Character characters[KeyAtomStringCache::maxStringLengthForCache]; resolveWith2Fibers(s1, s2, std::span { characters }.first(length)); - WTF::HashTranslatorCharBuffer buffer { std::span(characters).first(length) }; + WTF::HashTranslatorCharBuffer buffer { std::span(characters).first(length) }; return vm.keyAtomStringCache.make(vm, buffer, createFromFibers); } - UChar characters[KeyAtomStringCache::maxStringLengthForCache]; + char16_t characters[KeyAtomStringCache::maxStringLengthForCache]; resolveWith2Fibers(s1, s2, std::span(characters).first(length)); - WTF::HashTranslatorCharBuffer buffer { std::span(characters).first(length) }; + WTF::HashTranslatorCharBuffer buffer { std::span(characters).first(length) }; return vm.keyAtomStringCache.make(vm, buffer, createFromFibers); } @@ -582,14 +582,14 @@ inline JSString* jsAtomString(JSGlobalObject* globalObject, VM& vm, JSString* s1 }; if (s1->is8Bit() && s2->is8Bit() && s3->is8Bit()) { - LChar characters[KeyAtomStringCache::maxStringLengthForCache]; + Latin1Character characters[KeyAtomStringCache::maxStringLengthForCache]; resolveWith3Fibers(s1, s2, s3, std::span { characters }.first(length)); - WTF::HashTranslatorCharBuffer buffer { std::span { characters }.first(length) }; + WTF::HashTranslatorCharBuffer buffer { std::span { characters }.first(length) }; return vm.keyAtomStringCache.make(vm, buffer, createFromFibers); } - UChar characters[KeyAtomStringCache::maxStringLengthForCache]; + char16_t characters[KeyAtomStringCache::maxStringLengthForCache]; resolveWith3Fibers(s1, s2, s3, std::span { characters }.first(length)); - WTF::HashTranslatorCharBuffer buffer { std::span { characters }.first(length) }; + WTF::HashTranslatorCharBuffer buffer { std::span { characters }.first(length) }; return vm.keyAtomStringCache.make(vm, buffer, createFromFibers); } @@ -618,15 +618,15 @@ inline JSString* jsSubstringOfResolved(VM& vm, GCDeferralContext* deferralContex if (auto c = base.characterAt(offset); c <= maxSingleCharacterString) return vm.smallStrings.singleCharacterString(c); } else if (length == 2) { - UChar first = base.characterAt(offset); - UChar second = base.characterAt(offset + 1); + char16_t first = base.characterAt(offset); + char16_t second = base.characterAt(offset + 1); if ((first | second) < 0x80) { auto createFromSubstring = [&](VM& vm, auto& buffer) { auto impl = AtomStringImpl::add(buffer); return JSString::create(vm, deferralContext, impl.releaseNonNull()); }; - LChar buf[] = { static_cast(first), static_cast(second) }; - WTF::HashTranslatorCharBuffer buffer { std::span { buf, length } }; + Latin1Character buf[] = { static_cast(first), static_cast(second) }; + WTF::HashTranslatorCharBuffer buffer { std::span { buf, length } }; return vm.keyAtomStringCache.make(vm, buffer, createFromSubstring); } } diff --git a/Source/JavaScriptCore/runtime/JSStringJoiner.cpp b/Source/JavaScriptCore/runtime/JSStringJoiner.cpp index a0a84fe3ef8be..a3b373a308c03 100644 --- a/Source/JavaScriptCore/runtime/JSStringJoiner.cpp +++ b/Source/JavaScriptCore/runtime/JSStringJoiner.cpp @@ -38,7 +38,7 @@ JSStringJoiner::~JSStringJoiner() = default; template static inline void appendStringToData(std::span& data, StringView string) { - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { ASSERT(string.is8Bit()); string.getCharacters8(data); } else @@ -54,15 +54,15 @@ static inline void appendStringToData(std::span& data, std: } template -static inline void appendStringToDataWithOneCharacterSeparatorRepeatedly(std::span& data, UChar separatorCharacter, StringView string, unsigned count) +static inline void appendStringToDataWithOneCharacterSeparatorRepeatedly(std::span& data, char16_t separatorCharacter, StringView string, unsigned count) { #if OS(DARWIN) - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { ASSERT(string.is8Bit()); if (count > 4) { switch (string.length() + 1) { case 16: { - alignas(16) LChar pattern[16]; + alignas(16) Latin1Character pattern[16]; pattern[0] = separatorCharacter; string.getCharacters8(std::span { pattern }.subspan(1)); size_t fillLength = count * 16; @@ -71,7 +71,7 @@ static inline void appendStringToDataWithOneCharacterSeparatorRepeatedly(std::sp return; } case 8: { - alignas(8) LChar pattern[8]; + alignas(8) Latin1Character pattern[8]; pattern[0] = separatorCharacter; string.getCharacters8(std::span { pattern }.subspan(1)); size_t fillLength = count * 8; @@ -80,7 +80,7 @@ static inline void appendStringToDataWithOneCharacterSeparatorRepeatedly(std::sp return; } case 4: { - alignas(4) LChar pattern[4]; + alignas(4) Latin1Character pattern[4]; pattern[0] = separatorCharacter; string.getCharacters8(std::span { pattern }.subspan(1)); size_t fillLength = count * 4; @@ -202,12 +202,12 @@ JSValue JSStringJoiner::joinSlow(JSGlobalObject* globalObject) String result; if (m_isAll8Bit) - result = joinStrings(m_strings, m_separator.span8(), length); + result = joinStrings(m_strings, m_separator.span8(), length); else { if (m_separator.is8Bit()) - result = joinStrings(m_strings, m_separator.span8(), length); + result = joinStrings(m_strings, m_separator.span8(), length); else - result = joinStrings(m_strings, m_separator.span16(), length); + result = joinStrings(m_strings, m_separator.span16(), length); } if (UNLIKELY(result.isNull())) { diff --git a/Source/JavaScriptCore/runtime/LiteralParser.cpp b/Source/JavaScriptCore/runtime/LiteralParser.cpp index 23b0388f8b9eb..54a4844209c85 100644 --- a/Source/JavaScriptCore/runtime/LiteralParser.cpp +++ b/Source/JavaScriptCore/runtime/LiteralParser.cpp @@ -170,12 +170,12 @@ ALWAYS_INLINE JSString* LiteralParser::makeJSString(VM& v return jsString(vm, Identifier::fromString(vm, token->string16()).string()); } -[[maybe_unused]] static ALWAYS_INLINE bool cannotBeIdentPartOrEscapeStart(LChar) +[[maybe_unused]] static ALWAYS_INLINE bool cannotBeIdentPartOrEscapeStart(Latin1Character) { RELEASE_ASSERT_NOT_REACHED(); } -[[maybe_unused]] static ALWAYS_INLINE bool cannotBeIdentPartOrEscapeStart(UChar) +[[maybe_unused]] static ALWAYS_INLINE bool cannotBeIdentPartOrEscapeStart(char16_t) { RELEASE_ASSERT_NOT_REACHED(); } @@ -857,14 +857,14 @@ ALWAYS_INLINE TokenType LiteralParser::Lexer::nextMaybeId } template <> -ALWAYS_INLINE void setParserTokenString(LiteralParserToken& token, const LChar* string) +ALWAYS_INLINE void setParserTokenString(LiteralParserToken& token, const Latin1Character* string) { token.stringIs8Bit = 1; token.stringStart8 = string; } template <> -ALWAYS_INLINE void setParserTokenString(LiteralParserToken& token, const UChar* string) +ALWAYS_INLINE void setParserTokenString(LiteralParserToken& token, const char16_t* string) { token.stringIs8Bit = 0; token.stringStart16 = string; @@ -873,7 +873,7 @@ ALWAYS_INLINE void setParserTokenString(LiteralParserToken& token, enum class SafeStringCharacterSet { Strict, Sloppy }; template -static ALWAYS_INLINE bool isSafeStringCharacter(LChar c, LChar terminator) +static ALWAYS_INLINE bool isSafeStringCharacter(Latin1Character c, Latin1Character terminator) { if constexpr (set == SafeStringCharacterSet::Strict) return safeStringLatin1CharactersInStrictJSON[c]; @@ -882,21 +882,21 @@ static ALWAYS_INLINE bool isSafeStringCharacter(LChar c, LChar terminator) } template -static ALWAYS_INLINE bool isSafeStringCharacter(UChar c, UChar terminator) +static ALWAYS_INLINE bool isSafeStringCharacter(char16_t c, char16_t terminator) { if constexpr (set == SafeStringCharacterSet::Strict) { if (!isLatin1(c)) return true; - return isSafeStringCharacter(static_cast(c), static_cast(terminator)); + return isSafeStringCharacter(static_cast(c), static_cast(terminator)); } else return (c >= ' ' && isLatin1(c) && c != '\\' && c != terminator) || (c == '\t'); } template -static ALWAYS_INLINE bool isSafeStringCharacterForIdentifier(UChar c, UChar terminator) +static ALWAYS_INLINE bool isSafeStringCharacterForIdentifier(char16_t c, char16_t terminator) { if constexpr (set == SafeStringCharacterSet::Strict) - return isSafeStringCharacter(static_cast(c), static_cast(terminator)) || !isLatin1(c); + return isSafeStringCharacter(static_cast(c), static_cast(terminator)) || !isLatin1(c); else return (c >= ' ' && isLatin1(c) && c != '\\' && c != terminator) || (c == '\t'); } @@ -911,7 +911,7 @@ ALWAYS_INLINE TokenType LiteralParser::Lexer::lexString(L if (m_mode == StrictJSON) { ASSERT(terminator == '"'); if constexpr (hint == JSONIdentifierHint::MaybeIdentifier) { - while (m_ptr < m_end && isSafeStringCharacterForIdentifier(*m_ptr, '"')) + while (m_ptr < m_end && isSafeStringCharacterForIdentifier(*m_ptr, terminator)) ++m_ptr; } else { using UnsignedType = std::make_unsigned_t; @@ -926,8 +926,8 @@ ALWAYS_INLINE TokenType LiteralParser::Lexer::lexString(L return SIMD::findFirstNonZeroIndex(mask); }; - auto scalarMatch = [&](auto character) ALWAYS_INLINE_LAMBDA { - return !isSafeStringCharacter(character, '"'); + auto scalarMatch = [&](CharType character) ALWAYS_INLINE_LAMBDA { + return !isSafeStringCharacter(character, terminator); }; m_ptr = SIMD::find(std::span { m_ptr, m_end }, vectorMatch, scalarMatch); @@ -1780,10 +1780,10 @@ JSValue LiteralParser::parse(VM& vm, ParserState initialS } // Instantiate the two flavors of LiteralParser we need instead of putting most of this file in LiteralParser.h -template class LiteralParser; -template class LiteralParser; -template class LiteralParser; -template class LiteralParser; +template class LiteralParser; +template class LiteralParser; +template class LiteralParser; +template class LiteralParser; } diff --git a/Source/JavaScriptCore/runtime/LiteralParser.h b/Source/JavaScriptCore/runtime/LiteralParser.h index 0e0fbde75379e..752c22bcde8cd 100644 --- a/Source/JavaScriptCore/runtime/LiteralParser.h +++ b/Source/JavaScriptCore/runtime/LiteralParser.h @@ -117,13 +117,13 @@ template struct LiteralParserToken { union { double numberToken; // Only used for TokNumber. const CharacterType* identifierStart; - const LChar* stringStart8; - const UChar* stringStart16; + const Latin1Character* stringStart8; + const char16_t* stringStart16; }; std::span identifier() const { return { identifierStart, stringOrIdentifierLength }; } - std::span string8() const { return { stringStart8, stringOrIdentifierLength }; } - std::span string16() const { return { stringStart16, stringOrIdentifierLength }; } + std::span string8() const { return { stringStart8, stringOrIdentifierLength }; } + std::span string16() const { return { stringStart16, stringOrIdentifierLength }; } }; template diff --git a/Source/JavaScriptCore/runtime/NumberPrototype.cpp b/Source/JavaScriptCore/runtime/NumberPrototype.cpp index 46505611bb9c0..2cfa53f5b31fc 100644 --- a/Source/JavaScriptCore/runtime/NumberPrototype.cpp +++ b/Source/JavaScriptCore/runtime/NumberPrototype.cpp @@ -342,9 +342,9 @@ static char* toStringWithRadixInternal(RadixBuffer& buffer, double originalNumbe static String toStringWithRadixInternal(int32_t number, unsigned radix) { - LChar buf[1 + 32]; // Worst case is radix == 2, which gives us 32 digits + sign. - LChar* end = std::end(buf); - LChar* p = end; + Latin1Character buf[1 + 32]; // Worst case is radix == 2, which gives us 32 digits + sign. + Latin1Character* end = std::end(buf); + Latin1Character* p = end; bool negative = false; uint32_t positiveNumber = number; diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h index cb448cb9cc304..89f41e98821ea 100644 --- a/Source/JavaScriptCore/runtime/Operations.h +++ b/Source/JavaScriptCore/runtime/Operations.h @@ -100,7 +100,7 @@ ALWAYS_INLINE JSString* jsString(JSGlobalObject* globalObject, const String& u1, // We do not account u1 cost in (2) since u1 may be shared StringImpl, and it may not introduce additional cost. // We conservatively consider the cost of u1. Currently, we are not considering about is8Bit() case because 16-bit // strings are relatively rare. But we can do that if we need to consider it. - if (s2->isRope() || (StringImpl::headerSize() + length1 + length2) >= sizeof(JSRopeString)) + if (s2->isRope() || (StringImpl::headerSize() + length1 + length2) >= sizeof(JSRopeString)) return JSRopeString::create(vm, jsString(vm, u1), s2); ASSERT(!s2->isRope()); @@ -133,7 +133,7 @@ ALWAYS_INLINE JSString* jsString(JSGlobalObject* globalObject, JSString* s1, con // (1) Cost of making JSString : sizeof(JSString) (for new string) + sizeof(StringImpl header) + length1 + length2 // (2) Cost of making JSRopeString: sizeof(JSString) (for u2) + sizeof(JSRopeString) - if (s1->isRope() || (StringImpl::headerSize() + length1 + length2) >= sizeof(JSRopeString)) + if (s1->isRope() || (StringImpl::headerSize() + length1 + length2) >= sizeof(JSRopeString)) return JSRopeString::create(vm, s1, jsString(vm, u2)); ASSERT(!s1->isRope()); @@ -212,7 +212,7 @@ ALWAYS_INLINE JSString* jsString(JSGlobalObject* globalObject, const String& u1, // (1) Cost of making JSString : sizeof(JSString) (for new string) + sizeof(StringImpl header) + length1 + length2 // (2) Cost of making JSRopeString: sizeof(JSString) (for u1) + sizeof(JSString) (for u2) + sizeof(JSRopeString) - if ((StringImpl::headerSize() + length1 + length2) >= (sizeof(JSRopeString) + sizeof(JSString))) + if ((StringImpl::headerSize() + length1 + length2) >= (sizeof(JSRopeString) + sizeof(JSString))) return JSRopeString::create(vm, jsString(vm, u1), jsString(vm, u2)); String newString = tryMakeString(u1, u2); @@ -252,7 +252,7 @@ ALWAYS_INLINE JSString* jsString(JSGlobalObject* globalObject, const String& u1, // (1) Cost of making JSString : sizeof(JSString) (for new string) + sizeof(StringImpl header) + length1 + length2 + length3 // (2) Cost of making JSRopeString: sizeof(JSString) (for u1) + sizeof(JSString) (for u2) + sizeof(JSString) (for u3) + sizeof(JSRopeString) - if ((StringImpl::headerSize() + length1 + length2 + length3) >= (sizeof(JSRopeString) + sizeof(JSString) * 2)) + if ((StringImpl::headerSize() + length1 + length2 + length3) >= (sizeof(JSRopeString) + sizeof(JSString) * 2)) return JSRopeString::create(vm, jsString(vm, u1), jsString(vm, u2), jsString(vm, u3)); String newString = tryMakeString(u1, u2, u3); diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp index 51ccc94ae0996..d8ef7517039e4 100644 --- a/Source/JavaScriptCore/runtime/Options.cpp +++ b/Source/JavaScriptCore/runtime/Options.cpp @@ -207,7 +207,7 @@ std::optional parse(const char* string); template<> std::optional parse(const char* string) { - auto span = WTF::span(string); + auto span = WTF::unsafeSpan(string); if (equalLettersIgnoringASCIICase(span, "true"_s) || equalLettersIgnoringASCIICase(span, "yes"_s) || !strcmp(string, "1")) return true; if (equalLettersIgnoringASCIICase(span, "false"_s) || equalLettersIgnoringASCIICase(span, "no"_s) || !strcmp(string, "0")) @@ -278,7 +278,7 @@ std::optional parse(const char* string) template<> std::optional parse(const char* string) { - auto span = WTF::span(string); + auto span = WTF::unsafeSpan(string); if (equalLettersIgnoringASCIICase(span, "none"_s) || equalLettersIgnoringASCIICase(span, "no"_s) || equalLettersIgnoringASCIICase(span, "false"_s) || !strcmp(string, "0")) return GCLogging::None; @@ -296,7 +296,7 @@ std::optional parse(const char* string) { std::optional result; - auto span = WTF::span(string); + auto span = WTF::unsafeSpan(string); if (equalLettersIgnoringASCIICase(span, "none"_s) || equalLettersIgnoringASCIICase(span, "false"_s) || !strcmp(string, "0")) result = OSLogType::None; else if (equalLettersIgnoringASCIICase(span, "true"_s) || !strcmp(string, "1")) @@ -428,7 +428,7 @@ bool Options::overrideAliasedOptionWithHeuristic(const char* name) if (!stringValue) return false; - auto aliasedOption = makeString(span(&name[4]), '=', span(stringValue)); + auto aliasedOption = makeString(unsafeSpan(&name[4]), '=', unsafeSpan(stringValue)); if (Options::setOption(aliasedOption.utf8().data())) return true; @@ -1262,7 +1262,7 @@ bool Options::setAliasedOption(const char* arg, bool verify) && !strncasecmp(arg, #aliasedName_, equalStr - arg)) { \ auto unaliasedOption = String::fromLatin1(#unaliasedName_); \ if (equivalence == SameOption) \ - unaliasedOption = makeString(unaliasedOption, span(equalStr)); \ + unaliasedOption = makeString(unaliasedOption, unsafeSpan(equalStr)); \ else { \ ASSERT(equivalence == InvertedOption); \ auto invertedValueStr = invertBoolOptionValue(equalStr + 1); \ @@ -1439,10 +1439,10 @@ void Option::dump(StringBuilder& builder) const builder.append(m_int32); break; case Options::Type::OptionRange: - builder.append(span(m_optionRange.rangeString())); + builder.append(unsafeSpan(m_optionRange.rangeString())); break; case Options::Type::OptionString: - builder.append('"', m_optionString ? span8(m_optionString) : ""_span, '"'); + builder.append('"', m_optionString ? byteCast(unsafeSpan(m_optionString)) : ""_span, '"'); break; case Options::Type::GCLogLevel: builder.append(m_gcLogLevel); diff --git a/Source/JavaScriptCore/runtime/ParseInt.h b/Source/JavaScriptCore/runtime/ParseInt.h index d72d7fcd2ce9b..10da42bec0f83 100644 --- a/Source/JavaScriptCore/runtime/ParseInt.h +++ b/Source/JavaScriptCore/runtime/ParseInt.h @@ -51,12 +51,12 @@ ALWAYS_INLINE static int parseDigit(unsigned short c, int radix) return digit; } -static double parseIntOverflow(std::span s, int radix) +static double parseIntOverflow(std::span s, int radix) { double number = 0.0; double radixMultiplier = 1.0; - for (const LChar* p = s.data() + s.size() - 1; p >= s.data(); p--) { + for (const Latin1Character* p = s.data() + s.size() - 1; p >= s.data(); p--) { if (radixMultiplier == std::numeric_limits::infinity()) { if (*p != '0') { number = std::numeric_limits::infinity(); @@ -73,12 +73,12 @@ static double parseIntOverflow(std::span s, int radix) return number; } -static double parseIntOverflow(std::span s, int radix) +static double parseIntOverflow(std::span s, int radix) { double number = 0.0; double radixMultiplier = 1.0; - for (const UChar* p = s.data() + s.size() - 1; p >= s.data(); p--) { + for (const char16_t* p = s.data() + s.size() - 1; p >= s.data(); p--) { if (radixMultiplier == std::numeric_limits::infinity()) { if (*p != '0') { number = std::numeric_limits::infinity(); @@ -100,8 +100,8 @@ ALWAYS_INLINE static bool isStrWhiteSpace(CharacterType c) { // https://tc39.github.io/ecma262/#sec-tonumber-applied-to-the-string-type if constexpr (sizeof(c) == 1) - return Lexer::isWhiteSpace(c) || Lexer::isLineTerminator(c); - return Lexer::isWhiteSpace(c) || Lexer::isLineTerminator(c); + return Lexer::isWhiteSpace(c) || Lexer::isLineTerminator(c); + return Lexer::isWhiteSpace(c) || Lexer::isLineTerminator(c); } inline static std::optional parseIntDouble(double n) diff --git a/Source/JavaScriptCore/runtime/PropertyName.h b/Source/JavaScriptCore/runtime/PropertyName.h index 833ed99da283f..a40e2022de809 100644 --- a/Source/JavaScriptCore/runtime/PropertyName.h +++ b/Source/JavaScriptCore/runtime/PropertyName.h @@ -167,7 +167,7 @@ ALWAYS_INLINE bool isCanonicalNumericIndexString(UniquedStringImpl* propertyName double index = jsToNumber(propertyName); NumberToStringBuffer buffer; auto span = WTF::numberToStringAndSize(index, buffer); - return equal(propertyName, byteCast(span)); + return equal(propertyName, byteCast(span)); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/RegExp.cpp b/Source/JavaScriptCore/runtime/RegExp.cpp index d2c60d97cc84b..45ede5672d96d 100644 --- a/Source/JavaScriptCore/runtime/RegExp.cpp +++ b/Source/JavaScriptCore/runtime/RegExp.cpp @@ -94,7 +94,7 @@ void RegExpFunctionalTestCollector::outputEscapedString(StringView s, bool escap int len = s.length(); for (int i = 0; i < len; ++i) { - UChar c = s[i]; + char16_t c = s[i]; switch (c) { case '\0': @@ -574,7 +574,7 @@ template static inline void appendLineTerminatorEscape(StringBuilder&, CharacterType); template <> -inline void appendLineTerminatorEscape(StringBuilder& builder, LChar lineTerminator) +inline void appendLineTerminatorEscape(StringBuilder& builder, Latin1Character lineTerminator) { if (lineTerminator == '\n') builder.append('n'); @@ -583,7 +583,7 @@ inline void appendLineTerminatorEscape(StringBuilder& builder, LChar line } template <> -inline void appendLineTerminatorEscape(StringBuilder& builder, UChar lineTerminator) +inline void appendLineTerminatorEscape(StringBuilder& builder, char16_t lineTerminator) { if (lineTerminator == '\n') builder.append('n'); @@ -683,7 +683,7 @@ String RegExp::escapedPattern() const String RegExp::toSourceString() const { - return makeString('/', escapedPattern(), '/', span(Yarr::flagsString(flags()).data())); + return makeString('/', escapedPattern(), '/', unsafeSpan(Yarr::flagsString(flags()).data())); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/RegExpObjectInlines.h b/Source/JavaScriptCore/runtime/RegExpObjectInlines.h index 7139971a4ebd5..f7b77b0e7394d 100644 --- a/Source/JavaScriptCore/runtime/RegExpObjectInlines.h +++ b/Source/JavaScriptCore/runtime/RegExpObjectInlines.h @@ -131,11 +131,11 @@ inline unsigned advanceStringUnicode(StringView s, unsigned length, unsigned cur if (currentIndex + 1 >= length) return currentIndex + 1; - UChar first = s[currentIndex]; + char16_t first = s[currentIndex]; if (!U16_IS_LEAD(first)) return currentIndex + 1; - UChar second = s[currentIndex + 1]; + char16_t second = s[currentIndex + 1]; if (!U16_IS_TRAIL(second)) return currentIndex + 1; diff --git a/Source/JavaScriptCore/runtime/SamplingProfiler.cpp b/Source/JavaScriptCore/runtime/SamplingProfiler.cpp index a313789370fb6..7f768ce78322f 100644 --- a/Source/JavaScriptCore/runtime/SamplingProfiler.cpp +++ b/Source/JavaScriptCore/runtime/SamplingProfiler.cpp @@ -1315,7 +1315,7 @@ void SamplingProfiler::reportTopBytecodes(PrintStream& out) auto frameDescription = makeString(frame.displayName(m_vm), descriptionForLocation(frame.semanticLocation, frame.wasmCompilationMode, frame.wasmOffset)); if (std::optional> machineLocation = frame.machineLocation) { frameDescription = makeString(frameDescription, " <-- "_s, - span(machineLocation->second->inferredName().data()), descriptionForLocation(machineLocation->first, std::nullopt, BytecodeIndex())); + unsafeSpan(machineLocation->second->inferredName().data()), descriptionForLocation(machineLocation->first, std::nullopt, BytecodeIndex())); } bytecodeCounts.add(frameDescription, 0).iterator->value++; diff --git a/Source/JavaScriptCore/runtime/SmallStrings.cpp b/Source/JavaScriptCore/runtime/SmallStrings.cpp index 7ec76a9741531..830260eca89ab 100644 --- a/Source/JavaScriptCore/runtime/SmallStrings.cpp +++ b/Source/JavaScriptCore/runtime/SmallStrings.cpp @@ -49,7 +49,7 @@ void SmallStrings::initializeCommonStrings(VM& vm) for (unsigned i = 0; i < singleCharacterStringCount; ++i) { ASSERT(!m_singleCharacterStrings[i]); - std::array string = { static_cast(i) }; + std::array string = { static_cast(i) }; m_singleCharacterStrings[i] = JSString::createHasOtherOwner(vm, AtomStringImpl::add(string).releaseNonNull()); ASSERT(m_needsToBeVisited); } @@ -118,7 +118,7 @@ Ref SmallStrings::singleCharacterStringRep(unsigned char charact { if (LIKELY(m_isInitialized)) return *static_cast(const_cast(m_singleCharacterStrings[character]->tryGetValueImpl())); - std::array string = { static_cast(character) }; + std::array string = { static_cast(character) }; return AtomStringImpl::add(string).releaseNonNull(); } diff --git a/Source/JavaScriptCore/runtime/StringConstructor.cpp b/Source/JavaScriptCore/runtime/StringConstructor.cpp index 8889e548b9bec..ffc9537fec0d2 100644 --- a/Source/JavaScriptCore/runtime/StringConstructor.cpp +++ b/Source/JavaScriptCore/runtime/StringConstructor.cpp @@ -84,36 +84,36 @@ JSC_DEFINE_HOST_FUNCTION(stringFromCharCode, (JSGlobalObject* globalObject, Call unsigned length = callFrame->argumentCount(); if (LIKELY(length == 1)) { scope.release(); - UChar code = callFrame->uncheckedArgument(0).toUInt32(globalObject); + char16_t code = callFrame->uncheckedArgument(0).toUInt32(globalObject); // Not checking for an exception here is ok because jsSingleCharacterString will just fetch an unused string if there's an exception. return JSValue::encode(jsSingleCharacterString(vm, code)); } - std::span buf8Bit; + std::span buf8Bit; auto impl8Bit = StringImpl::createUninitialized(length, buf8Bit); for (unsigned i = 0; i < length; ++i) { - UChar character = static_cast(callFrame->uncheckedArgument(i).toUInt32(globalObject)); + char16_t character = static_cast(callFrame->uncheckedArgument(i).toUInt32(globalObject)); RETURN_IF_EXCEPTION(scope, encodedJSValue()); if (UNLIKELY(!isLatin1(character))) { - std::span buf16Bit; + std::span buf16Bit; auto impl16Bit = StringImpl::createUninitialized(length, buf16Bit); StringImpl::copyCharacters(buf16Bit.data(), buf8Bit.first(i)); buf16Bit[i] = character; ++i; for (; i < length; ++i) { - buf16Bit[i] = static_cast(callFrame->uncheckedArgument(i).toUInt32(globalObject)); + buf16Bit[i] = static_cast(callFrame->uncheckedArgument(i).toUInt32(globalObject)); RETURN_IF_EXCEPTION(scope, encodedJSValue()); } RELEASE_AND_RETURN(scope, JSValue::encode(jsString(vm, WTFMove(impl16Bit)))); } - buf8Bit[i] = static_cast(character); + buf8Bit[i] = static_cast(character); } RELEASE_AND_RETURN(scope, JSValue::encode(jsString(vm, WTFMove(impl8Bit)))); } JSString* stringFromCharCode(JSGlobalObject* globalObject, int32_t arg) { - return jsSingleCharacterString(globalObject->vm(), static_cast(arg)); + return jsSingleCharacterString(globalObject->vm(), static_cast(arg)); } JSC_DEFINE_HOST_FUNCTION(stringFromCodePoint, (JSGlobalObject* globalObject, CallFrame* callFrame)) @@ -135,7 +135,7 @@ JSC_DEFINE_HOST_FUNCTION(stringFromCodePoint, (JSGlobalObject* globalObject, Cal return throwVMError(globalObject, scope, createRangeError(globalObject, "Arguments contain a value that is out of range of code points"_s)); if (U_IS_BMP(codePoint)) - builder.append(static_cast(codePoint)); + builder.append(static_cast(codePoint)); else { builder.append(U16_LEAD(codePoint)); builder.append(U16_TRAIL(codePoint)); diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp index 61490fc3a9b56..6e018cbdbce0a 100644 --- a/Source/JavaScriptCore/runtime/StringPrototype.cpp +++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp @@ -193,7 +193,7 @@ NEVER_INLINE void substituteBackreferencesSlow(StringBuilder& result, StringView if (i + 1 == replacement.length()) break; - UChar ref = replacement[i + 1]; + char16_t ref = replacement[i + 1]; if (ref == '$') { // "$$" -> "$" ++i; @@ -310,7 +310,7 @@ static ALWAYS_INLINE JSString* jsSpliceSubstrings(JSGlobalObject* globalObject, return jsEmptyString(vm); if (source.is8Bit()) { - std::span buffer; + std::span buffer; auto sourceData = source.span8(); auto impl = StringImpl::tryCreateUninitialized(totalLength, buffer); if (!impl) { @@ -328,7 +328,7 @@ static ALWAYS_INLINE JSString* jsSpliceSubstrings(JSGlobalObject* globalObject, RELEASE_AND_RETURN(scope, jsString(vm, impl.releaseNonNull())); } - std::span buffer; + std::span buffer; auto sourceData = source.span16(); auto impl = StringImpl::tryCreateUninitialized(totalLength, buffer); @@ -940,10 +940,10 @@ JSC_DEFINE_HOST_FUNCTION(stringProtoFuncRepeatCharacter, (JSGlobalObject* global auto view = string->view(globalObject); ASSERT(view->length() == 1); scope.assertNoException(); - UChar character = view[0]; + char16_t character = view[0]; scope.release(); if (isLatin1(character)) - return JSValue::encode(repeatCharacter(globalObject, static_cast(character), repeatCount)); + return JSValue::encode(repeatCharacter(globalObject, static_cast(character), repeatCount)); return JSValue::encode(repeatCharacter(globalObject, character, repeatCount)); } @@ -1300,7 +1300,7 @@ JSC_DEFINE_HOST_FUNCTION(stringProtoFuncSlice, (JSGlobalObject* globalObject, Ca // Return true in case of early return (resultLength got to limitLength). template -static ALWAYS_INLINE bool splitStringByOneCharacterImpl(Indice& result, StringImpl* string, UChar separatorCharacter, unsigned limitLength) +static ALWAYS_INLINE bool splitStringByOneCharacterImpl(Indice& result, StringImpl* string, char16_t separatorCharacter, unsigned limitLength) { // 12. Let q = p. size_t matchPosition; @@ -1459,12 +1459,12 @@ JSC_DEFINE_HOST_FUNCTION(stringProtoFuncSplitFast, (JSGlobalObject* globalObject StringImpl* separatorImpl = separator.impl(); if (separatorLength == 1) { - UChar separatorCharacter = separatorImpl->at(0); + char16_t separatorCharacter = separatorImpl->at(0); if (stringImpl->is8Bit()) { - if (splitStringByOneCharacterImpl(result, stringImpl, separatorCharacter, limit)) + if (splitStringByOneCharacterImpl(result, stringImpl, separatorCharacter, limit)) RELEASE_AND_RETURN(scope, JSValue::encode(cacheAndCreateArray())); } else { - if (splitStringByOneCharacterImpl(result, stringImpl, separatorCharacter, limit)) + if (splitStringByOneCharacterImpl(result, stringImpl, separatorCharacter, limit)) RELEASE_AND_RETURN(scope, JSValue::encode(cacheAndCreateArray())); } } else { @@ -1775,7 +1775,7 @@ static EncodedJSValue toLocaleCase(JSGlobalObject* globalObject, CallFrame* call // 17. Let L be a String whose elements are, in order, the elements of cuList. // Most strings lower/upper case will be the same size as original, so try that first. - Vector buffer; + Vector buffer; buffer.reserveInitialCapacity(s->length()); auto convertCase = mode == CaseConversionMode::Lower ? u_strToLower : u_strToUpper; auto status = callBufferProducingFunction(convertCase, buffer, StringView { s }.upconvertedCharacters().get(), s->length(), locale.utf8().data()); @@ -2059,7 +2059,7 @@ static JSValue normalize(JSGlobalObject* globalObject, JSString* string, Normali int32_t normalizedStringLength = unorm2_normalize(normalizer, characters, view->length(), nullptr, 0, &status); ASSERT(needsToGrowToProduceBuffer(status)); - std::span buffer; + std::span buffer; auto result = StringImpl::tryCreateUninitialized(normalizedStringLength, buffer); if (!result) return throwOutOfMemoryError(globalObject, scope); @@ -2103,10 +2103,10 @@ JSC_DEFINE_HOST_FUNCTION(stringProtoFuncNormalize, (JSGlobalObject* globalObject RELEASE_AND_RETURN(scope, JSValue::encode(normalize(globalObject, string, form))); } -static inline std::optional illFormedIndex(std::span characters) +static inline std::optional illFormedIndex(std::span characters) { for (unsigned index = 0; index < characters.size(); ++index) { - UChar character = characters[index]; + char16_t character = characters[index]; if (!U16_IS_SURROGATE(character)) continue; @@ -2116,7 +2116,7 @@ static inline std::optional illFormedIndex(std::span char ASSERT(U16_IS_SURROGATE_LEAD(character)); if ((index + 1) == characters.size()) return index; - UChar nextCharacter = characters[index + 1]; + char16_t nextCharacter = characters[index + 1]; if (!U16_IS_SURROGATE(nextCharacter)) return index; @@ -2180,11 +2180,11 @@ JSC_DEFINE_HOST_FUNCTION(stringProtoFuncToWellFormed, (JSGlobalObject* globalObj if (!firstIllFormedIndex) return JSValue::encode(stringValue); - Vector buffer; + Vector buffer; buffer.reserveInitialCapacity(characters.size()); buffer.append(characters.first(*firstIllFormedIndex)); for (unsigned index = firstIllFormedIndex.value(); index < characters.size(); ++index) { - UChar character = characters[index]; + char16_t character = characters[index]; if (!U16_IS_SURROGATE(character)) { buffer.append(character); @@ -2201,7 +2201,7 @@ JSC_DEFINE_HOST_FUNCTION(stringProtoFuncToWellFormed, (JSGlobalObject* globalObj buffer.append(replacementCharacter); continue; } - UChar nextCharacter = characters[index + 1]; + char16_t nextCharacter = characters[index + 1]; if (!U16_IS_SURROGATE(nextCharacter)) { buffer.append(replacementCharacter); diff --git a/Source/JavaScriptCore/runtime/StringPrototypeInlines.h b/Source/JavaScriptCore/runtime/StringPrototypeInlines.h index 6d4d556141939..06dfca03ef5ab 100644 --- a/Source/JavaScriptCore/runtime/StringPrototypeInlines.h +++ b/Source/JavaScriptCore/runtime/StringPrototypeInlines.h @@ -145,7 +145,7 @@ ALWAYS_INLINE JSString* jsSpliceSubstringsWithSeparators(JSGlobalObject* globalO return jsEmptyString(vm); if (source.is8Bit() && allSeparators8Bit) { - std::span buffer; + std::span buffer; auto impl = StringImpl::tryCreateUninitialized(totalLength, buffer); if (!impl) { throwOutOfMemoryError(globalObject, scope); @@ -170,7 +170,7 @@ ALWAYS_INLINE JSString* jsSpliceSubstringsWithSeparators(JSGlobalObject* globalO RELEASE_AND_RETURN(scope, jsString(vm, impl.releaseNonNull())); } - std::span buffer; + std::span buffer; auto impl = StringImpl::tryCreateUninitialized(totalLength, buffer); if (!impl) { throwOutOfMemoryError(globalObject, scope); diff --git a/Source/JavaScriptCore/testRegExp.cpp b/Source/JavaScriptCore/testRegExp.cpp index 34ed21e9d66c8..706a30da75ac4 100644 --- a/Source/JavaScriptCore/testRegExp.cpp +++ b/Source/JavaScriptCore/testRegExp.cpp @@ -227,7 +227,7 @@ static int scanString(char* buffer, int bufferLength, StringBuilder& builder, ch bool escape = false; for (int i = 0; i < bufferLength; ++i) { - UChar c = buffer[i]; + char16_t c = buffer[i]; if (escape) { switch (c) { @@ -267,7 +267,7 @@ static int scanString(char* buffer, int bufferLength, StringBuilder& builder, ch unsigned int charValue; if (sscanf(buffer+i+1, "%04x", &charValue) != 1) return -1; - c = static_cast(charValue); + c = static_cast(charValue); i += 4; break; } diff --git a/Source/JavaScriptCore/tools/CharacterPropertyDataGenerator.cpp b/Source/JavaScriptCore/tools/CharacterPropertyDataGenerator.cpp index d2e04626df394..5e4b744a918de 100644 --- a/Source/JavaScriptCore/tools/CharacterPropertyDataGenerator.cpp +++ b/Source/JavaScriptCore/tools/CharacterPropertyDataGenerator.cpp @@ -43,8 +43,8 @@ namespace JSC { // class LineBreakData { public: - static constexpr UChar minChar = '!'; - static constexpr UChar maxChar = 0xFF; + static constexpr char16_t minChar = '!'; + static constexpr char16_t maxChar = 0xFF; static constexpr unsigned numChars = maxChar - minChar + 1; static constexpr unsigned numCharsRoundUp8 = (numChars + 7) / 8 * 8; @@ -61,8 +61,8 @@ class LineBreakData { private: void fill() { - for (UChar ch = minChar; ch <= maxChar; ++ch) { - for (UChar chNext = minChar; chNext <= maxChar; ++chNext) { + for (char16_t ch = minChar; ch <= maxChar; ++ch) { + for (char16_t chNext = minChar; chNext <= maxChar; ++chNext) { auto string = makeString(ch, chNext); CachedTextBreakIterator iterator(string, { }, WTF::TextBreakIterator::LineMode { WTF::TextBreakIterator::LineMode::Behavior::Default }, AtomString("en"_str)); setPairValue(ch, chNext, iterator.isBoundary(1)); @@ -176,7 +176,7 @@ class LineBreakData { // Print the column comment. dataLog(" /*"); - for (UChar ch = minChar; ch <= maxChar; ++ch) { + for (char16_t ch = minChar; ch <= maxChar; ++ch) { if (ch != minChar && (ch - minChar) % 8 == 0) dataLog(" "); dataLogF(ch < 0x7F ? " %c" : "%02X", ch); @@ -185,7 +185,7 @@ class LineBreakData { // Print the data array. for (unsigned y = 0; y < numChars; ++y) { - const UChar ch = y + minChar; + const char16_t ch = y + minChar; dataLogF("/* %02X %c */ {B(", ch, ch < 0x7F ? ch : ' '); const char* prefix = ""; for (unsigned x = 0; x < numCharsRoundUp8; ++x) { @@ -201,16 +201,16 @@ class LineBreakData { dataLogLn("} // namespace WebCore"); } - void setPairValue(UChar ch1Min, UChar ch1Max, UChar ch2Min, UChar ch2Max, bool value) + void setPairValue(char16_t ch1Min, char16_t ch1Max, char16_t ch2Min, char16_t ch2Max, bool value) { - for (UChar ch1 = ch1Min; ch1 <= ch1Max; ++ch1) { - for (UChar ch2 = ch2Min; ch2 <= ch2Max; ++ch2) + for (char16_t ch1 = ch1Min; ch1 <= ch1Max; ++ch1) { + for (char16_t ch2 = ch2Min; ch2 <= ch2Max; ++ch2) setPairValue(ch1, ch2, value); } } // Set the breakability between `ch1` and `ch2`. - void setPairValue(UChar ch1, UChar ch2, bool value) + void setPairValue(char16_t ch1, char16_t ch2, bool value) { RELEASE_ASSERT(ch1 >= minChar); RELEASE_ASSERT(ch1 <= maxChar); diff --git a/Source/JavaScriptCore/tools/FunctionOverrides.cpp b/Source/JavaScriptCore/tools/FunctionOverrides.cpp index 960d961893e79..f038d4fce3ab8 100644 --- a/Source/JavaScriptCore/tools/FunctionOverrides.cpp +++ b/Source/JavaScriptCore/tools/FunctionOverrides.cpp @@ -244,7 +244,7 @@ WTF_ALLOW_UNSAFE_BUFFER_USAGE_END builder.append(std::span { line, p + 1 }); return builder.toString(); } - builder.append(span(line)); + builder.append(unsafeSpan(line)); WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN } while ((line = fgets(buffer, bufferSize, file))); diff --git a/Source/JavaScriptCore/wasm/WasmParser.h b/Source/JavaScriptCore/wasm/WasmParser.h index c889ca6fde2f8..9f2ad49517866 100644 --- a/Source/JavaScriptCore/wasm/WasmParser.h +++ b/Source/JavaScriptCore/wasm/WasmParser.h @@ -183,7 +183,7 @@ ALWAYS_INLINE bool ParserBase::consumeUTF8String(Name& result, size_t stringLeng if (!result.tryReserveCapacity(stringLength)) return false; - auto string = spanReinterpretCast(m_source.subspan(m_offset, stringLength)); + auto string = byteCast(m_source.subspan(m_offset, stringLength)); if (auto checkResult = WTF::Unicode::checkUTF8(string); checkResult.characters.size() != string.size()) return false; diff --git a/Source/JavaScriptCore/yarr/YarrCanonicalizeUCS2.js b/Source/JavaScriptCore/yarr/YarrCanonicalizeUCS2.js index 9eac46f58285e..3b365212dc813 100644 --- a/Source/JavaScriptCore/yarr/YarrCanonicalizeUCS2.js +++ b/Source/JavaScriptCore/yarr/YarrCanonicalizeUCS2.js @@ -183,8 +183,8 @@ function createTables(prefix, maxValue, canonicalGroups) } print("};"); print(); - // Create canonical table for LChar domain - let line = "const uint16_t canonicalTableLChar[256] = {"; + // Create canonical table for Latin1Character domain + let line = "const uint16_t canonicalTableLatin1Character[256] = {"; for (let i = 0; i < 256; i++) { if (!(i % 16)) { print(line); diff --git a/Source/JavaScriptCore/yarr/YarrInterpreter.cpp b/Source/JavaScriptCore/yarr/YarrInterpreter.cpp index 0ed882f454f89..8b935df6c2ff8 100644 --- a/Source/JavaScriptCore/yarr/YarrInterpreter.cpp +++ b/Source/JavaScriptCore/yarr/YarrInterpreter.cpp @@ -3174,30 +3174,30 @@ unsigned interpret(BytecodePattern* bytecode, StringView input, unsigned start, { SuperSamplerScope superSamplerScope(false); if (input.is8Bit()) - return Interpreter(bytecode, output, input.span8(), start).interpret(); - return Interpreter(bytecode, output, input.span16(), start).interpret(); + return Interpreter(bytecode, output, input.span8(), start).interpret(); + return Interpreter(bytecode, output, input.span16(), start).interpret(); } -unsigned interpret(BytecodePattern* bytecode, std::span input, unsigned start, unsigned* output) +unsigned interpret(BytecodePattern* bytecode, std::span input, unsigned start, unsigned* output) { SuperSamplerScope superSamplerScope(false); - return Interpreter(bytecode, output, input, start).interpret(); + return Interpreter(bytecode, output, input, start).interpret(); } -unsigned interpret(BytecodePattern* bytecode, std::span input, unsigned start, unsigned* output) +unsigned interpret(BytecodePattern* bytecode, std::span input, unsigned start, unsigned* output) { SuperSamplerScope superSamplerScope(false); - return Interpreter(bytecode, output, input, start).interpret(); + return Interpreter(bytecode, output, input, start).interpret(); } -// These should be the same for both UChar & LChar. +// These should be the same for both char16_t & Latin1Character. static_assert(sizeof(BackTrackInfoPatternCharacter) == (YarrStackSpaceForBackTrackInfoPatternCharacter * sizeof(uintptr_t))); static_assert(sizeof(BackTrackInfoCharacterClass) == (YarrStackSpaceForBackTrackInfoCharacterClass * sizeof(uintptr_t))); static_assert(sizeof(BackTrackInfoBackReference) == (YarrStackSpaceForBackTrackInfoBackReference * sizeof(uintptr_t))); static_assert(sizeof(BackTrackInfoAlternative) == (YarrStackSpaceForBackTrackInfoAlternative * sizeof(uintptr_t))); static_assert(sizeof(BackTrackInfoParentheticalAssertion) == (YarrStackSpaceForBackTrackInfoParentheticalAssertion * sizeof(uintptr_t))); static_assert(sizeof(BackTrackInfoParenthesesOnce) == (YarrStackSpaceForBackTrackInfoParenthesesOnce * sizeof(uintptr_t))); -static_assert(sizeof(Interpreter::BackTrackInfoParentheses) <= (YarrStackSpaceForBackTrackInfoParentheses * sizeof(uintptr_t))); +static_assert(sizeof(Interpreter::BackTrackInfoParentheses) <= (YarrStackSpaceForBackTrackInfoParentheses * sizeof(uintptr_t))); } } diff --git a/Source/JavaScriptCore/yarr/YarrInterpreter.h b/Source/JavaScriptCore/yarr/YarrInterpreter.h index 61a257c29415c..17737a3be2d75 100644 --- a/Source/JavaScriptCore/yarr/YarrInterpreter.h +++ b/Source/JavaScriptCore/yarr/YarrInterpreter.h @@ -536,7 +536,7 @@ struct BytecodePattern { JS_EXPORT_PRIVATE std::unique_ptr byteCompile(YarrPattern&, BumpPointerAllocator*, ErrorCode&, ConcurrentJSLock* = nullptr); JS_EXPORT_PRIVATE unsigned interpret(BytecodePattern*, StringView input, unsigned start, unsigned* output); -unsigned interpret(BytecodePattern*, std::span input, unsigned start, unsigned* output); -unsigned interpret(BytecodePattern*, std::span input, unsigned start, unsigned* output); +unsigned interpret(BytecodePattern*, std::span input, unsigned start, unsigned* output); +unsigned interpret(BytecodePattern*, std::span input, unsigned start, unsigned* output); } } // namespace JSC::Yarr diff --git a/Source/JavaScriptCore/yarr/YarrJIT.cpp b/Source/JavaScriptCore/yarr/YarrJIT.cpp index c36d744bf6e86..33e38e3ac67d0 100644 --- a/Source/JavaScriptCore/yarr/YarrJIT.cpp +++ b/Source/JavaScriptCore/yarr/YarrJIT.cpp @@ -111,7 +111,7 @@ class SubjectSampler { { } - int32_t frequency(UChar character) const + int32_t frequency(char16_t character) const { if (!m_size) return 1; @@ -143,7 +143,7 @@ class SubjectSampler { bool is8Bit() const { return m_is8Bit; } private: - inline void add(UChar character) + inline void add(char16_t character) { ++m_size; ++m_samples[character & BoyerMooreBitmap::mapMask]; @@ -971,7 +971,7 @@ class YarrGenerator final : public YarrJITInfo { if (m_charSize == CharSize::Char8) return MacroAssembler::BaseIndex(m_regs.input, indexReg, MacroAssembler::TimesOne, characterOffset * static_cast(sizeof(char))); - return MacroAssembler::BaseIndex(m_regs.input, indexReg, MacroAssembler::TimesTwo, characterOffset * static_cast(sizeof(UChar))); + return MacroAssembler::BaseIndex(m_regs.input, indexReg, MacroAssembler::TimesTwo, characterOffset * static_cast(sizeof(char16_t))); } #if ENABLE(YARR_JIT_UNICODE_EXPRESSIONS) diff --git a/Source/JavaScriptCore/yarr/YarrJIT.h b/Source/JavaScriptCore/yarr/YarrJIT.h index 7e1eae4f3bfd2..8d07c4cada7f4 100644 --- a/Source/JavaScriptCore/yarr/YarrJIT.h +++ b/Source/JavaScriptCore/yarr/YarrJIT.h @@ -276,10 +276,10 @@ class YarrCodeBlock final : public YarrBoyerMooreData { WTF_MAKE_NONCOPYABLE(YarrCodeBlock); public: - using YarrJITCode8 = UGPRPair SYSV_ABI (*)(const LChar* input, UCPURegister start, UCPURegister length, int* output, MatchingContextHolder*) YARR_CALL; - using YarrJITCode16 = UGPRPair SYSV_ABI (*)(const UChar* input, UCPURegister start, UCPURegister length, int* output, MatchingContextHolder*) YARR_CALL; - using YarrJITCodeMatchOnly8 = UGPRPair SYSV_ABI (*)(const LChar* input, UCPURegister start, UCPURegister length, void*, MatchingContextHolder*) YARR_CALL; - using YarrJITCodeMatchOnly16 = UGPRPair SYSV_ABI (*)(const UChar* input, UCPURegister start, UCPURegister length, void*, MatchingContextHolder*) YARR_CALL; + using YarrJITCode8 = UGPRPair SYSV_ABI (*)(const Latin1Character* input, UCPURegister start, UCPURegister length, int* output, MatchingContextHolder*) YARR_CALL; + using YarrJITCode16 = UGPRPair SYSV_ABI (*)(const char16_t* input, UCPURegister start, UCPURegister length, int* output, MatchingContextHolder*) YARR_CALL; + using YarrJITCodeMatchOnly8 = UGPRPair SYSV_ABI (*)(const Latin1Character* input, UCPURegister start, UCPURegister length, void*, MatchingContextHolder*) YARR_CALL; + using YarrJITCodeMatchOnly16 = UGPRPair SYSV_ABI (*)(const char16_t* input, UCPURegister start, UCPURegister length, void*, MatchingContextHolder*) YARR_CALL; YarrCodeBlock(RegExp* regExp) : m_regExp(regExp) @@ -332,7 +332,7 @@ class YarrCodeBlock final : public YarrBoyerMooreData { InlineStats& get8BitInlineStats() { return m_matchOnly8Stats; } InlineStats& get16BitInlineStats() { return m_matchOnly16Stats; } - MatchResult execute(std::span input, unsigned start, int* output, MatchingContextHolder* matchingContext) + MatchResult execute(std::span input, unsigned start, int* output, MatchingContextHolder* matchingContext) { ASSERT(has8BitCode()); #if CPU(ARM64E) @@ -342,7 +342,7 @@ class YarrCodeBlock final : public YarrBoyerMooreData { return MatchResult(untagCFunctionPtr(m_ref8.code().taggedPtr())(input.data(), start, input.size(), output, matchingContext)); } - MatchResult execute(std::span input, unsigned start, int* output, MatchingContextHolder* matchingContext) + MatchResult execute(std::span input, unsigned start, int* output, MatchingContextHolder* matchingContext) { ASSERT(has16BitCode()); #if CPU(ARM64E) @@ -352,7 +352,7 @@ class YarrCodeBlock final : public YarrBoyerMooreData { return MatchResult(untagCFunctionPtr(m_ref16.code().taggedPtr())(input.data(), start, input.size(), output, matchingContext)); } - MatchResult execute(std::span input, unsigned start, MatchingContextHolder* matchingContext) + MatchResult execute(std::span input, unsigned start, MatchingContextHolder* matchingContext) { ASSERT(has8BitCodeMatchOnly()); #if CPU(ARM64E) @@ -362,7 +362,7 @@ class YarrCodeBlock final : public YarrBoyerMooreData { return MatchResult(untagCFunctionPtr(m_matchOnly8.code().taggedPtr())(input.data(), start, input.size(), nullptr, matchingContext)); } - MatchResult execute(std::span input, unsigned start, MatchingContextHolder* matchingContext) + MatchResult execute(std::span input, unsigned start, MatchingContextHolder* matchingContext) { ASSERT(has16BitCodeMatchOnly()); #if CPU(ARM64E) diff --git a/Source/JavaScriptCore/yarr/YarrParser.h b/Source/JavaScriptCore/yarr/YarrParser.h index 4cf4273e36979..1cd4d47492ae8 100644 --- a/Source/JavaScriptCore/yarr/YarrParser.h +++ b/Source/JavaScriptCore/yarr/YarrParser.h @@ -1973,7 +1973,7 @@ class Parser { return octal; } - bool tryConsume(UChar ch) + bool tryConsume(char16_t ch) { if (atEndOfPattern() || (m_data[m_index] != ch)) return false; @@ -2188,8 +2188,8 @@ template ErrorCode parse(Delegate& delegate, const StringView pattern, CompileMode compileMode, unsigned backReferenceLimit = quantifyInfinite, bool isNamedForwardReferenceAllowed = true) { if (pattern.is8Bit()) - return Parser(delegate, pattern, compileMode, backReferenceLimit, isNamedForwardReferenceAllowed).parse(); - return Parser(delegate, pattern, compileMode, backReferenceLimit, isNamedForwardReferenceAllowed).parse(); + return Parser(delegate, pattern, compileMode, backReferenceLimit, isNamedForwardReferenceAllowed).parse(); + return Parser(delegate, pattern, compileMode, backReferenceLimit, isNamedForwardReferenceAllowed).parse(); } } } // namespace JSC::Yarr diff --git a/Source/JavaScriptCore/yarr/YarrPattern.cpp b/Source/JavaScriptCore/yarr/YarrPattern.cpp index b4f4383ebf42c..07e7c0bc78f04 100644 --- a/Source/JavaScriptCore/yarr/YarrPattern.cpp +++ b/Source/JavaScriptCore/yarr/YarrPattern.cpp @@ -286,7 +286,7 @@ class CharacterClassConstructor { // Nothing to do - no canonical equivalents. break; case CanonicalizeSet: { - UChar ch; + char16_t ch; for (auto* set = canonicalCharacterSetInfo(info->value, m_canonicalMode); (ch = *set); ++set) addSorted(ch); break; @@ -2041,7 +2041,7 @@ class YarrPatternConstructor { return { }; if (term.m_matchDirection != MatchDirection::Forward) return { }; - builder.append(static_cast(term.patternCharacter)); + builder.append(static_cast(term.patternCharacter)); } String atom = builder.toString(); if (atom.length() > 0) diff --git a/Source/JavaScriptCore/yarr/YarrSyntaxChecker.cpp b/Source/JavaScriptCore/yarr/YarrSyntaxChecker.cpp index cb95e7c032a21..a300cec90803c 100644 --- a/Source/JavaScriptCore/yarr/YarrSyntaxChecker.cpp +++ b/Source/JavaScriptCore/yarr/YarrSyntaxChecker.cpp @@ -39,8 +39,8 @@ class SyntaxChecker { void atomPatternCharacter(char32_t) { } void atomBuiltInCharacterClass(BuiltInCharacterClassID, bool) { } void atomCharacterClassBegin(bool = false) { } - void atomCharacterClassAtom(UChar) { } - void atomCharacterClassRange(UChar, UChar) { } + void atomCharacterClassAtom(char16_t) { } + void atomCharacterClassRange(char16_t, char16_t) { } void atomCharacterClassBuiltIn(BuiltInCharacterClassID, bool) { } void atomClassStringDisjunction(Vector>&) { } void atomCharacterClassSetOp(CharacterClassSetOp) { } diff --git a/Source/JavaScriptCore/yarr/hasher.py b/Source/JavaScriptCore/yarr/hasher.py index dd86fbc88a5d3..5c07bd7579ca9 100644 --- a/Source/JavaScriptCore/yarr/hasher.py +++ b/Source/JavaScriptCore/yarr/hasher.py @@ -72,7 +72,7 @@ def maskTop8BitsAndAvoidZero(value): def superFastHash(str): # Implements Paul Hsieh's SuperFastHash - http://www.azillionmonkeys.com/qed/hash.html - # LChar data is interpreted as Latin-1-encoded (zero extended to 16 bits). + # Latin1Character data is interpreted as Latin-1-encoded (zero extended to 16 bits). stringHashingStartValue = 0x9E3779B9 hash = stringHashingStartValue diff --git a/Source/WTF/WTF.xcodeproj/project.pbxproj b/Source/WTF/WTF.xcodeproj/project.pbxproj index 74f1cc055d2be..2053e48e11756 100644 --- a/Source/WTF/WTF.xcodeproj/project.pbxproj +++ b/Source/WTF/WTF.xcodeproj/project.pbxproj @@ -209,6 +209,8 @@ C2BCFC551F621F3F00C9222C /* LineEnding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2BCFC531F621F3F00C9222C /* LineEnding.cpp */; }; C805EF39E5F14481A96D39FC /* ASCIILiteral.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C6F050790D9C432A99085E75 /* ASCIILiteral.cpp */; }; CD5497AC15857D0300B5BC30 /* MediaTime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD5497AA15857D0300B5BC30 /* MediaTime.cpp */; }; + CDD4AC792D9C309A00D11414 /* CStringView.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDD4AC772D9C309A00D11414 /* CStringView.cpp */; }; + CDD4AC7A2D9C309A00D11414 /* CStringView.h in Headers */ = {isa = PBXBuildFile; fileRef = CDD4AC782D9C309A00D11414 /* CStringView.h */; settings = {ATTRIBUTES = (Private, ); }; }; CEA072AA236FFBF70018839C /* CrashReporter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEA072A9236FFBF70018839C /* CrashReporter.cpp */; }; DCEE22011CEA7551000C2396 /* BlockObjCExceptions.mm in Sources */ = {isa = PBXBuildFile; fileRef = DCEE21FD1CEA7551000C2396 /* BlockObjCExceptions.mm */; }; DD03059327B5DA0D00344002 /* SignedPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = 862A8D32278DE74A0014120C /* SignedPtr.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -596,7 +598,7 @@ DDF307D027C086DF006A526F /* TextBreakIteratorCF.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CCDB1491E566626006C73C0 /* TextBreakIteratorCF.h */; settings = {ATTRIBUTES = (Private, ); }; }; DDF307D127C086DF006A526F /* StringConcatenateNumbers.h in Headers */ = {isa = PBXBuildFile; fileRef = 7CD4C26F1E2C82B900929470 /* StringConcatenateNumbers.h */; settings = {ATTRIBUTES = (Private, ); }; }; DDF307D227C086DF006A526F /* UTextProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C181C8A1D307AB800F5FA16 /* UTextProvider.h */; settings = {ATTRIBUTES = (Private, ); }; }; - DDF307D327C086DF006A526F /* LChar.h in Headers */ = {isa = PBXBuildFile; fileRef = 93AC91A718942FC400244939 /* LChar.h */; settings = {ATTRIBUTES = (Private, ); }; }; + DDF307D327C086DF006A526F /* Latin1Character.h in Headers */ = {isa = PBXBuildFile; fileRef = 93AC91A718942FC400244939 /* Latin1Character.h */; settings = {ATTRIBUTES = (Private, ); }; }; DDF307D427C086DF006A526F /* TextBreakIteratorICU.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CCDB14D1E566898006C73C0 /* TextBreakIteratorICU.h */; settings = {ATTRIBUTES = (Private, ); }; }; DDF307D527C086DF006A526F /* LineEnding.h in Headers */ = {isa = PBXBuildFile; fileRef = C2BCFC541F621F3F00C9222C /* LineEnding.h */; settings = {ATTRIBUTES = (Private, ); }; }; DDF307D627C086DF006A526F /* NullTextBreakIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = DD4901ED27B474D900D7E50D /* NullTextBreakIterator.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -1326,7 +1328,7 @@ 93853DD228755A6600FF4E2B /* EscapedFormsForJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EscapedFormsForJSON.h; sourceTree = ""; }; 93934BD218A1E8C300D0D6A1 /* StringViewCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = StringViewCocoa.mm; sourceTree = ""; }; 93934BD418A1F16900D0D6A1 /* StringViewCF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StringViewCF.cpp; sourceTree = ""; }; - 93AC91A718942FC400244939 /* LChar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LChar.h; sourceTree = ""; }; + 93AC91A718942FC400244939 /* Latin1Character.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Latin1Character.h; sourceTree = ""; }; 93B07ED626B86BB500A09B34 /* SuspendableWorkQueue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SuspendableWorkQueue.h; sourceTree = ""; }; 93B07ED726B8715B00A09B34 /* SuspendableWorkQueue.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SuspendableWorkQueue.cpp; sourceTree = ""; }; 93B5B44D2213D616004B7AA7 /* HexNumber.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HexNumber.cpp; sourceTree = ""; }; @@ -1532,6 +1534,8 @@ CD5497AB15857D0300B5BC30 /* MediaTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaTime.h; sourceTree = ""; }; CD6D9FCD1EEF3AD4008B0671 /* Algorithms.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Algorithms.h; sourceTree = ""; }; CDCC9BC422382FCE00FFB51C /* AggregateLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AggregateLogger.h; path = wtf/AggregateLogger.h; sourceTree = SOURCE_ROOT; }; + CDD4AC772D9C309A00D11414 /* CStringView.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CStringView.cpp; sourceTree = ""; }; + CDD4AC782D9C309A00D11414 /* CStringView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CStringView.h; sourceTree = ""; }; CE1132832370634900A8C83B /* AnsiColors.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AnsiColors.h; sourceTree = ""; }; CEA072A8236FFBF70018839C /* CrashReporter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CrashReporter.h; sourceTree = ""; }; CEA072A9236FFBF70018839C /* CrashReporter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CrashReporter.cpp; sourceTree = ""; }; @@ -2611,12 +2615,14 @@ 0F8F2B9B172F2594007DBDA5 /* ConversionMode.h */, A8A47321151A825B004123FF /* CString.cpp */, A8A47322151A825B004123FF /* CString.h */, + CDD4AC772D9C309A00D11414 /* CStringView.cpp */, + CDD4AC782D9C309A00D11414 /* CStringView.h */, 93853DD228755A6600FF4E2B /* EscapedFormsForJSON.h */, 50DE35F3215BB01500B979C7 /* ExternalStringImpl.cpp */, 50DE35F4215BB01500B979C7 /* ExternalStringImpl.h */, 461229712ACF6B3100BB1CCC /* FastCharacterComparison.h */, 26147B0815DDCCDC00DDB907 /* IntegerToStringConversion.h */, - 93AC91A718942FC400244939 /* LChar.h */, + 93AC91A718942FC400244939 /* Latin1Character.h */, C2BCFC531F621F3F00C9222C /* LineEnding.cpp */, C2BCFC541F621F3F00C9222C /* LineEnding.h */, BC5267662C2726D600E422DD /* MakeString.h */, @@ -3221,6 +3227,7 @@ DD3DC8FC27A4BF8E007E5B61 /* CryptographicallyRandomNumber.h in Headers */, DD3DC8B727A4BF8E007E5B61 /* CryptographicUtilities.h in Headers */, DDF307E127C086DF006A526F /* CString.h in Headers */, + CDD4AC7A2D9C309A00D11414 /* CStringView.h in Headers */, DD3DC8E327A4BF8E007E5B61 /* DataLog.h in Headers */, DD4901E927B4748A00D7E50D /* DataMutex.h in Headers */, DD3DC94227A4BF8E007E5B61 /* DataRef.h in Headers */, @@ -3324,9 +3331,9 @@ DD3DC86F27A4BF8E007E5B61 /* JSValueMalloc.h in Headers */, DD3DC99727A4BF8E007E5B61 /* KeyValuePair.h in Headers */, DD3DC8BF27A4BF8E007E5B61 /* Language.h in Headers */, + DDF307D327C086DF006A526F /* Latin1Character.h in Headers */, E32AB5012B5CE35D00B9FAAE /* LazyRef.h in Headers */, E32AB5022B5CE35D00B9FAAE /* LazyUniqueRef.h in Headers */, - DDF307D327C086DF006A526F /* LChar.h in Headers */, DD3DC88927A4BF8E007E5B61 /* LEBDecoder.h in Headers */, 6311592628989A55006A9A12 /* LibraryPathDiagnostics.h in Headers */, DD3DC8B427A4BF8E007E5B61 /* LikelyDenseUnsignedIntegerSet.h in Headers */, @@ -4029,6 +4036,7 @@ A8A4739A151A825B004123FF /* CryptographicallyRandomNumber.cpp in Sources */, E15556F518A0CC18006F48FB /* CryptographicUtilities.cpp in Sources */, A8A47439151A825B004123FF /* CString.cpp in Sources */, + CDD4AC792D9C309A00D11414 /* CStringView.cpp in Sources */, A8A4739C151A825B004123FF /* CurrentTime.cpp in Sources */, A8A4739E151A825B004123FF /* DataLog.cpp in Sources */, A8A473A0151A825B004123FF /* DateMath.cpp in Sources */, diff --git a/Source/WTF/wtf/ASCIICType.h b/Source/WTF/wtf/ASCIICType.h index cfbbe0758356d..9532646de460c 100644 --- a/Source/WTF/wtf/ASCIICType.h +++ b/Source/WTF/wtf/ASCIICType.h @@ -25,7 +25,7 @@ #pragma once #include -#include +#include // The behavior of many of the functions in the header is dependent // on the current locale. But in the WebKit project, all uses of those functions @@ -184,7 +184,7 @@ template<> inline char toASCIILower(char character) return static_cast(asciiCaseFoldTable[static_cast(character)]); } -template<> inline LChar toASCIILower(LChar character) +template<> inline Latin1Character toASCIILower(Latin1Character character) { return asciiCaseFoldTable[character]; } diff --git a/Source/WTF/wtf/Assertions.cpp b/Source/WTF/wtf/Assertions.cpp index 56ee4c7bbf91a..36acb5f7c2f4c 100644 --- a/Source/WTF/wtf/Assertions.cpp +++ b/Source/WTF/wtf/Assertions.cpp @@ -200,8 +200,8 @@ ALLOW_NONLITERAL_FORMAT_END WTF_ATTRIBUTE_PRINTF(2, 0) static void vprintf_stderr_with_prefix(const char* rawPrefix, const char* rawFormat, va_list args) { - auto prefix = span(rawPrefix); - auto format = span(rawFormat); + auto prefix = unsafeSpan(rawPrefix); + auto format = unsafeSpan(rawFormat); Vector formatWithPrefix(prefix.size() + format.size() + 1); memcpySpan(formatWithPrefix.mutableSpan(), prefix); memcpySpan(formatWithPrefix.mutableSpan().subspan(prefix.size()), format); @@ -215,7 +215,7 @@ ALLOW_NONLITERAL_FORMAT_END WTF_ATTRIBUTE_PRINTF(2, 0) static void vprintf_stderr_with_trailing_newline(WTFLogChannel* channel, const char* rawFormat, va_list args) { - auto format = span(rawFormat); + auto format = unsafeSpan(rawFormat); if (!format.empty() && format.back() == '\n') { vprintf_stderr_common(channel, rawFormat, args); return; diff --git a/Source/WTF/wtf/CMakeLists.txt b/Source/WTF/wtf/CMakeLists.txt index a1c4469d73844..769690f87842d 100644 --- a/Source/WTF/wtf/CMakeLists.txt +++ b/Source/WTF/wtf/CMakeLists.txt @@ -438,6 +438,7 @@ set(WTF_PUBLIC_HEADERS text/AtomStringTable.h text/Base64.h text/CString.h + text/CStringView.h text/CharacterProperties.h text/CodePointIterator.h text/ConversionMode.h @@ -445,7 +446,7 @@ set(WTF_PUBLIC_HEADERS text/ExternalStringImpl.h text/FastCharacterComparison.h text/IntegerToStringConversion.h - text/LChar.h + text/Latin1Character.h text/LineEnding.h text/MakeString.h text/NullTextBreakIterator.h @@ -622,6 +623,7 @@ set(WTF_SOURCES text/AtomStringTable.cpp text/Base64.cpp text/CString.cpp + text/CStringView.cpp text/ExternalStringImpl.cpp text/LineEnding.cpp text/StringBuffer.cpp diff --git a/Source/WTF/wtf/DateMath.cpp b/Source/WTF/wtf/DateMath.cpp index c116d66a23c31..e03b26ab2cb1d 100644 --- a/Source/WTF/wtf/DateMath.cpp +++ b/Source/WTF/wtf/DateMath.cpp @@ -70,6 +70,8 @@ */ #include "config.h" +#include "StdLibExtras.h" +#include "text/StringCommon.h" #include #include @@ -131,8 +133,8 @@ static void appendTwoDigitNumber(StringBuilder& builder, int number) { ASSERT(number >= 0); ASSERT(number < 100); - builder.append(static_cast('0' + number / 10)); - builder.append(static_cast('0' + number % 10)); + builder.append(static_cast('0' + number / 10)); + builder.append(static_cast('0' + number % 10)); } static inline double msToMilliseconds(double ms) @@ -416,7 +418,7 @@ static const struct KnownZone { { "pdt", -420 } }; -inline static void skipSpacesAndComments(std::span& s) +inline static void skipSpacesAndComments(std::span& s) { int nesting = 0; while (!s.empty()) { @@ -434,7 +436,7 @@ inline static void skipSpacesAndComments(std::span& s) } // returns 0-11 (Jan-Dec); -1 on failure -static int findMonth(std::span monthStr) +static int findMonth(std::span monthStr) { if (monthStr.size() < 3) return -1; @@ -453,7 +455,7 @@ static int findMonth(std::span monthStr) return -1; } -static bool parseInt(std::span& string, int base, int* result) +static bool parseInt(std::span& string, int base, int* result) { char* stopPosition; long longResult = strtol(byteCast(string.data()), &stopPosition, base); @@ -465,7 +467,7 @@ static bool parseInt(std::span& string, int base, int* result) return true; } -static bool parseLong(std::span& string, int base, long* result) +static bool parseLong(std::span& string, int base, long* result) { char* stopPosition; *result = strtol(byteCast(string.data()), &stopPosition, base); @@ -479,7 +481,7 @@ static bool parseLong(std::span& string, int base, long* result) // Parses a date with the format YYYY[-MM[-DD]]. // Year parsing is lenient, allows any number of digits, and +/-. // Returns 0 if a parse error occurs, else returns the end of the parsed portion of the string. -static bool parseES5DatePortion(std::span& currentPosition, int& year, long& month, long& day) +static bool parseES5DatePortion(std::span& currentPosition, int& year, long& month, long& day) { // This is a bit more lenient on the year string than ES5 specifies: // instead of restricting to 4 digits (or 6 digits with mandatory +/-), @@ -523,7 +525,7 @@ static bool parseES5DatePortion(std::span& currentPosition, int& ye // Parses a time with the format HH:mm[:ss[.sss]][Z|(+|-)(00:00|0000|00)]. // Fractional seconds parsing is lenient, allows any number of digits. // Returns 0 if a parse error occurs, else returns the end of the parsed portion of the string. -static bool parseES5TimePortion(std::span& currentPosition, long& hours, long& minutes, long& seconds, double& milliseconds, bool& isLocalTime, long& timeZoneSeconds) +static bool parseES5TimePortion(std::span& currentPosition, long& hours, long& minutes, long& seconds, double& milliseconds, bool& isLocalTime, long& timeZoneSeconds) { isLocalTime = false; @@ -644,7 +646,7 @@ static bool parseES5TimePortion(std::span& currentPosition, long& h return true; } -double parseES5Date(std::span dateString, bool& isLocalTime) +double parseES5Date(std::span dateString, bool& isLocalTime) { isLocalTime = false; @@ -704,7 +706,7 @@ double parseES5Date(std::span dateString, bool& isLocalTime) } // Odd case where 'exec' is allowed to be 0, to accomodate a caller in WebCore. -double parseDate(std::span dateString, bool& isLocalTime) +double parseDate(std::span dateString, bool& isLocalTime) { isLocalTime = true; int offset = 0; @@ -959,7 +961,7 @@ double parseDate(std::span dateString, bool& isLocalTime) for (auto& knownZone : knownZones) { // Since the passed-in length is used for both strings, the following checks that // dateString has the time zone name as a prefix, not that it is equal. - auto tzName = span8(knownZone.tzName); + auto tzName = byteCast(unsafeSpan(knownZone.tzName)); if (dateString.size() >= tzName.size() && equalLettersIgnoringASCIICaseWithLength(dateString, tzName, tzName.size())) { offset = knownZone.tzOffset; dateString = dateString.subspan(tzName.size()); @@ -1009,7 +1011,7 @@ double parseDate(std::span dateString, bool& isLocalTime) return ymdhmsToMilliseconds(year.value(), month + 1, day, hour, minute, second, 0) - offset * (secondsPerMinute * msPerSecond); } -double parseDate(std::span dateString) +double parseDate(std::span dateString) { bool isLocalTime; double value = parseDate(dateString, isLocalTime); diff --git a/Source/WTF/wtf/DateMath.h b/Source/WTF/wtf/DateMath.h index 594645c39e888..75a18b16bf87e 100644 --- a/Source/WTF/wtf/DateMath.h +++ b/Source/WTF/wtf/DateMath.h @@ -77,9 +77,9 @@ void initializeDates(); int equivalentYearForDST(int year); // Not really math related, but this is currently the only shared place to put these. -WTF_EXPORT_PRIVATE double parseES5Date(std::span dateString, bool& isLocalTime); -WTF_EXPORT_PRIVATE double parseDate(std::span dateString); -WTF_EXPORT_PRIVATE double parseDate(std::span dateString, bool& isLocalTime); +WTF_EXPORT_PRIVATE double parseES5Date(std::span dateString, bool& isLocalTime); +WTF_EXPORT_PRIVATE double parseDate(std::span dateString); +WTF_EXPORT_PRIVATE double parseDate(std::span dateString, bool& isLocalTime); // dayOfWeek: [0, 6] 0 being Monday, day: [1, 31], month: [0, 11], year: ex: 2011, hours: [0, 23], minutes: [0, 59], seconds: [0, 59], utcOffset: [-720,720]. WTF_EXPORT_PRIVATE String makeRFC2822DateString(unsigned dayOfWeek, unsigned day, unsigned month, unsigned year, unsigned hours, unsigned minutes, unsigned seconds, int utcOffset); diff --git a/Source/WTF/wtf/FastFloat.cpp b/Source/WTF/wtf/FastFloat.cpp index c4a98d44e87e3..a8d16dff88eea 100644 --- a/Source/WTF/wtf/FastFloat.cpp +++ b/Source/WTF/wtf/FastFloat.cpp @@ -30,7 +30,7 @@ namespace WTF { -double parseDouble(std::span string, size_t& parsedLength) +double parseDouble(std::span string, size_t& parsedLength) { double doubleValue = 0; auto stringData = byteCast(string.data()); diff --git a/Source/WTF/wtf/FastFloat.h b/Source/WTF/wtf/FastFloat.h index 11d1ee3ef0365..87fd60b560964 100644 --- a/Source/WTF/wtf/FastFloat.h +++ b/Source/WTF/wtf/FastFloat.h @@ -31,7 +31,7 @@ namespace WTF { -WTF_EXPORT_PRIVATE double parseDouble(std::span string, size_t& parsedLength); -WTF_EXPORT_PRIVATE double parseDouble(std::span string, size_t& parsedLength); +WTF_EXPORT_PRIVATE double parseDouble(std::span string, size_t& parsedLength); +WTF_EXPORT_PRIVATE double parseDouble(std::span string, size_t& parsedLength); } // namespace WTF diff --git a/Source/WTF/wtf/FileSystem.cpp b/Source/WTF/wtf/FileSystem.cpp index 8b8ef752e0cb4..efa42c826808e 100644 --- a/Source/WTF/wtf/FileSystem.cpp +++ b/Source/WTF/wtf/FileSystem.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #if !OS(WINDOWS) #include @@ -64,9 +65,10 @@ ALLOW_DEPRECATED_DECLARATIONS_END static String fromStdFileSystemPath(const std::filesystem::path& path) { #if HAVE(MISSING_U8STRING) - return String::fromUTF8(span8(path.u8string().c_str())); + // FIXME: This uses u8string so how can it be correct inside HAVE(MISSING_U8STRING)? + return String::fromUTF8(unsafeSpan(path.u8string().c_str())); #else - return String::fromUTF8(span(path.u8string())); + return span(path.u8string()); #endif } diff --git a/Source/WTF/wtf/HexNumber.cpp b/Source/WTF/wtf/HexNumber.cpp index d0a3c185e15ca..80d9d05ff288b 100644 --- a/Source/WTF/wtf/HexNumber.cpp +++ b/Source/WTF/wtf/HexNumber.cpp @@ -27,7 +27,14 @@ namespace WTF { namespace Internal { -std::pair appendHex(LChar* buffer, unsigned bufferSize, std::uintmax_t number, unsigned minimumDigits, HexConversionMode mode) +static const Latin1Character* hexDigitsForMode(HexConversionMode mode) +{ + static const Latin1Character lowercaseHexDigits[17] = "0123456789abcdef"; + static const Latin1Character uppercaseHexDigits[17] = "0123456789ABCDEF"; + return mode == Lowercase ? lowercaseHexDigits : uppercaseHexDigits; +} + +std::pair appendHex(Latin1Character* buffer, unsigned bufferSize, std::uintmax_t number, unsigned minimumDigits, HexConversionMode mode) { auto end = buffer + bufferSize; auto start = end; diff --git a/Source/WTF/wtf/HexNumber.h b/Source/WTF/wtf/HexNumber.h index 1f577ede13a78..8e95629bfe3ec 100644 --- a/Source/WTF/wtf/HexNumber.h +++ b/Source/WTF/wtf/HexNumber.h @@ -29,17 +29,10 @@ enum HexConversionMode { Lowercase, Uppercase }; namespace Internal { -inline const LChar* hexDigitsForMode(HexConversionMode mode) -{ - static const LChar lowercaseHexDigits[17] = "0123456789abcdef"; - static const LChar uppercaseHexDigits[17] = "0123456789ABCDEF"; - return mode == Lowercase ? lowercaseHexDigits : uppercaseHexDigits; -} - -WTF_EXPORT_PRIVATE std::pair appendHex(LChar* buffer, unsigned bufferSize, std::uintmax_t number, unsigned minimumDigits, HexConversionMode); +WTF_EXPORT_PRIVATE std::pair appendHex(Latin1Character* buffer, unsigned bufferSize, std::uintmax_t number, unsigned minimumDigits, HexConversionMode); template -inline std::pair appendHex(std::array& buffer, NumberType number, unsigned minimumDigits, HexConversionMode mode) +inline std::pair appendHex(std::array& buffer, NumberType number, unsigned minimumDigits, HexConversionMode mode) { return appendHex(&buffer.front(), buffer.size(), static_cast::type>(number), minimumDigits, mode); } @@ -49,10 +42,10 @@ inline std::pair appendHex(std::array& buffe struct HexNumberBuffer { WTF_MAKE_STRUCT_FAST_ALLOCATED; - std::array buffer; + std::array buffer; unsigned length; - std::span span() const LIFETIME_BOUND { return std::span { buffer }.last(length); } + std::span span() const LIFETIME_BOUND { return std::span { buffer }.last(length); } }; template HexNumberBuffer hex(NumberType number, unsigned minimumDigits = 0, HexConversionMode mode = Uppercase) diff --git a/Source/WTF/wtf/Int128.cpp b/Source/WTF/wtf/Int128.cpp index 8326873032bf8..bb2d03d9c70bb 100644 --- a/Source/WTF/wtf/Int128.cpp +++ b/Source/WTF/wtf/Int128.cpp @@ -302,7 +302,7 @@ std::ostream& operator<<(std::ostream& os, Int128Impl v) { void printInternal(PrintStream& out, UInt128 value) { - auto vector = numberToStringUnsigned>(value); + auto vector = numberToStringUnsigned>(value); vector.append('\0'); out.printf("%s", std::bit_cast(vector.data())); } @@ -318,7 +318,7 @@ void printInternal(PrintStream& out, Int128 value) positive = static_cast(0x8000'0000'0000'0000ULL) << 64; else positive = -value; - auto vector = numberToStringUnsigned>(positive); + auto vector = numberToStringUnsigned>(positive); vector.append('\0'); out.printf("-%s", std::bit_cast(vector.data())); } diff --git a/Source/WTF/wtf/JSONValues.cpp b/Source/WTF/wtf/JSONValues.cpp index a22c907801b54..5673a469276fd 100644 --- a/Source/WTF/wtf/JSONValues.cpp +++ b/Source/WTF/wtf/JSONValues.cpp @@ -545,7 +545,7 @@ RefPtr Value::parseJSON(StringView json) RefPtr result; if (json.is8Bit()) { auto data = json.span8(); - std::span tokenEnd; + std::span tokenEnd; result = buildValue(data, tokenEnd, 0); if (containsNonSpace(tokenEnd)) return nullptr; diff --git a/Source/WTF/wtf/Logger.cpp b/Source/WTF/wtf/Logger.cpp index c806bfec5efac..dc96a9d4fbedd 100644 --- a/Source/WTF/wtf/Logger.cpp +++ b/Source/WTF/wtf/Logger.cpp @@ -39,8 +39,8 @@ Lock messageHandlerLoggerObserverLock; String Logger::LogSiteIdentifier::toString() const { if (className) - return makeString(className, "::"_s, span(methodName), '(', hex(objectPtr), ") "_s); - return makeString(span(methodName), '(', hex(objectPtr), ") "_s); + return makeString(className, "::"_s, unsafeSpan(methodName), '(', hex(objectPtr), ") "_s); + return makeString(unsafeSpan(methodName), '(', hex(objectPtr), ") "_s); } String LogArgument::toString(const void* argument) diff --git a/Source/WTF/wtf/Logger.h b/Source/WTF/wtf/Logger.h index 9f0de7bc2bdf5..19189285e6049 100644 --- a/Source/WTF/wtf/Logger.h +++ b/Source/WTF/wtf/Logger.h @@ -57,6 +57,7 @@ struct LogArgument { template static std::enable_if_t, StringBuilder*>, String> toString(StringBuilder* argument) { return argument->toString(); } template static std::enable_if_t, String> toString(const char* argument) { return String::fromLatin1(argument); } template static std::enable_if_t, String> toString(ASCIILiteral argument) { return argument; } + template static std::enable_if_t>, String> toString(std::span argument) { return argument; } #ifdef __OBJC__ template static std::enable_if_t>, String> toString(NSError *argument) { return String(argument.localizedDescription); } template static std::enable_if_t>, String> toString(NSObject *argument) { return String(argument.description); } diff --git a/Source/WTF/wtf/PlatformGTK.cmake b/Source/WTF/wtf/PlatformGTK.cmake index 296a8959b70f9..bbbd6dc797ef3 100644 --- a/Source/WTF/wtf/PlatformGTK.cmake +++ b/Source/WTF/wtf/PlatformGTK.cmake @@ -7,6 +7,7 @@ list(APPEND WTF_SOURCES glib/Application.cpp glib/ChassisType.cpp glib/FileSystemGlib.cpp + glib/GMallocString.cpp glib/GRefPtr.cpp glib/GSocketMonitor.cpp glib/GSpanExtras.cpp @@ -30,6 +31,7 @@ list(APPEND WTF_SOURCES list(APPEND WTF_PUBLIC_HEADERS glib/Application.h glib/ChassisType.h + glib/GMallocString.h glib/GMutexLocker.h glib/GRefPtr.h glib/GSocketMonitor.h diff --git a/Source/WTF/wtf/PlatformWPE.cmake b/Source/WTF/wtf/PlatformWPE.cmake index 0d71ecb15478f..163a6a46eb3b8 100644 --- a/Source/WTF/wtf/PlatformWPE.cmake +++ b/Source/WTF/wtf/PlatformWPE.cmake @@ -6,6 +6,7 @@ list(APPEND WTF_SOURCES glib/Application.cpp glib/ChassisType.cpp glib/FileSystemGlib.cpp + glib/GMallocString.cpp glib/GRefPtr.cpp glib/GSocketMonitor.cpp glib/GSpanExtras.cpp @@ -33,6 +34,7 @@ list(APPEND WTF_SOURCES list(APPEND WTF_PUBLIC_HEADERS glib/Application.h glib/ChassisType.h + glib/GMallocString.h glib/GMutexLocker.h glib/GRefPtr.h glib/GSocketMonitor.h diff --git a/Source/WTF/wtf/PrintStream.cpp b/Source/WTF/wtf/PrintStream.cpp index 250febc4b75d6..01f00ae5c83de 100644 --- a/Source/WTF/wtf/PrintStream.cpp +++ b/Source/WTF/wtf/PrintStream.cpp @@ -119,6 +119,11 @@ void printInternal(PrintStream& out, const StringImpl* string) printExpectedCStringHelper(out, "StringImpl*", string->tryGetUTF8()); } +void printInternal(PrintStream& stream, std::span codeUnits) +{ + printInternal(stream, byteCast(codeUnits)); +} + void printInternal(PrintStream& out, bool value) { out.print(boolForPrinting(value)); diff --git a/Source/WTF/wtf/PrintStream.h b/Source/WTF/wtf/PrintStream.h index 352637c34f52f..aa8e5961f5166 100644 --- a/Source/WTF/wtf/PrintStream.h +++ b/Source/WTF/wtf/PrintStream.h @@ -113,6 +113,7 @@ WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const CString&); WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const String&); WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const AtomString&); WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const StringImpl*); +WTF_EXPORT_PRIVATE void printInternal(PrintStream&, std::span); inline void printInternal(PrintStream& out, const AtomStringImpl* value) { printInternal(out, std::bit_cast(value)); } inline void printInternal(PrintStream& out, const UniquedStringImpl* value) { printInternal(out, std::bit_cast(value)); } inline void printInternal(PrintStream& out, const UniquedStringImpl& value) { printInternal(out, &value); } diff --git a/Source/WTF/wtf/SIMDHelpers.h b/Source/WTF/wtf/SIMDHelpers.h index 1344580fd21a7..bbb8431c0535f 100644 --- a/Source/WTF/wtf/SIMDHelpers.h +++ b/Source/WTF/wtf/SIMDHelpers.h @@ -466,7 +466,7 @@ ALWAYS_INLINE std::optional findFirstNonZeroIndex(simde_uint64x2_t valu #endif } -template +template ALWAYS_INLINE simde_uint8x16_t equal(simde_uint8x16_t input) { auto result = simde_vceqq_u8(input, simde_vmovq_n_u8(character)); diff --git a/Source/WTF/wtf/StdLibExtras.h b/Source/WTF/wtf/StdLibExtras.h index 35a5e57b63cd0..cc42c3cdbb119 100644 --- a/Source/WTF/wtf/StdLibExtras.h +++ b/Source/WTF/wtf/StdLibExtras.h @@ -37,6 +37,7 @@ #include #include #include +#include #include // Use this macro to declare and define a debug-only global variable that may have a @@ -779,31 +780,77 @@ int compareSpans(std::span a, std::span b) return result; } -template concept ByteType = sizeof(T) == 1 && ((std::is_integral_v && !std::same_as) || std::same_as) && !std::is_const_v; +template +concept TriviallyComparableCodeUnits = std::is_same_v, std::remove_const_t> || (!std::is_same_v, char8_t> && !std::is_same_v, char8_t>); + +template +concept CanBeConstByteType = sizeof(T) == 1 && ((std::is_integral_v && !std::same_as) || std::same_as); + +template +concept TriviallyComparableOneByteCodeUnits = TriviallyComparableCodeUnits && CanBeConstByteType && CanBeConstByteType; + +// Returns the index of the first occurrence of |needed| in |haystack| or notFound if not present. +template + requires(TriviallyComparableOneByteCodeUnits) +size_t find(std::span haystack, std::span needle) +{ + if (needle.empty()) + return 0; + +#if !HAVE(MEMMEM) + if (haystack.size() < needle.size()) + return notFound; + + size_t lastPossiblePosition = haystack.size() - needle.size(); + + for (size_t i = 0; i <= lastPossiblePosition; ++i) { + auto candidateSpan = haystack.subspan(i, needle.size()); + if (equalSpans(candidateSpan, needle)) + return i; + } + + return notFound; +#else + auto* result = static_cast(memmem(haystack.data(), haystack.size(), needle.data(), needle.size())); // NOLINT + if (!result) + return notFound; + return result - haystack.data(); +#endif +} + +template + requires(TriviallyComparableOneByteCodeUnits) +size_t contains(std::span haystack, std::span needle) +{ + return find(haystack, needle) != notFound; +} + +template +concept NonConstByteType = CanBeConstByteType && !std::is_const_v; template struct ByteCastTraits; -template struct ByteCastTraits { - template static constexpr U cast(T character) { return static_cast(character); } +template struct ByteCastTraits { + template static constexpr U cast(T character) { return static_cast(character); } }; -template struct ByteCastTraits { - template static constexpr auto cast(T* pointer) { return std::bit_cast(pointer); } +template struct ByteCastTraits { + template static constexpr auto cast(T* pointer) { return std::bit_cast(pointer); } }; -template struct ByteCastTraits { - template static constexpr auto cast(const T* pointer) { return std::bit_cast(pointer); } +template struct ByteCastTraits { + template static constexpr auto cast(const T* pointer) { return std::bit_cast(pointer); } }; -template struct ByteCastTraits> { - template static constexpr auto cast(std::span span) { return spanReinterpretCast(span); } +template struct ByteCastTraits> { + template static constexpr auto cast(std::span span) { return spanReinterpretCast(span); } }; -template struct ByteCastTraits> { - template static constexpr auto cast(std::span span) { return spanReinterpretCast(span); } +template struct ByteCastTraits> { + template static constexpr auto cast(std::span span) { return spanReinterpretCast(span); } }; -template constexpr auto byteCast(const U& value) +template constexpr auto byteCast(const U& value) { return ByteCastTraits::template cast(value); } @@ -850,6 +897,7 @@ using WTF::bitwise_cast; using WTF::byteCast; using WTF::callStatelessLambda; using WTF::checkAndSet; +using WTF::compareSpans; using WTF::constructFixedSizeArrayWithArguments; using WTF::equalSpans; using WTF::findBitInWord; diff --git a/Source/WTF/wtf/URL.cpp b/Source/WTF/wtf/URL.cpp index be52bd9f501b3..39e1c5ff11bc9 100644 --- a/Source/WTF/wtf/URL.cpp +++ b/Source/WTF/wtf/URL.cpp @@ -189,7 +189,7 @@ String URL::protocolHostAndPort() const ); } -static std::optional decodeEscapeSequence(StringView input, unsigned index, unsigned length) +static std::optional decodeEscapeSequence(StringView input, unsigned index, unsigned length) { if (index + 3 > length || input[index] != '%') return std::nullopt; @@ -209,7 +209,7 @@ static String decodeEscapeSequencesFromParsedURL(StringView input) return input.toString(); // FIXME: This 100 is arbitrary. Should make a histogram of how this function is actually used to choose a better value. - Vector percentDecoded; + Vector percentDecoded; percentDecoded.reserveInitialCapacity(length); for (unsigned i = 0; i < length; ) { if (auto decodedCharacter = decodeEscapeSequence(input, i, length)) { diff --git a/Source/WTF/wtf/URLParser.cpp b/Source/WTF/wtf/URLParser.cpp index bc3ca0a63e2e0..699e140c7213c 100644 --- a/Source/WTF/wtf/URLParser.cpp +++ b/Source/WTF/wtf/URLParser.cpp @@ -410,7 +410,7 @@ ALWAYS_INLINE void URLParser::appendToASCIIBuffer(char32_t codePoint) m_asciiBuffer.append(codePoint); } -ALWAYS_INLINE void URLParser::appendToASCIIBuffer(std::span characters) +ALWAYS_INLINE void URLParser::appendToASCIIBuffer(std::span characters) { if (UNLIKELY(m_didSeeSyntaxViolation)) m_asciiBuffer.append(characters); @@ -475,7 +475,7 @@ bool URLParser::shouldCopyFileURL(CodePointIterator iterator) return !isSlashQuestionOrHash(*iterator); } -static void percentEncodeByte(uint8_t byte, Vector& buffer) +static void percentEncodeByte(uint8_t byte, Vector& buffer) { buffer.append('%'); buffer.append(upperNibbleToASCIIHexDigit(byte)); @@ -971,7 +971,7 @@ bool URLParser::shouldPopPath(unsigned newPathAfterLastSlash) return true; ASSERT(m_url.m_pathAfterLastSlash <= m_asciiBuffer.size()); - CodePointIterator componentToPop({ &m_asciiBuffer[newPathAfterLastSlash], &m_asciiBuffer[0] + m_url.m_pathAfterLastSlash }); + CodePointIterator componentToPop({ &m_asciiBuffer[newPathAfterLastSlash], &m_asciiBuffer[0] + m_url.m_pathAfterLastSlash }); if (newPathAfterLastSlash == m_url.m_hostEnd + m_url.m_portLength + 1 && isWindowsDriveLetter(componentToPop)) return false; return true; @@ -1051,8 +1051,8 @@ bool URLParser::isAtLocalhost(CodePointIterator iterator) bool URLParser::isLocalhost(StringView view) { if (view.is8Bit()) - return isAtLocalhost(view.span8()); - return isAtLocalhost(view.span16()); + return isAtLocalhost(view.span8()); + return isAtLocalhost(view.span16()); } ALWAYS_INLINE StringView URLParser::parsedDataView(size_t start, size_t length) @@ -2078,9 +2078,9 @@ void URLParser::parseAuthority(CodePointIterator iterator) template void URLParser::appendNumberToASCIIBuffer(UnsignedIntegerType number) { - LChar buf[sizeof(UnsignedIntegerType) * 3 + 1]; - LChar* end = std::end(buf); - LChar* p = end; + Latin1Character buf[sizeof(UnsignedIntegerType) * 3 + 1]; + Latin1Character* end = std::end(buf); + Latin1Character* p = end; do { *--p = (number % 10) + '0'; number /= 10; @@ -2476,7 +2476,7 @@ std::optional URLParser::parseIPv6Host(CodePointIterator } template -URLParser::LCharBuffer URLParser::percentDecode(std::span input, const CodePointIterator& iteratorForSyntaxViolationPosition) +URLParser::LCharBuffer URLParser::percentDecode(std::span input, const CodePointIterator& iteratorForSyntaxViolationPosition) { LCharBuffer output; output.reserveInitialCapacity(input.size()); @@ -2498,7 +2498,7 @@ URLParser::LCharBuffer URLParser::percentDecode(std::span input, co return output; } -URLParser::LCharBuffer URLParser::percentDecode(std::span input) +URLParser::LCharBuffer URLParser::percentDecode(std::span input) { LCharBuffer output; output.reserveInitialCapacity(input.size()); @@ -2705,8 +2705,8 @@ bool URLParser::subdomainStartsWithXNDashDash(CodePointIterator i bool URLParser::subdomainStartsWithXNDashDash(StringImpl& host) { if (host.is8Bit()) - return subdomainStartsWithXNDashDash(host.span8()); - return subdomainStartsWithXNDashDash(host.span16()); + return subdomainStartsWithXNDashDash(host.span8()); + return subdomainStartsWithXNDashDash(host.span16()); } static bool dnsNameEndsInNumber(StringView name) @@ -2860,9 +2860,9 @@ auto URLParser::parseHostAndPort(CodePointIterator iterator) -> H if (!asciiDomain || hasForbiddenHostCodePoint(asciiDomain.value())) return HostParsingResult::InvalidHost; LCharBuffer& asciiDomainValue = asciiDomain.value(); - const LChar* asciiDomainCharacters = asciiDomainValue.data(); + const Latin1Character* asciiDomainCharacters = asciiDomainValue.data(); - auto address = parseIPv4Host(hostBegin, asciiDomainValue.span()); + auto address = parseIPv4Host(hostBegin, asciiDomainValue.span()); if (address) { serializeIPv4(address.value()); m_url.m_hostEnd = currentPosition(iterator); @@ -2892,7 +2892,7 @@ std::optional URLParser::formURLDecode(StringView input) auto utf8 = input.utf8(StrictConversion); if (utf8.isNull()) return std::nullopt; - auto percentDecoded = percentDecode(utf8.span()); + auto percentDecoded = percentDecode(byteCast(utf8.span())); return String::fromUTF8ReplacingInvalidSequences(percentDecoded.span()); } @@ -2923,7 +2923,7 @@ std::optional> URLParser::parseQueryNameAndValue(St return std::nullopt; } -static void serializeURLEncodedForm(const String& input, Vector& output) +static void serializeURLEncodedForm(const String& input, Vector& output) { auto utf8 = input.utf8(StrictConversion); for (char byte : utf8.span()) { @@ -2947,7 +2947,7 @@ String URLParser::serialize(const URLEncodedForm& tuples) if (tuples.isEmpty()) return { }; - Vector output; + Vector output; for (auto& tuple : tuples) { if (!output.isEmpty()) output.append('&'); diff --git a/Source/WTF/wtf/URLParser.h b/Source/WTF/wtf/URLParser.h index d371bf592564b..20b035fccb015 100644 --- a/Source/WTF/wtf/URLParser.h +++ b/Source/WTF/wtf/URLParser.h @@ -78,7 +78,7 @@ class URLParser { friend class URL; URL m_url; - Vector m_asciiBuffer; + Vector m_asciiBuffer; bool m_urlIsSpecial { false }; bool m_urlIsFile { false }; bool m_hostHasPercentOrNonASCII { false }; @@ -87,7 +87,7 @@ class URLParser { const void* m_inputBegin { nullptr }; static constexpr size_t defaultInlineBufferSize = 2048; - using LCharBuffer = Vector; + using LCharBuffer = Vector; template void parse(std::span, const URL&, const URLTextEncoding*); template void parseAuthority(CodePointIterator); @@ -119,13 +119,13 @@ class URLParser { template void utf8PercentEncode(const CodePointIterator&); template void utf8QueryEncode(const CodePointIterator&); template std::optional domainToASCII(StringImpl&, const CodePointIterator& iteratorForSyntaxViolationPosition); - template LCharBuffer percentDecode(std::span, const CodePointIterator& iteratorForSyntaxViolationPosition); - static LCharBuffer percentDecode(std::span); + template LCharBuffer percentDecode(std::span, const CodePointIterator& iteratorForSyntaxViolationPosition); + static LCharBuffer percentDecode(std::span); bool hasForbiddenHostCodePoint(const LCharBuffer&); void percentEncodeByte(uint8_t); void appendToASCIIBuffer(char32_t); - void appendToASCIIBuffer(std::span); - template void encodeNonUTF8Query(const Vector& source, const URLTextEncoding&, CodePointIterator); + void appendToASCIIBuffer(std::span); + template void encodeNonUTF8Query(const Vector& source, const URLTextEncoding&, CodePointIterator); void copyASCIIStringUntil(const String&, size_t length); bool copyBaseWindowsDriveLetter(const URL&); StringView parsedDataView(size_t start, size_t length) LIFETIME_BOUND; diff --git a/Source/WTF/wtf/WTFConfig.cpp b/Source/WTF/wtf/WTFConfig.cpp index 828d97700787b..7a69980c9a982 100644 --- a/Source/WTF/wtf/WTFConfig.cpp +++ b/Source/WTF/wtf/WTFConfig.cpp @@ -117,7 +117,7 @@ void Config::initialize() reservedConfigBytes[WebConfig::ReservedByteForAllocationProfiling] = 0; const char* useAllocationProfilingRaw = getenv("JSC_useAllocationProfiling"); if (useAllocationProfilingRaw) { - auto useAllocationProfiling = span(useAllocationProfilingRaw); + auto useAllocationProfiling = unsafeSpan(useAllocationProfilingRaw); if (equalLettersIgnoringASCIICase(useAllocationProfiling, "true"_s) || equalLettersIgnoringASCIICase(useAllocationProfiling, "yes"_s) || equal(useAllocationProfiling, "1"_s)) diff --git a/Source/WTF/wtf/cf/CFURLExtras.cpp b/Source/WTF/wtf/cf/CFURLExtras.cpp index b5f2c02944ba7..b9cd0896af2ef 100644 --- a/Source/WTF/wtf/cf/CFURLExtras.cpp +++ b/Source/WTF/wtf/cf/CFURLExtras.cpp @@ -54,9 +54,9 @@ String bytesAsString(CFURLRef url) auto bytesLength = CFURLGetBytes(url, nullptr, 0); RELEASE_ASSERT(bytesLength != -1); RELEASE_ASSERT(bytesLength <= static_cast(String::MaxLength)); - LChar* buffer; + Latin1Character* buffer; auto result = String::createUninitialized(bytesLength, buffer); - CFURLGetBytes(url, buffer, bytesLength); + CFURLGetBytes(url, byteCast(buffer()), bytesLength); return result; } @@ -90,7 +90,7 @@ bool isSameOrigin(CFURLRef a, const URL& b) auto aBytes = bytesAsVector(a); RELEASE_ASSERT(aBytes.size() <= String::MaxLength); - StringView aString { aBytes.span() }; + StringView aString { byteCast(aBytes.span()) }; StringView bString { b.string() }; if (!b.hasPath()) diff --git a/Source/WTF/wtf/cocoa/NSURLExtras.mm b/Source/WTF/wtf/cocoa/NSURLExtras.mm index 9388cc947b9fa..893c9dcfce4c5 100644 --- a/Source/WTF/wtf/cocoa/NSURLExtras.mm +++ b/Source/WTF/wtf/cocoa/NSURLExtras.mm @@ -317,7 +317,7 @@ static bool hasQuestionMarkOnlyQueryString(NSURL *URL) NSString *userVisibleString(NSURL *URL) { - return URLHelpers::userVisibleURL(span(originalURLData(URL))); + return URLHelpers::userVisibleURL(byteCast(span(originalURLData(URL)))); } BOOL isUserVisibleURL(NSString *string) diff --git a/Source/WTF/wtf/glib/Application.cpp b/Source/WTF/wtf/glib/Application.cpp index 349c1ccbf367b..760a0f196b6cf 100644 --- a/Source/WTF/wtf/glib/Application.cpp +++ b/Source/WTF/wtf/glib/Application.cpp @@ -57,7 +57,7 @@ const CString& applicationID() // and won't flood xdg-desktop-portal with new ids. if (auto executablePath = FileSystem::currentExecutablePath(); !executablePath.isNull()) { GUniquePtr digest(g_compute_checksum_for_data(G_CHECKSUM_SHA256, reinterpret_cast(executablePath.data()), executablePath.length())); - id.get() = makeString("org.webkit.app-"_s, span(digest.get())).utf8(); + id.get() = makeString("org.webkit.app-"_s, unsafeSpan(digest.get())).utf8(); return; } diff --git a/Source/WTF/wtf/glib/GMallocString.cpp b/Source/WTF/wtf/glib/GMallocString.cpp new file mode 100644 index 0000000000000..4cbcfa69eb278 --- /dev/null +++ b/Source/WTF/wtf/glib/GMallocString.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 Yusuke Suzuki + * Copyright (C) 2024 Apple Inc. All Rights Reserved. + * Copyright (C) 2025 Comcast Inc. + * Copyright (C) 2025 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include + +#include + +namespace WTF { + +void GMallocString::dump(PrintStream& out) const +{ + out.print(span()); +} + +} // namespace WTF diff --git a/Source/WTF/wtf/glib/GMallocString.h b/Source/WTF/wtf/glib/GMallocString.h new file mode 100644 index 0000000000000..0582e302e0d39 --- /dev/null +++ b/Source/WTF/wtf/glib/GMallocString.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2018 Yusuke Suzuki + * Copyright (C) 2024 Apple Inc. All Rights Reserved. + * Copyright (C) 2025 Comcast Inc. + * Copyright (C) 2025 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace WTF { + +class PrintStream; + +class GMallocString final { + WTF_FORBID_HEAP_ALLOCATION; + WTF_MAKE_NONCOPYABLE(GMallocString); +public: + + static GMallocString unsafeAdoptFromUTF8(char* string) + { + if (!string) + return GMallocString(); + return GMallocString { adoptGMallocSpan(unsafeMakeSpan(byteCast(string), string ? std::char_traits::length(string) + 1 : 0)) }; + } + + static GMallocString unsafeAdoptFromUTF8(GUniquePtr&& pointer) + { + return unsafeAdoptFromUTF8(pointer.release()); + } + + static GMallocString unsafeAdoptFromUTF8(GUniqueOutPtr&& pointer) + { + return unsafeAdoptFromUTF8(pointer.release()); + } + + static GMallocString adoptFromUTF8(std::span string) + { + if (string.size() < 1) + return GMallocString(); + RELEASE_ASSERT(string[string.size() - 1] == '\0'); + return GMallocString { adoptGMallocSpan(byteCast(string)) }; + } + + explicit GMallocString(const CStringView& view) + { + m_spanWithNullTerminator = dupGMallocSpan(view.spanIncludingNullTerminator()); + } + + WTF_EXPORT_PRIVATE void dump(PrintStream& out) const; + + GMallocString() = default; + constexpr GMallocString(std::nullptr_t) + : GMallocString() + { } + + GMallocString(GMallocString&& other) + : m_spanWithNullTerminator(WTFMove(other.m_spanWithNullTerminator)) + { + } + GMallocString& operator=(GMallocString&& other) + { + GMallocSpan otherSpan = WTFMove(other.m_spanWithNullTerminator); + std::swap(m_spanWithNullTerminator, otherSpan); + return *this; + } + + bool isNull() const { return m_spanWithNullTerminator.span().empty(); } + const char* utf8() const LIFETIME_BOUND { return byteCast(m_spanWithNullTerminator.span().data()); } + WARN_UNUSED_RETURN char* leakUTF8() { return byteCast(m_spanWithNullTerminator.leakSpan().data()); } + size_t lengthInBytes() const { return !m_spanWithNullTerminator.span().empty() ? m_spanWithNullTerminator.span().size() - 1 : 0; } + std::span span() const LIFETIME_BOUND { return m_spanWithNullTerminator.span().first(lengthInBytes()); } + std::span spanIncludingNullTerminator() const LIFETIME_BOUND { return m_spanWithNullTerminator.span(); } + size_t isEmpty() const { return m_spanWithNullTerminator.span().size() <= 1; } + + explicit operator bool() const { return !isEmpty(); } + bool operator!() const { return isEmpty(); } + +private: + explicit GMallocString(GMallocSpan&& string) + : m_spanWithNullTerminator(WTFMove(string)) + { + } + + GMallocSpan m_spanWithNullTerminator; +}; + +inline bool operator==(const GMallocString& a, const GMallocString& b) +{ + return equal(a.span(), b.span()); +} + +inline bool operator==(const GMallocString& a, ASCIILiteral b) +{ + return equal(a.span(), byteCast(b.span())); +} + +inline bool operator==(const GMallocString& a, CStringView b) +{ + return equal(a.span(), b.span()); +} + +// GMallocString is null terminated +inline const char* safePrintfType(const GMallocString& string) { return string.utf8(); } + +inline CStringView toCStringView(const GMallocString& string LIFETIME_BOUND) { return CStringView::fromUTF8(string.spanIncludingNullTerminator()); } + +} // namespace WTF + +using WTF::GMallocString; +using WTF::toCStringView; diff --git a/Source/WTF/wtf/glib/GSpanExtras.cpp b/Source/WTF/wtf/glib/GSpanExtras.cpp index 1d5bbd526e2dd..7bc2f23d0fcfd 100644 --- a/Source/WTF/wtf/glib/GSpanExtras.cpp +++ b/Source/WTF/wtf/glib/GSpanExtras.cpp @@ -21,26 +21,31 @@ #include #include +#include namespace WTF { -GMallocSpan gFileGetContents(const char* path, GUniqueOutPtr& error) +Expected, GUniquePtr> gFileGetContents(CStringView path) { char* contents; gsize length; - if (!g_file_get_contents(path, &contents, &length, &error.outPtr())) - return { }; + GUniqueOutPtr error; + if (!g_file_get_contents(path.utf8(), &contents, &length, &error.outPtr())) + return makeUnexpected(GUniquePtr(error.release())); return adoptGMallocSpan(unsafeMakeSpan(contents, length)); } -GMallocSpan gKeyFileGetKeys(GKeyFile* keyFile, const char* groupName, GUniqueOutPtr& error) +Expected, GUniquePtr> gKeyFileGetKeys(GKeyFile* keyFile, CStringView groupName) { ASSERT(keyFile); ASSERT(groupName); size_t keyCount = 0; - char** keys = g_key_file_get_keys(keyFile, groupName, &keyCount, &error.outPtr()); + GUniqueOutPtr error; + char** keys = g_key_file_get_keys(keyFile, groupName.utf8(), &keyCount, &error.outPtr()); + if (error) + return makeUnexpected(GUniquePtr(error.release())); return adoptGMallocSpan(unsafeMakeSpan(keys, keyCount)); } diff --git a/Source/WTF/wtf/glib/GSpanExtras.h b/Source/WTF/wtf/glib/GSpanExtras.h index 5934331f61112..d400568cd6954 100644 --- a/Source/WTF/wtf/glib/GSpanExtras.h +++ b/Source/WTF/wtf/glib/GSpanExtras.h @@ -19,6 +19,7 @@ #pragma once +#include #include #include #include @@ -36,6 +37,8 @@ void g_strfreev(char**); namespace WTF { +class CStringView; + struct GMalloc { static void* malloc(size_t size) { return g_malloc(size); } static void* tryMalloc(size_t size) { return g_try_malloc(size); } @@ -64,8 +67,16 @@ GMallocSpan adoptGMallocSpan(std::span span) return adoptMallocSpan(span); } -WTF_EXPORT_PRIVATE GMallocSpan gFileGetContents(const char* path, GUniqueOutPtr&); -WTF_EXPORT_PRIVATE GMallocSpan gKeyFileGetKeys(GKeyFile*, const char* groupName, GUniqueOutPtr&); +template +GMallocSpan dupGMallocSpan(std::span span) +{ + auto duplicate = GMallocSpan::malloc(span.size_bytes()); + memcpySpan(duplicate.mutableSpan(), span); + return duplicate; +} + +WTF_EXPORT_PRIVATE Expected, GUniquePtr> gFileGetContents(CStringView); +WTF_EXPORT_PRIVATE Expected, GUniquePtr> gKeyFileGetKeys(GKeyFile*, CStringView groupName); WTF_EXPORT_PRIVATE GMallocSpan gObjectClassGetProperties(GObjectClass*); WTF_EXPORT_PRIVATE GMallocSpan gVariantGetStrv(const GRefPtr&); diff --git a/Source/WTF/wtf/persistence/PersistentCoders.cpp b/Source/WTF/wtf/persistence/PersistentCoders.cpp index d159ce8ec71a8..2b8160d588af5 100644 --- a/Source/WTF/wtf/persistence/PersistentCoders.cpp +++ b/Source/WTF/wtf/persistence/PersistentCoders.cpp @@ -100,7 +100,7 @@ void Coder::encodeForPersistence(Encoder& encoder, const String& string) encoder << string.length() << is8Bit; if (is8Bit) - encoder.encodeFixedLengthData(string.span8()); + encoder.encodeFixedLengthData(asBytes(string.span8())); else encoder.encodeFixedLengthData(asBytes(string.span16())); } @@ -138,8 +138,8 @@ std::optional Coder::decodeForPersistence(Decoder& decoder) return std::nullopt; if (*is8Bit) - return decodeStringText(decoder, *length); - return decodeStringText(decoder, *length); + return decodeStringText(decoder, *length); + return decodeStringText(decoder, *length); } void Coder::encodeForPersistence(Encoder& encoder, const URL& url) diff --git a/Source/WTF/wtf/text/ASCIIFastPath.h b/Source/WTF/wtf/text/ASCIIFastPath.h index e45b6be285028..0cd07229d284b 100644 --- a/Source/WTF/wtf/text/ASCIIFastPath.h +++ b/Source/WTF/wtf/text/ASCIIFastPath.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include #if CPU(X86_SSE2) #include @@ -57,7 +57,7 @@ template struct NonASCIIMask; template<> struct NonASCIIMask<4, UChar> { static inline uint32_t value() { return 0xFF80FF80U; } }; -template<> struct NonASCIIMask<4, LChar> { +template<> struct NonASCIIMask<4, Latin1Character> { static inline uint32_t value() { return 0x80808080U; } }; template<> struct NonASCIIMask<4, char8_t> { @@ -66,7 +66,7 @@ template<> struct NonASCIIMask<4, char8_t> { template<> struct NonASCIIMask<8, UChar> { static inline uint64_t value() { return 0xFF80FF80FF80FF80ULL; } }; -template<> struct NonASCIIMask<8, LChar> { +template<> struct NonASCIIMask<8, Latin1Character> { static inline uint64_t value() { return 0x8080808080808080ULL; } }; template<> struct NonASCIIMask<8, char8_t> { diff --git a/Source/WTF/wtf/text/ASCIILiteral.h b/Source/WTF/wtf/text/ASCIILiteral.h index c8f914a77c018..15dd7cd4c0ddc 100644 --- a/Source/WTF/wtf/text/ASCIILiteral.h +++ b/Source/WTF/wtf/text/ASCIILiteral.h @@ -63,7 +63,8 @@ class ASCIILiteral final { constexpr const char* characters() const { return m_charactersWithNullTerminator.data(); } constexpr size_t length() const { return !m_charactersWithNullTerminator.empty() ? m_charactersWithNullTerminator.size() - 1 : 0; } - std::span span8() const { return { std::bit_cast(characters()), length() }; } + constexpr std::span span() const { return m_charactersWithNullTerminator.first(length()); } + std::span span8() const { return byteCast(m_charactersWithNullTerminator.first(length())); } std::span spanIncludingNullTerminator() const { return m_charactersWithNullTerminator; } size_t isEmpty() const { return m_charactersWithNullTerminator.size() <= 1; } @@ -139,13 +140,18 @@ constexpr ASCIILiteral operator"" _s(const char* characters, size_t) return result; } -constexpr std::span operator"" _span(const char* characters, size_t n) +constexpr std::span operator"" _span(const char* characters, size_t n) { #if ASSERT_ENABLED for (size_t i = 0; i < n; ++i) ASSERT_UNDER_CONSTEXPR_CONTEXT(isASCII(characters[i])); #endif - return std::span { std::bit_cast(characters), n }; + return std::span { std::bit_cast(characters), n }; +} + +constexpr std::span operator""_span(const char8_t* characters, size_t n) +{ + return unsafeMakeSpan(characters, n); } } // inline StringLiterals diff --git a/Source/WTF/wtf/text/AdaptiveStringSearcher.h b/Source/WTF/wtf/text/AdaptiveStringSearcher.h index 7ba63a8af08ec..eb0d483a8d4b2 100644 --- a/Source/WTF/wtf/text/AdaptiveStringSearcher.h +++ b/Source/WTF/wtf/text/AdaptiveStringSearcher.h @@ -62,8 +62,8 @@ class AdaptiveStringSearcherBase { // to compensate for the algorithmic overhead compared to simple brute force. static constexpr int bmMinPatternLength = 7; - static constexpr bool exceedsOneByte(LChar) { return false; } - static constexpr bool exceedsOneByte(UChar c) { return c > 0xff; } + static constexpr bool exceedsOneByte(Latin1Character) { return false; } + static constexpr bool exceedsOneByte(char16_t c) { return c > 0xff; } template static inline int findFirstCharacter(std::span pattern, std::span subject, int index) diff --git a/Source/WTF/wtf/text/AtomString.cpp b/Source/WTF/wtf/text/AtomString.cpp index ec9494c58378a..bb99948d6aec5 100644 --- a/Source/WTF/wtf/text/AtomString.cpp +++ b/Source/WTF/wtf/text/AtomString.cpp @@ -58,12 +58,12 @@ ALWAYS_INLINE AtomString AtomString::convertASCIICase() const } return *this; SlowPath: - LChar localBuffer[localBufferSize]; + Latin1Character localBuffer[localBufferSize]; for (unsigned i = 0; i < failingIndex; ++i) localBuffer[i] = characters[i]; for (unsigned i = failingIndex; i < length; ++i) localBuffer[i] = type == CaseConvertType::Lower ? toASCIILower(characters[i]) : toASCIIUpper(characters[i]); - return std::span { localBuffer, length }; + return std::span { localBuffer, length }; } Ref convertedString = type == CaseConvertType::Lower ? impl->convertToASCIILowercase() : impl->convertToASCIIUppercase(); diff --git a/Source/WTF/wtf/text/AtomString.h b/Source/WTF/wtf/text/AtomString.h index ae6e4d2f46066..2a1cfdc815be6 100644 --- a/Source/WTF/wtf/text/AtomString.h +++ b/Source/WTF/wtf/text/AtomString.h @@ -20,6 +20,7 @@ #pragma once +#include "StringCommon.h" #include #include #include @@ -30,10 +31,10 @@ class AtomString final { WTF_MAKE_FAST_ALLOCATED; public: AtomString(); - AtomString(std::span); - AtomString(std::span); + AtomString(std::span); + AtomString(std::span); - ALWAYS_INLINE static AtomString fromLatin1(const char* characters) { return AtomString(characters); } + ALWAYS_INLINE static AtomString fromLatin1(const char *characters) { return AtomString(characters); } AtomString(AtomStringImpl*); AtomString(RefPtr&&); @@ -66,8 +67,8 @@ class AtomString final { RefPtr releaseImpl() { return static_pointer_cast(m_string.releaseImpl()); } bool is8Bit() const { return m_string.is8Bit(); } - std::span span8() const { return m_string.span8(); } - std::span span16() const { return m_string.span16(); } + std::span span8() const LIFETIME_BOUND { return m_string.span8(); } + std::span span16() const LIFETIME_BOUND { return m_string.span16(); } unsigned length() const { return m_string.length(); } UChar operator[](unsigned int i) const { return m_string[i]; } @@ -174,7 +175,7 @@ inline AtomString::AtomString(const char* string) { } -inline AtomString::AtomString(std::span string) +inline AtomString::AtomString(std::span string) : m_string(AtomStringImpl::add(string)) { } @@ -282,7 +283,7 @@ inline AtomString AtomString::fromUTF8(const char* characters) return nullAtom(); if (!*characters) return emptyAtom(); - return fromUTF8Internal(span(characters)); + return fromUTF8Internal(unsafeSpan(characters)); } inline AtomString String::toExistingAtomString() const @@ -341,7 +342,7 @@ ALWAYS_INLINE String WARN_UNUSED_RETURN makeStringByReplacingAll(const AtomStrin template<> struct IntegerToStringConversionTrait { using ReturnType = AtomString; using AdditionalArgumentType = void; - static AtomString flush(std::span characters, void*) { return characters; } + static AtomString flush(std::span characters, void*) { return characters; } }; } // namespace WTF diff --git a/Source/WTF/wtf/text/AtomStringImpl.cpp b/Source/WTF/wtf/text/AtomStringImpl.cpp index af90a6f6d8138..e215ca33b9c7d 100644 --- a/Source/WTF/wtf/text/AtomStringImpl.cpp +++ b/Source/WTF/wtf/text/AtomStringImpl.cpp @@ -133,7 +133,7 @@ struct HashedUTF8CharactersTranslator { return Unicode::equal(string->span16(), characters.characters); } - auto charactersLatin1 = spanReinterpretCast(characters.characters); + auto charactersLatin1 = spanReinterpretCast(characters.characters); if (string->is8Bit()) return WTF::equal(string->span8().data(), charactersLatin1); return WTF::equal(string->span16().data(), charactersLatin1); @@ -148,7 +148,7 @@ struct HashedUTF8CharactersTranslator { RELEASE_ASSERT(result.code == Unicode::ConversionResultCode::Success); if (result.isAllASCII) - newString = StringImpl::create(spanReinterpretCast(characters.characters)); + newString = StringImpl::create(spanReinterpretCast(characters.characters)); auto* pointer = &newString.leakRef(); pointer->setHash(hash); @@ -241,7 +241,7 @@ RefPtr AtomStringImpl::add(StringImpl* baseString, unsigned star return addToStringTable(buffer); } -using LCharBuffer = HashTranslatorCharBuffer; +using LCharBuffer = HashTranslatorCharBuffer; struct LCharBufferTranslator { static unsigned hash(const LCharBuffer& buf) { @@ -284,7 +284,7 @@ struct BufferFromStaticDataTranslator { } }; -RefPtr AtomStringImpl::add(HashTranslatorCharBuffer& buffer) +RefPtr AtomStringImpl::add(HashTranslatorCharBuffer& buffer) { if (!buffer.characters.data()) return nullptr; @@ -295,7 +295,7 @@ RefPtr AtomStringImpl::add(HashTranslatorCharBuffer& buff return addToStringTable(buffer); } -RefPtr AtomStringImpl::add(std::span characters) +RefPtr AtomStringImpl::add(std::span characters) { if (!characters.data()) return nullptr; @@ -307,13 +307,13 @@ RefPtr AtomStringImpl::add(std::span characters) return addToStringTable(buffer); } -Ref AtomStringImpl::addLiteral(std::span characters) +Ref AtomStringImpl::addLiteral(std::span characters) { ASSERT(characters.data()); ASSERT(!characters.empty()); LCharBuffer buffer { characters }; - return addToStringTable>(buffer); + return addToStringTable>(buffer); } static Ref addSymbol(AtomStringTableLocker& locker, StringTableImpl& atomStringTable, StringImpl& base) @@ -340,7 +340,7 @@ static Ref addStatic(AtomStringTableLocker& locker, StringTableI if (base.is8Bit()) { LCharBuffer buffer { base.span8(), base.hash() }; - return addToStringTable>(locker, atomStringTable, buffer); + return addToStringTable>(locker, atomStringTable, buffer); } UCharBuffer buffer { base.span16(), base.hash() }; return addToStringTable>(locker, atomStringTable, buffer); @@ -482,7 +482,7 @@ RefPtr AtomStringImpl::add(std::span characters) return addToStringTable(buffer); } -RefPtr AtomStringImpl::lookUp(std::span characters) +RefPtr AtomStringImpl::lookUp(std::span characters) { AtomStringTableLocker locker; auto& table = stringTable(); diff --git a/Source/WTF/wtf/text/AtomStringImpl.h b/Source/WTF/wtf/text/AtomStringImpl.h index db2b3f2ddbf66..8b733962c8184 100644 --- a/Source/WTF/wtf/text/AtomStringImpl.h +++ b/Source/WTF/wtf/text/AtomStringImpl.h @@ -20,6 +20,7 @@ #pragma once +#include "StringCommon.h" #include namespace WTF { @@ -28,18 +29,18 @@ class AtomStringTable; class SUPPRESS_REFCOUNTED_WITHOUT_VIRTUAL_DESTRUCTOR AtomStringImpl final : public UniquedStringImpl { public: - WTF_EXPORT_PRIVATE static RefPtr lookUp(std::span); - WTF_EXPORT_PRIVATE static RefPtr lookUp(std::span); + WTF_EXPORT_PRIVATE static RefPtr lookUp(std::span); + WTF_EXPORT_PRIVATE static RefPtr lookUp(std::span); static RefPtr lookUp(StringImpl*); static void remove(AtomStringImpl*); - WTF_EXPORT_PRIVATE static RefPtr add(std::span); - WTF_EXPORT_PRIVATE static RefPtr add(std::span); + WTF_EXPORT_PRIVATE static RefPtr add(std::span); + WTF_EXPORT_PRIVATE static RefPtr add(std::span); ALWAYS_INLINE static RefPtr add(std::span characters); - WTF_EXPORT_PRIVATE static RefPtr add(HashTranslatorCharBuffer&); - WTF_EXPORT_PRIVATE static RefPtr add(HashTranslatorCharBuffer&); + WTF_EXPORT_PRIVATE static RefPtr add(HashTranslatorCharBuffer&); + WTF_EXPORT_PRIVATE static RefPtr add(HashTranslatorCharBuffer&); WTF_EXPORT_PRIVATE static RefPtr add(StringImpl*, unsigned offset, unsigned length); ALWAYS_INLINE static RefPtr add(StringImpl*); @@ -69,7 +70,7 @@ class SUPPRESS_REFCOUNTED_WITHOUT_VIRTUAL_DESTRUCTOR AtomStringImpl final : publ ALWAYS_INLINE static Ref add(StringImpl&); ALWAYS_INLINE static Ref add(Ref&&); - WTF_EXPORT_PRIVATE static Ref addLiteral(std::span); + WTF_EXPORT_PRIVATE static Ref addLiteral(std::span); ALWAYS_INLINE static Ref add(AtomStringTable&, StringImpl&); @@ -89,7 +90,7 @@ inline RefPtr AtomStringImpl::lookUp(StringImpl* string) ALWAYS_INLINE RefPtr AtomStringImpl::add(std::span characters) { - return add(byteCast(characters)); + return add(byteCast(characters)); } ALWAYS_INLINE RefPtr AtomStringImpl::add(StringImpl* string) @@ -113,7 +114,7 @@ ALWAYS_INLINE Ref AtomStringImpl::add(ASCIILiteral literal) ALWAYS_INLINE RefPtr AtomStringImpl::addCString(const char* s) { - return s ? add(WTF::span8(s)) : nullptr; + return s ? add(byteCast(WTF::unsafeSpan(s))) : nullptr; } template diff --git a/Source/WTF/wtf/text/Base64.cpp b/Source/WTF/wtf/text/Base64.cpp index 33e84b99e983e..65095448983c8 100644 --- a/Source/WTF/wtf/text/Base64.cpp +++ b/Source/WTF/wtf/text/Base64.cpp @@ -175,7 +175,7 @@ void base64Encode(std::span input, std::span destination base64EncodeInternal(input, destination, options); } -void base64Encode(std::span input, std::span destination, OptionSet options) +void base64Encode(std::span input, std::span destination, OptionSet options) { if (!destination.size()) return; @@ -309,8 +309,8 @@ String base64DecodeToString(StringView input, OptionSet opti }; if (input.is8Bit()) - return toString(base64DecodeInternal(input.span8(), options)); - return toString(base64DecodeInternal(input.span16(), options)); + return toString(base64DecodeInternal(input.span8(), options)); + return toString(base64DecodeInternal(input.span16(), options)); } template diff --git a/Source/WTF/wtf/text/Base64.h b/Source/WTF/wtf/text/Base64.h index 71fc19071992d..7af1170a59ac6 100644 --- a/Source/WTF/wtf/text/Base64.h +++ b/Source/WTF/wtf/text/Base64.h @@ -57,8 +57,8 @@ WTF_EXPORT_PRIVATE unsigned calculateBase64EncodedSize(unsigned inputLength, Opt template bool isBase64OrBase64URLCharacter(CharacterType); -WTF_EXPORT_PRIVATE void base64Encode(std::span, std::span, OptionSet = { }); -WTF_EXPORT_PRIVATE void base64Encode(std::span, std::span, OptionSet = { }); +WTF_EXPORT_PRIVATE void base64Encode(std::span, std::span, OptionSet = { }); +WTF_EXPORT_PRIVATE void base64Encode(std::span, std::span, OptionSet = { }); WTF_EXPORT_PRIVATE Vector base64EncodeToVector(std::span, OptionSet = { }); Vector base64EncodeToVector(std::span, OptionSet = { }); diff --git a/Source/WTF/wtf/text/CString.cpp b/Source/WTF/wtf/text/CString.cpp index 571a851bc0381..8847fe3cc5d86 100644 --- a/Source/WTF/wtf/text/CString.cpp +++ b/Source/WTF/wtf/text/CString.cpp @@ -50,7 +50,7 @@ CString::CString(const char* string) if (!string) return; - init(WTF::span(string)); + init(WTF::unsafeSpan(string)); } CString::CString(std::span string) @@ -177,4 +177,30 @@ bool CStringHash::equal(const CString& a, const CString& b) return a == b; } +enum class ASCIICase { Lower, Upper }; + +template +CString convertASCIICase(std::span input) +{ + if (input.empty()) + return CString(""_s); + + std::span characters; + auto result = CString::newUninitialized(input.size(), characters); + size_t i = 0; + for (auto character : input) + characters[i++] = type == ASCIICase::Lower ? toASCIILower(character) : toASCIIUpper(character); + return result; +} + +CString convertToASCIILowercase(std::span string) +{ + return convertASCIICase(string); +} + +CString convertToASCIIUppercase(std::span string) +{ + return convertASCIICase(string); +} + } // namespace WTF diff --git a/Source/WTF/wtf/text/CString.h b/Source/WTF/wtf/text/CString.h index 8d127eab37e00..1ec7087610d40 100644 --- a/Source/WTF/wtf/text/CString.h +++ b/Source/WTF/wtf/text/CString.h @@ -46,7 +46,7 @@ class CStringBuffer final : public RefCounted { size_t length() const { return m_length; } WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN - std::span span() const LIFETIME_BOUND { return unsafeMakeSpan(reinterpret_cast_ptr(this + 1), m_length); } + std::span span() const LIFETIME_BOUND { return unsafeMakeSpan(reinterpret_cast_ptr(this + 1), m_length); } std::span spanIncludingNullTerminator() const LIFETIME_BOUND { return unsafeMakeSpan(reinterpret_cast_ptr(this + 1), m_length + 1); } WTF_ALLOW_UNSAFE_BUFFER_USAGE_END @@ -93,6 +93,7 @@ class CString final { size_t length() const; bool isNull() const { return !m_buffer; } + bool isEmpty() const { return isNull() || !m_buffer->length(); } bool isSafeToSendToAnotherThread() const; CStringBuffer* buffer() const LIFETIME_BOUND { return m_buffer.get(); } @@ -114,6 +115,9 @@ WTF_EXPORT_PRIVATE bool operator==(const CString&, const CString&); WTF_EXPORT_PRIVATE bool operator==(const CString&, const char*); WTF_EXPORT_PRIVATE bool operator<(const CString&, const CString&); +WTF_EXPORT_PRIVATE CString convertToASCIILowercase(std::span); +WTF_EXPORT_PRIVATE CString convertToASCIIUppercase(std::span); + struct CStringHash { static unsigned hash(const CString& string) { return string.hash(); } WTF_EXPORT_PRIVATE static bool equal(const CString& a, const CString& b); @@ -126,7 +130,7 @@ template<> struct DefaultHash : CStringHash { }; template struct HashTraits; template<> struct HashTraits : SimpleClassHashTraits { }; -inline CString::CString(std::span bytes) +inline CString::CString(std::span bytes) : CString(byteCast(bytes)) { } @@ -158,3 +162,5 @@ inline size_t CString::length() const } // namespace WTF using WTF::CString; +using WTF::convertToASCIILowercase; +using WTF::convertToASCIIUppercase; diff --git a/Source/WTF/wtf/text/CStringView.cpp b/Source/WTF/wtf/text/CStringView.cpp new file mode 100644 index 0000000000000..0c0eea1c1d33c --- /dev/null +++ b/Source/WTF/wtf/text/CStringView.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 Yusuke Suzuki + * Copyright (C) 2024 Apple Inc. All Rights Reserved. + * Copyright (C) 2025 Comcast Inc. + * Copyright (C) 2025 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include + +#include + +namespace WTF { + +void CStringView::dump(PrintStream& out) const +{ + out.print(span()); +} + +} // namespace WTF diff --git a/Source/WTF/wtf/text/CStringView.h b/Source/WTF/wtf/text/CStringView.h new file mode 100644 index 0000000000000..ac3b896a5e3a5 --- /dev/null +++ b/Source/WTF/wtf/text/CStringView.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2018 Yusuke Suzuki + * Copyright (C) 2024 Apple Inc. All Rights Reserved. + * Copyright (C) 2025 Comcast Inc. + * Copyright (C) 2025 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace WTF { + +class PrintStream; + +// This is a class designed to contain a null terminated UTF8 string, untouched. It contains char8_t to avoid mixing +// incompatible encodings at compile time. +class CStringView final { + WTF_FORBID_HEAP_ALLOCATION; +public: + static CStringView unsafeFromUTF8(const char* string) + { + if (!string) + return CStringView(); + return CStringView(unsafeMakeSpan(byteCast(string), std::char_traits::length(string) + 1)); + } + + static CStringView fromUTF8(std::span spanWithNullTerminator LIFETIME_BOUND) + { + if (spanWithNullTerminator.size() < 1) + return CStringView(); + RELEASE_ASSERT(spanWithNullTerminator[spanWithNullTerminator.size() - 1] == '\0'); + return CStringView(spanWithNullTerminator); + } + + WTF_EXPORT_PRIVATE void dump(PrintStream& out) const; + + CStringView() = default; + constexpr CStringView(std::nullptr_t) + : CStringView() + { } + CStringView(ASCIILiteral literal LIFETIME_BOUND) + { + if (!literal.length()) + return; + m_spanWithNullTerminator = byteCast(literal.spanIncludingNullTerminator()); + } + + bool isNull() const { return m_spanWithNullTerminator.empty(); } + + // This member function is designed to interface with external C functions handling UTF8 strings. Interactions with + // other strings should be handled by using the span. + const char* utf8() const LIFETIME_BOUND { return reinterpret_cast(m_spanWithNullTerminator.data()); } + size_t lengthInBytes() const { return m_spanWithNullTerminator.size() > 0 ? m_spanWithNullTerminator.size() - 1 : 0; } + std::span span() const LIFETIME_BOUND { return m_spanWithNullTerminator.first(lengthInBytes()); } + std::span spanIncludingNullTerminator() const LIFETIME_BOUND { return m_spanWithNullTerminator; } + bool isEmpty() const { return m_spanWithNullTerminator.size() <= 1; } + + explicit operator bool() const { return !isEmpty(); } + bool operator!() const { return isEmpty(); } + +private: + explicit CStringView(std::span spanWithNullTerminator LIFETIME_BOUND) + : m_spanWithNullTerminator(spanWithNullTerminator) + { + } + + std::span m_spanWithNullTerminator; +}; + +inline bool operator==(CStringView a, CStringView b) +{ + return equalSpans(a.span(), b.span()); +} + +inline bool operator==(CStringView a, ASCIILiteral b) +{ + return equalSpans(a.span(), byteCast(b.span())); +} + +inline bool operator==(ASCIILiteral a, CStringView b) +{ + return b == a; +} + +// CStringView is null terminated +inline const char* safePrintfType(const CStringView& string) { return string.utf8(); } + +} // namespace WTF + +using WTF::CStringView; diff --git a/Source/WTF/wtf/text/CodePointIterator.h b/Source/WTF/wtf/text/CodePointIterator.h index ad9254cf7f1ba..ac681f89ab71b 100644 --- a/Source/WTF/wtf/text/CodePointIterator.h +++ b/Source/WTF/wtf/text/CodePointIterator.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace WTF { @@ -76,14 +76,14 @@ class CodePointIterator { }; template<> -ALWAYS_INLINE char32_t CodePointIterator::operator*() const +ALWAYS_INLINE char32_t CodePointIterator::operator*() const { ASSERT(!atEnd()); return m_data.front(); } template<> -ALWAYS_INLINE auto CodePointIterator::operator++() -> CodePointIterator& +ALWAYS_INLINE auto CodePointIterator::operator++() -> CodePointIterator& { m_data = m_data.subspan(1); return *this; diff --git a/Source/WTF/wtf/text/ExternalStringImpl.cpp b/Source/WTF/wtf/text/ExternalStringImpl.cpp index 15aeaefb97d34..c5229b9be866a 100644 --- a/Source/WTF/wtf/text/ExternalStringImpl.cpp +++ b/Source/WTF/wtf/text/ExternalStringImpl.cpp @@ -28,7 +28,7 @@ namespace WTF { -WTF_EXPORT_PRIVATE Ref ExternalStringImpl::create(std::span characters, ExternalStringImplFreeFunction&& free) +WTF_EXPORT_PRIVATE Ref ExternalStringImpl::create(std::span characters, ExternalStringImplFreeFunction&& free) { return adoptRef(*new ExternalStringImpl(characters, WTFMove(free))); } @@ -38,7 +38,7 @@ WTF_EXPORT_PRIVATE Ref ExternalStringImpl::create(std::span< return adoptRef(*new ExternalStringImpl(characters, WTFMove(free))); } -ExternalStringImpl::ExternalStringImpl(std::span characters, ExternalStringImplFreeFunction&& free) +ExternalStringImpl::ExternalStringImpl(std::span characters, ExternalStringImplFreeFunction&& free) : StringImpl(characters, ConstructWithoutCopying) , m_free(WTFMove(free)) { diff --git a/Source/WTF/wtf/text/ExternalStringImpl.h b/Source/WTF/wtf/text/ExternalStringImpl.h index 990373d644824..7cd5100d8c828 100644 --- a/Source/WTF/wtf/text/ExternalStringImpl.h +++ b/Source/WTF/wtf/text/ExternalStringImpl.h @@ -36,14 +36,14 @@ using ExternalStringImplFreeFunction = Function create(std::span characters, ExternalStringImplFreeFunction&&); - WTF_EXPORT_PRIVATE static Ref create(std::span characters, ExternalStringImplFreeFunction&&); + WTF_EXPORT_PRIVATE static Ref create(std::span characters, ExternalStringImplFreeFunction&&); + WTF_EXPORT_PRIVATE static Ref create(std::span characters, ExternalStringImplFreeFunction&&); private: friend class StringImpl; - ExternalStringImpl(std::span characters, ExternalStringImplFreeFunction&&); - ExternalStringImpl(std::span characters, ExternalStringImplFreeFunction&&); + ExternalStringImpl(std::span characters, ExternalStringImplFreeFunction&&); + ExternalStringImpl(std::span characters, ExternalStringImplFreeFunction&&); inline void freeExternalBuffer(void* buffer, unsigned bufferSize); diff --git a/Source/WTF/wtf/text/IntegerToStringConversion.h b/Source/WTF/wtf/text/IntegerToStringConversion.h index 7da3f16e4ee0e..080acab327a96 100644 --- a/Source/WTF/wtf/text/IntegerToStringConversion.h +++ b/Source/WTF/wtf/text/IntegerToStringConversion.h @@ -26,7 +26,7 @@ #include #include #include -#include +#include namespace WTF { @@ -37,12 +37,12 @@ template struct IntegerToStringConversionTrait; template static typename IntegerToStringConversionTrait::ReturnType numberToStringImpl(UnsignedIntegerType number, AdditionalArgumentType additionalArgument) { - LChar buf[sizeof(UnsignedIntegerType) * 3 + 1]; - LChar* end = std::end(buf); - LChar* p = end; + Latin1Character buf[sizeof(UnsignedIntegerType) * 3 + 1]; + Latin1Character* end = std::end(buf); + Latin1Character* p = end; do { - *--p = static_cast((number % 10) + '0'); + *--p = static_cast((number % 10) + '0'); number /= 10; } while (number); @@ -70,12 +70,12 @@ template>, "'bool' not supported"); - LChar buf[sizeof(UnsignedIntegerType) * 3 + 1]; - LChar* end = std::end(buf); - LChar* p = end; + Latin1Character buf[sizeof(UnsignedIntegerType) * 3 + 1]; + Latin1Character* end = std::end(buf); + Latin1Character* p = end; do { - *--p = static_cast((number % 10) + '0'); + *--p = static_cast((number % 10) + '0'); number /= 10; } while (number); @@ -133,10 +133,10 @@ constexpr unsigned lengthOfIntegerAsString(IntegerType integer) } template -struct IntegerToStringConversionTrait> { - using ReturnType = Vector; +struct IntegerToStringConversionTrait> { + using ReturnType = Vector; using AdditionalArgumentType = void; - static ReturnType flush(std::span characters, void*) { return characters; } + static ReturnType flush(std::span characters, void*) { return characters; } }; } // namespace WTF diff --git a/Source/WTF/wtf/text/LChar.h b/Source/WTF/wtf/text/Latin1Character.h similarity index 97% rename from Source/WTF/wtf/text/LChar.h rename to Source/WTF/wtf/text/Latin1Character.h index 465406b8d49af..592f27bb1cc2b 100644 --- a/Source/WTF/wtf/text/LChar.h +++ b/Source/WTF/wtf/text/Latin1Character.h @@ -29,4 +29,4 @@ // A type to hold a single Latin-1 character. // This type complements the UChar type that we get from the ICU library. // To parallel that type, we put this one in the global namespace. -typedef unsigned char LChar; +typedef unsigned char Latin1Character; diff --git a/Source/WTF/wtf/text/MakeString.h b/Source/WTF/wtf/text/MakeString.h index 3fc47702690b7..13f5d035b0b89 100644 --- a/Source/WTF/wtf/text/MakeString.h +++ b/Source/WTF/wtf/text/MakeString.h @@ -44,7 +44,7 @@ RefPtr tryMakeStringImplFromAdaptersInternal(unsigned length, bool a { ASSERT(length <= String::MaxLength); if (areAllAdapters8Bit) { - LChar* buffer; + Latin1Character* buffer; RefPtr result = StringImpl::tryCreateUninitialized(length, buffer); if (!result) return nullptr; @@ -55,7 +55,7 @@ RefPtr tryMakeStringImplFromAdaptersInternal(unsigned length, bool a return result; } - UChar* buffer; + char16_t* buffer; RefPtr result = StringImpl::tryCreateUninitialized(length, buffer); if (!result) return nullptr; @@ -121,13 +121,13 @@ AtomString tryMakeAtomStringFromAdapters(StringTypeAdapters ...adapters) constexpr size_t maxLengthToUseStackVariable = 64; if (length < maxLengthToUseStackVariable) { if (areAllAdapters8Bit) { - LChar buffer[maxLengthToUseStackVariable]; + Latin1Character buffer[maxLengthToUseStackVariable]; stringTypeAdapterAccumulator(buffer, adapters...); - return std::span { buffer, length }; + return std::span { buffer, length }; } - UChar buffer[maxLengthToUseStackVariable]; + char16_t buffer[maxLengthToUseStackVariable]; stringTypeAdapterAccumulator(buffer, adapters...); - return std::span { buffer, length }; + return std::span { buffer, length }; } return tryMakeStringImplFromAdaptersInternal(length, areAllAdapters8Bit, adapters...).get(); } diff --git a/Source/WTF/wtf/text/ParsingUtilities.h b/Source/WTF/wtf/text/ParsingUtilities.h index 9b2ad140640c8..439526e56eb8f 100644 --- a/Source/WTF/wtf/text/ParsingUtilities.h +++ b/Source/WTF/wtf/text/ParsingUtilities.h @@ -94,7 +94,7 @@ template bool skipExactly(String return false; } -template bool skipExactly(StringParsingBuffer& buffer) +template bool skipExactly(StringParsingBuffer& buffer) { if (buffer.hasCharactersRemaining() && characterPredicate(*buffer)) { ++buffer; @@ -103,7 +103,7 @@ template bool skipExactly(StringParsingBuffer bool skipExactly(StringParsingBuffer& buffer) +template bool skipExactly(StringParsingBuffer& buffer) { if (buffer.hasCharactersRemaining() && characterPredicate(*buffer)) { ++buffer; @@ -112,7 +112,7 @@ template bool skipExactly(StringParsingBuffer bool skipExactly(std::span& buffer) +template bool skipExactly(std::span& buffer) requires(std::is_same_v, Latin1Character>) { if (!buffer.empty() && characterPredicate(buffer[0])) { skip(buffer, 1); @@ -121,7 +121,25 @@ template bool skipExactly(std::span return false; } -template bool skipExactly(std::span& buffer) +template bool skipExactly(std::span& buffer) +{ + if (!buffer.empty() && characterPredicate(buffer[0])) { + skip(buffer, 1); + return true; + } + return false; +} + +template bool skipExactly(std::span& buffer) requires(std::is_same_v, char8_t>) +{ + if (!buffer.empty() && characterPredicate(buffer[0])) { + skip(buffer, 1); + return true; + } + return false; +} + +template bool skipExactly(std::span& buffer) requires(std::is_same_v, char>) { if (!buffer.empty() && characterPredicate(buffer[0])) { skip(buffer, 1); @@ -144,7 +162,15 @@ template void skipUntil(std::spa skip(buffer, index); } -template void skipUntil(std::span& data) +template void skipUntil(std::span& data) requires(std::is_same_v, Latin1Character>) +{ + size_t index = 0; + while (index < data.size() && !characterPredicate(data[index])) + ++index; + skip(data, index); +} + +template void skipUntil(std::span& data) { size_t index = 0; while (index < data.size() && !characterPredicate(data[index])) @@ -152,7 +178,7 @@ template void skipUntil(std::span& skip(data, index); } -template void skipUntil(std::span& data) +template void skipUntil(std::span& data) requires(std::is_same_v, char8_t>) { size_t index = 0; while (index < data.size() && !characterPredicate(data[index])) @@ -160,13 +186,21 @@ template void skipUntil(std::span& skip(data, index); } -template void skipUntil(StringParsingBuffer& buffer) +template void skipUntil(std::span& data) requires(std::is_same_v, char>) +{ + size_t index = 0; + while (index < data.size() && !characterPredicate(data[index])) + ++index; + skip(data, index); +} + +template void skipUntil(StringParsingBuffer& buffer) { while (buffer.hasCharactersRemaining() && !characterPredicate(*buffer)) ++buffer; } -template void skipUntil(StringParsingBuffer& buffer) +template void skipUntil(StringParsingBuffer& buffer) { while (buffer.hasCharactersRemaining() && !characterPredicate(*buffer)) ++buffer; @@ -186,7 +220,23 @@ template void skipWhile(std::spa skip(buffer, index); } -template void skipWhile(std::span& data) +template void skipWhile(std::span& data) requires(std::is_same_v, Latin1Character>) +{ + size_t index = 0; + while (index < data.size() && characterPredicate(data[index])) + ++index; + skip(data, index); +} + +template void skipWhile(std::span& data) +{ + size_t index = 0; + while (index < data.size() && characterPredicate(data[index])) + ++index; + skip(data, index); +} + +template void skipWhile(std::span& data) requires(std::is_same_v, char8_t>) { size_t index = 0; while (index < data.size() && characterPredicate(data[index])) @@ -194,7 +244,7 @@ template void skipWhile(std::span& skip(data, index); } -template void skipWhile(std::span& data) +template void skipWhile(std::span& data) requires(std::is_same_v, char>) { size_t index = 0; while (index < data.size() && characterPredicate(data[index])) @@ -202,13 +252,13 @@ template void skipWhile(std::span& skip(data, index); } -template void skipWhile(StringParsingBuffer& buffer) +template void skipWhile(StringParsingBuffer& buffer) { while (buffer.hasCharactersRemaining() && characterPredicate(*buffer)) ++buffer; } -template void skipWhile(StringParsingBuffer& buffer) +template void skipWhile(StringParsingBuffer& buffer) { while (buffer.hasCharactersRemaining() && characterPredicate(*buffer)) ++buffer; @@ -285,11 +335,11 @@ match_constness_t& consumeAndCastTo(std::span>(consumeSpan(data, sizeof(DestinationType)))[0]; } -// Adapt a UChar-predicate to an LChar-predicate. -template -static inline bool LCharPredicateAdapter(LChar c) { return characterPredicate(c); } +// Adapt a char16_t-predicate to an Latin1Character-predicate. +template +static inline bool Latin1CharacterPredicateAdapter(Latin1Character c) { return characterPredicate(c); } -template bool skipExactly(const LChar*& position, const LChar* end) +template bool skipExactly(const Latin1Character*& position, const Latin1Character* end) { if (position < end && characterPredicate(*position)) { ++position; @@ -298,7 +348,7 @@ template bool skipExactly(const LChar*& position return false; } -template bool skipExactly(const UChar*& position, const UChar* end) +template bool skipExactly(const char16_t*& position, const char16_t* end) { if (position < end && characterPredicate(*position)) { ++position; @@ -313,37 +363,37 @@ template void skipUntil(const Ch ++position; } -template void skipUntil(const LChar*& position, const LChar* end) +template void skipUntil(const Latin1Character*& position, const Latin1Character* end) { while (position < end && !characterPredicate(*position)) ++position; } -template void skipUntil(const UChar*& position, const UChar* end) +template void skipUntil(const char16_t*& position, const char16_t* end) { while (position < end && !characterPredicate(*position)) ++position; } -template void skipWhile(const LChar*& position, const LChar* end) +template void skipWhile(const Latin1Character*& position, const Latin1Character* end) { while (position < end && characterPredicate(*position)) ++position; } -template void skipWhile(const UChar*& position, const UChar* end) +template void skipWhile(const char16_t*& position, const char16_t* end) { while (position < end && characterPredicate(*position)) ++position; } -template void reverseSkipWhile(const LChar*& position, const LChar* start) +template void reverseSkipWhile(const Latin1Character*& position, const Latin1Character* start) { while (position >= start && characterPredicate(*position)) --position; } -template void reverseSkipWhile(const UChar*& position, const UChar* start) +template void reverseSkipWhile(const char16_t*& position, const char16_t* start) { while (position >= start && characterPredicate(*position)) --position; @@ -396,7 +446,7 @@ template constexpr bool skipCha } // namespace WTF -using WTF::LCharPredicateAdapter; +using WTF::Latin1CharacterPredicateAdapter; using WTF::clampedMoveCursorWithinSpan; using WTF::consume; using WTF::consumeAndCastTo; @@ -414,7 +464,7 @@ using WTF::skipWhile; using WTF::reverseSkipWhile; namespace WebCore { - using WTF::LCharPredicateAdapter; + using WTF::Latin1CharacterPredicateAdapter; using WTF::clampedMoveCursorWithinSpan; using WTF::consume; using WTF::consumeAndCastTo; diff --git a/Source/WTF/wtf/text/StringBuilder.cpp b/Source/WTF/wtf/text/StringBuilder.cpp index e8548813e0804..536d63f9fbc89 100644 --- a/Source/WTF/wtf/text/StringBuilder.cpp +++ b/Source/WTF/wtf/text/StringBuilder.cpp @@ -93,9 +93,9 @@ void StringBuilder::shrink(unsigned newLength) } // Allocate a fresh buffer, with a copy of the characters we are keeping. if (m_buffer->is8Bit()) - allocateBuffer(m_buffer->span8().data(), newLength); + allocateBuffer(m_buffer->span8().data(), newLength); else - allocateBuffer(m_buffer->span16().data(), newLength); + allocateBuffer(m_buffer->span16().data(), newLength); return; } @@ -106,9 +106,9 @@ void StringBuilder::shrink(unsigned newLength) void StringBuilder::reallocateBuffer(unsigned requiredCapacity) { if (is8Bit()) - reallocateBuffer(requiredCapacity); + reallocateBuffer(requiredCapacity); else - reallocateBuffer(requiredCapacity); + reallocateBuffer(requiredCapacity); } void StringBuilder::reserveCapacity(unsigned newCapacity) @@ -122,39 +122,39 @@ void StringBuilder::reserveCapacity(unsigned newCapacity) } else { if (newCapacity > m_length) { if (!m_length) - allocateBuffer(static_cast(nullptr), newCapacity); + allocateBuffer(static_cast(nullptr), newCapacity); else if (m_string.is8Bit()) - allocateBuffer(m_string.span8().data(), newCapacity); + allocateBuffer(m_string.span8().data(), newCapacity); else - allocateBuffer(m_string.span16().data(), newCapacity); + allocateBuffer(m_string.span16().data(), newCapacity); } } ASSERT(hasOverflowed() || !newCapacity || m_buffer->length() >= newCapacity); } // Alterative extendBufferForAppending that can be called from the header without inlining. -LChar* StringBuilder::extendBufferForAppendingLChar(unsigned requiredLength) +Latin1Character* StringBuilder::extendBufferForAppendingLatin1Character(unsigned requiredLength) { - return extendBufferForAppending(requiredLength); + return extendBufferForAppending(requiredLength); } -UChar* StringBuilder::extendBufferForAppendingWithUpconvert(unsigned requiredLength) +char16_t* StringBuilder::extendBufferForAppendingWithUpconvert(unsigned requiredLength) { if (is8Bit()) { - allocateBuffer(characters(), expandedCapacity(capacity(), requiredLength)); + allocateBuffer(characters(), expandedCapacity(capacity(), requiredLength)); if (UNLIKELY(hasOverflowed())) return nullptr; - return const_cast(m_buffer->span16().data()) + std::exchange(m_length, requiredLength); + return const_cast(m_buffer->span16().data()) + std::exchange(m_length, requiredLength); } - return extendBufferForAppending(requiredLength); + return extendBufferForAppending(requiredLength); } -void StringBuilder::append(std::span characters) +void StringBuilder::append(std::span characters) { if (characters.empty() || hasOverflowed()) return; if (characters.size() == 1 && isLatin1(characters[0]) && is8Bit()) { - append(static_cast(characters[0])); + append(static_cast(characters[0])); return; } RELEASE_ASSERT(characters.size() < std::numeric_limits::max()); @@ -162,16 +162,16 @@ void StringBuilder::append(std::span characters) StringImpl::copyCharacters(destination, characters); } -void StringBuilder::append(std::span characters) +void StringBuilder::append(std::span characters) { if (characters.empty() || hasOverflowed()) return; RELEASE_ASSERT(characters.size() < std::numeric_limits::max()); if (is8Bit()) { - if (auto destination = extendBufferForAppending(saturatedSum(m_length, static_cast(characters.size())))) + if (auto destination = extendBufferForAppending(saturatedSum(m_length, static_cast(characters.size())))) StringImpl::copyCharacters(destination, characters); } else { - if (auto destination = extendBufferForAppending(saturatedSum(m_length, static_cast(characters.size())))) + if (auto destination = extendBufferForAppending(saturatedSum(m_length, static_cast(characters.size())))) StringImpl::copyCharacters(destination, characters); } } diff --git a/Source/WTF/wtf/text/StringBuilder.h b/Source/WTF/wtf/text/StringBuilder.h index 2aeb3319d9e31..029ef556af06a 100644 --- a/Source/WTF/wtf/text/StringBuilder.h +++ b/Source/WTF/wtf/text/StringBuilder.h @@ -56,16 +56,16 @@ class StringBuilder { template void append(const StringTypes&...); // FIXME: We should keep these overloads only if optimizations make them more efficient than the single-argument form of the variadic append above. - WTF_EXPORT_PRIVATE void append(std::span); - WTF_EXPORT_PRIVATE void append(std::span); + WTF_EXPORT_PRIVATE void append(std::span); + WTF_EXPORT_PRIVATE void append(std::span); void append(const AtomString& string) { append(string.string()); } void append(const String&); void append(StringView); void append(ASCIILiteral); void append(const char*) = delete; // Pass ASCIILiteral or span instead. - void append(UChar); - void append(LChar); - void append(char character) { append(byteCast(character)); } + void append(char16_t); + void append(Latin1Character); + void append(char character) { append(byteCast(character)); } template void appendFromAdapters(const StringTypeAdapters&...); @@ -84,13 +84,13 @@ class StringBuilder { unsigned length() const; operator StringView() const; - UChar operator[](unsigned i) const; + char16_t operator[](unsigned i) const; bool is8Bit() const; - std::span span8() const { return { characters(), length() }; } - std::span span16() const { return { characters(), length() }; } - template std::span span() const { return std::span(characters(), length()); } - + std::span span8() const LIFETIME_BOUND { return span(); } + std::span span16() const LIFETIME_BOUND { return span(); } + template std::span span() const LIFETIME_BOUND { return std::span(characters(), length()); } + unsigned capacity() const; WTF_EXPORT_PRIVATE void reserveCapacity(unsigned newCapacity); @@ -110,8 +110,8 @@ class StringBuilder { template CharacterType* extendBufferForAppending(unsigned requiredLength); template CharacterType* extendBufferForAppendingSlowCase(unsigned requiredLength); - WTF_EXPORT_PRIVATE LChar* extendBufferForAppendingLChar(unsigned requiredLength); - WTF_EXPORT_PRIVATE UChar* extendBufferForAppendingWithUpconvert(unsigned requiredLength); + WTF_EXPORT_PRIVATE Latin1Character* extendBufferForAppendingLatin1Character(unsigned requiredLength); + WTF_EXPORT_PRIVATE char16_t* extendBufferForAppendingWithUpconvert(unsigned requiredLength); WTF_EXPORT_PRIVATE void reifyString() const; @@ -156,11 +156,11 @@ inline void StringBuilder::swap(StringBuilder& other) inline StringBuilder::operator StringView() const { if (is8Bit()) - return span(); - return span(); + return span(); + return span(); } -inline void StringBuilder::append(UChar character) +inline void StringBuilder::append(char16_t character) { if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) { if (!m_buffer->is8Bit()) { @@ -168,14 +168,14 @@ inline void StringBuilder::append(UChar character) return; } if (isLatin1(character)) { - spanConstCast(m_buffer->span8())[m_length++] = static_cast(character); + spanConstCast(m_buffer->span8())[m_length++] = static_cast(character); return; } } append(WTF::span(character)); } -inline void StringBuilder::append(LChar character) +inline void StringBuilder::append(Latin1Character character) { if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) { if (m_buffer->is8Bit()) @@ -276,10 +276,9 @@ inline unsigned StringBuilder::capacity() const return m_buffer ? m_buffer->length() : length(); } -inline UChar StringBuilder::operator[](unsigned i) const +inline char16_t StringBuilder::operator[](unsigned i) const { - RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(i < length()); - return is8Bit() ? characters()[i] : characters()[i]; + return is8Bit() ? char16_t { span8()[i] } : span16()[i]; } inline bool StringBuilder::is8Bit() const @@ -308,7 +307,7 @@ template void StringBuilder::appendFromAdapters( } else { auto requiredLength = saturatedSum(m_length, adapters.length()...); if (is8Bit() && are8Bit(adapters...)) { - auto destination = extendBufferForAppendingLChar(requiredLength); + auto destination = extendBufferForAppendingLatin1Character(requiredLength); if (!destination) return; stringTypeAdapterAccumulator(destination, adapters...); @@ -349,7 +348,7 @@ template bool equal(const StringBuilder& builder, const template<> struct IntegerToStringConversionTrait { using ReturnType = void; using AdditionalArgumentType = StringBuilder; - static void flush(std::span characters, StringBuilder* builder) { builder->append(characters); } + static void flush(std::span characters, StringBuilder* builder) { builder->append(characters); } }; // Helper functor useful in generic contexts where both makeString() and StringBuilder are being used. diff --git a/Source/WTF/wtf/text/StringBuilderJSON.cpp b/Source/WTF/wtf/text/StringBuilderJSON.cpp index a1f37a447c8bf..3abf8a794c01e 100644 --- a/Source/WTF/wtf/text/StringBuilderJSON.cpp +++ b/Source/WTF/wtf/text/StringBuilderJSON.cpp @@ -36,7 +36,7 @@ void StringBuilder::appendQuotedJSONString(const String& string) auto stringLengthValue = stringLength.value(); if (is8Bit() && string.is8Bit()) { - if (auto* output = extendBufferForAppending(saturatedSum(m_length, stringLengthValue))) { + if (auto* output = extendBufferForAppending(saturatedSum(m_length, stringLengthValue))) { auto* end = output + stringLengthValue; *output++ = '"'; appendEscapedJSONStringContent(output, string.span8()); diff --git a/Source/WTF/wtf/text/StringCommon.cpp b/Source/WTF/wtf/text/StringCommon.cpp index 4a7309e260c65..6206606192f95 100644 --- a/Source/WTF/wtf/text/StringCommon.cpp +++ b/Source/WTF/wtf/text/StringCommon.cpp @@ -90,7 +90,7 @@ const double* findDoubleAlignedImpl(const double* pointer, double target, size_t } SUPPRESS_ASAN -const LChar* find8NonASCIIAlignedImpl(std::span data) +const Latin1Character* find8NonASCIIAlignedImpl(std::span data) { constexpr simde_uint8x16_t indexMask { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; @@ -110,7 +110,7 @@ const LChar* find8NonASCIIAlignedImpl(std::span data) if (simde_vmaxvq_u8(mask)) { simde_uint8x16_t ranked = simde_vornq_u8(indexMask, mask); uint8_t index = simde_vminvq_u8(ranked); - return std::bit_cast((index < length) ? cursor + index : nullptr); + return std::bit_cast((index < length) ? cursor + index : nullptr); } if (length <= stride) return nullptr; diff --git a/Source/WTF/wtf/text/StringCommon.h b/Source/WTF/wtf/text/StringCommon.h index daec2d3478de4..cf8fb6b9c002c 100644 --- a/Source/WTF/wtf/text/StringCommon.h +++ b/Source/WTF/wtf/text/StringCommon.h @@ -36,29 +36,46 @@ #include #include #include +#include namespace WTF { -inline std::span span(const LChar& character) +inline std::span span(const Latin1Character& character) { return { &character, 1 }; } -inline std::span span(const UChar& character) +inline std::span span(const char16_t& character) { return { &character, 1 }; } -inline std::span span8(const char* string) +inline std::span unsafeSpan(const char* string) { - return { byteCast(string), string ? strlen(string) : 0 }; +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN + return unsafeMakeSpan(string, string ? strlen(string) : 0); +WTF_ALLOW_UNSAFE_BUFFER_USAGE_END } -inline std::span span(const char* string) +inline std::span unsafeSpanIncludingNullTerminator(const char* string) { - return { string, string ? strlen(string) : 0 }; +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN + return unsafeMakeSpan(string, string ? strlen(string) + 1 : 0); +WTF_ALLOW_UNSAFE_BUFFER_USAGE_END } +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN +inline std::span unsafeSpan(const char16_t* string) +{ + if (!string) + return { }; + size_t length = 0; + while (string[length]) + ++length; + return unsafeMakeSpan(string, length); +} +WTF_ALLOW_UNSAFE_BUFFER_USAGE_END + #if !HAVE(MISSING_U8STRING) inline std::span span(const std::u8string& string) { @@ -72,27 +89,33 @@ template inline constexpr bool isLatin1(CharacterType ch return static_cast(character) <= static_cast(0xFF); } -template<> ALWAYS_INLINE constexpr bool isLatin1(LChar) +template<> ALWAYS_INLINE constexpr bool isLatin1(Latin1Character) { return true; } using CodeUnitMatchFunction = bool (*)(UChar); -template bool equalIgnoringASCIICase(std::span, std::span); +template + requires(TriviallyComparableCodeUnits) +bool equalIgnoringASCIICase(std::span, std::span); template bool equalIgnoringASCIICaseCommon(const StringClassA&, const StringClassB&); -template bool equalLettersIgnoringASCIICase(std::span, std::span lowercaseLetters); +template bool equalLettersIgnoringASCIICase(std::span, std::span lowercaseLetters); template bool equalLettersIgnoringASCIICase(std::span, ASCIILiteral); template bool equalLettersIgnoringASCIICaseCommon(const StringClass&, ASCIILiteral); bool equalIgnoringASCIICase(const char*, const char*); +template +concept OneByteCharacterType = std::is_same_v, Latin1Character> || std::is_same_v, char8_t> || std::is_same_v, char>; + // Do comparisons 8 or 4 bytes-at-a-time on architectures where it's safe. #if (CPU(X86_64) || CPU(ARM64)) && !ASAN_ENABLED -ALWAYS_INLINE bool equal(const LChar* aLChar, std::span bLChar) +template +ALWAYS_INLINE bool equal(const CharacterType* a, std::span b) { ASSERT(bLChar.size() <= std::numeric_limits::max()); unsigned length = bLChar.size(); @@ -193,7 +216,8 @@ ALWAYS_INLINE bool equal(const UChar* aUChar, std::span bUChar) } } #elif CPU(X86) && !ASAN_ENABLED -ALWAYS_INLINE bool equal(const LChar* aLChar, std::span bLChar) +template +ALWAYS_INLINE bool equal(const CharacterType* a, std::span b) { ASSERT(bLChar.size() <= std::numeric_limits::max()); unsigned length = bLChar.size(); @@ -212,8 +236,8 @@ ALWAYS_INLINE bool equal(const LChar* aLChar, std::span bLChar) length &= 3; if (length) { - const LChar* aRemainder = byteCast(a); - const LChar* bRemainder = byteCast(b); + auto* aRemainder = byteCast(aString); + auto* bRemainder = byteCast(bString); for (unsigned i = 0; i < length; ++i) { if (aRemainder[i] != bRemainder[i]) @@ -245,125 +269,16 @@ ALWAYS_INLINE bool equal(const UChar* aUChar, std::span bUChar) return true; } -#elif OS(DARWIN) && WTF_ARM_ARCH_AT_LEAST(7) && !ASAN_ENABLED -ALWAYS_INLINE bool equal(const LChar* a, std::span bSpan) -{ - ASSERT(b.size() <= std::numeric_limits::max()); - auto* b = bSpan.data(); - unsigned length = bSpan.size(); - - bool isEqual = false; - uint32_t aValue; - uint32_t bValue; - asm("subs %[length], #4\n" - "blo 2f\n" - - "0:\n" // Label 0 = Start of loop over 32 bits. - "ldr %[aValue], [%[a]], #4\n" - "ldr %[bValue], [%[b]], #4\n" - "cmp %[aValue], %[bValue]\n" - "bne 66f\n" - "subs %[length], #4\n" - "bhs 0b\n" - - // At this point, length can be: - // -0: 00000000000000000000000000000000 (0 bytes left) - // -1: 11111111111111111111111111111111 (3 bytes left) - // -2: 11111111111111111111111111111110 (2 bytes left) - // -3: 11111111111111111111111111111101 (1 byte left) - // -4: 11111111111111111111111111111100 (length was 0) - // The pointers are at the correct position. - "2:\n" // Label 2 = End of loop over 32 bits, check for pair of characters. - "tst %[length], #2\n" - "beq 1f\n" - "ldrh %[aValue], [%[a]], #2\n" - "ldrh %[bValue], [%[b]], #2\n" - "cmp %[aValue], %[bValue]\n" - "bne 66f\n" - - "1:\n" // Label 1 = Check for a single character left. - "tst %[length], #1\n" - "beq 42f\n" - "ldrb %[aValue], [%[a]]\n" - "ldrb %[bValue], [%[b]]\n" - "cmp %[aValue], %[bValue]\n" - "bne 66f\n" - - "42:\n" // Label 42 = Success. - "mov %[isEqual], #1\n" - "66:\n" // Label 66 = End without changing isEqual to 1. - : [length]"+r"(length), [isEqual]"+r"(isEqual), [a]"+r"(a), [b]"+r"(b), [aValue]"+r"(aValue), [bValue]"+r"(bValue) - : - : - ); - return isEqual; -} - -ALWAYS_INLINE bool equal(const UChar* a, std::span bSpan) -{ - ASSERT(b.size() <= std::numeric_limits::max()); - auto* b = bSpan.data(); - unsigned length = bSpan.size(); - - bool isEqual = false; - uint32_t aValue; - uint32_t bValue; - asm("subs %[length], #2\n" - "blo 1f\n" - - "0:\n" // Label 0 = Start of loop over 32 bits. - "ldr %[aValue], [%[a]], #4\n" - "ldr %[bValue], [%[b]], #4\n" - "cmp %[aValue], %[bValue]\n" - "bne 66f\n" - "subs %[length], #2\n" - "bhs 0b\n" - - // At this point, length can be: - // -0: 00000000000000000000000000000000 (0 bytes left) - // -1: 11111111111111111111111111111111 (1 character left, 2 bytes) - // -2: 11111111111111111111111111111110 (length was zero) - // The pointers are at the correct position. - "1:\n" // Label 1 = Check for a single character left. - "tst %[length], #1\n" - "beq 42f\n" - "ldrh %[aValue], [%[a]]\n" - "ldrh %[bValue], [%[b]]\n" - "cmp %[aValue], %[bValue]\n" - "bne 66f\n" - - "42:\n" // Label 42 = Success. - "mov %[isEqual], #1\n" - "66:\n" // Label 66 = End without changing isEqual to 1. - : [length]"+r"(length), [isEqual]"+r"(isEqual), [a]"+r"(a), [b]"+r"(b), [aValue]"+r"(aValue), [bValue]"+r"(bValue) - : - : - ); - return isEqual; -} -#elif !ASAN_ENABLED -ALWAYS_INLINE bool equal(const LChar* a, std::span b) { return !memcmp(a, b.data(), b.size()); } -ALWAYS_INLINE bool equal(const UChar* a, std::span b) { return !memcmp(a, b.data(), b.size_bytes()); } #else -ALWAYS_INLINE bool equal(const LChar* a, std::span b) +template +ALWAYS_INLINE bool equal(const CharacterType* a, std::span b) { - for (size_t i = 0; i < b.size(); ++i) { - if (a[i] != b[i]) - return false; - } - return true; -} -ALWAYS_INLINE bool equal(const UChar* a, std::span b) -{ - for (size_t i = 0; i < b.size(); ++i) { - if (a[i] != b[i]) - return false; - } - return true; + return !memcmp(a, b.data(), b.size()); } +ALWAYS_INLINE bool equal(const char16_t* a, std::span b) { return !memcmp(a, b.data(), b.size_bytes()); } #endif -ALWAYS_INLINE bool equal(const LChar* a, std::span b) +ALWAYS_INLINE bool equal(const Latin1Character* a, std::span b) { #if CPU(ARM64) ASSERT(b.size() <= std::numeric_limits::max()); @@ -383,7 +298,7 @@ ALWAYS_INLINE bool equal(const LChar* a, std::span b) return true; } if (length >= 4) { - auto read4 = [](const LChar* p) ALWAYS_INLINE_LAMBDA { + auto read4 = [](const Latin1Character* p) ALWAYS_INLINE_LAMBDA { // Copy 32 bits and expand to 64 bits. uint32_t v32 = unalignedLoad(p); uint64_t v64 = static_cast(v32); @@ -394,7 +309,7 @@ ALWAYS_INLINE bool equal(const LChar* a, std::span b) return static_cast(read4(a) == unalignedLoad(b.data())) & static_cast(read4(a + (length % 4)) == unalignedLoad(b.data() + (length % 4))); } if (length >= 2) { - auto read2 = [](const LChar* p) ALWAYS_INLINE_LAMBDA { + auto read2 = [](const Latin1Character* p) ALWAYS_INLINE_LAMBDA { // Copy 16 bits and expand to 32 bits. uint16_t v16 = unalignedLoad(p); uint32_t v32 = static_cast(v16); @@ -414,11 +329,25 @@ ALWAYS_INLINE bool equal(const LChar* a, std::span b) #endif } -ALWAYS_INLINE bool equal(const UChar* a, std::span b) +ALWAYS_INLINE bool equal(const char16_t* a, std::span b) { return equal(b.data(), { a, b.size() }); } +template +ALWAYS_INLINE bool equal(std::span a, std::span b) +{ + if (a.size() != b.size()) + return false; + return equal(a.data(), b); +} + +template +ALWAYS_INLINE bool equal(std::span a, ASCIILiteral b) +{ + return equal(a, byteCast(b.span())); +} + template ALWAYS_INLINE bool equalCommon(const StringClassA& a, const StringClassB& b, unsigned length) { @@ -475,6 +404,23 @@ template bool equal(const StringClass& a, return equal(a.span16().data(), { codeUnits, length }); } +template +concept ContainsEncodingAwareSpans = requires(T t) +{ + { t.is8Bit() } -> std::convertible_to; + { t.span8() } -> std::convertible_to>; + { t.span16() } -> std::convertible_to>; +}; + +template +bool equal(const StringClass& string, std::span span) +{ + if (string.is8Bit()) + return Unicode::equal(string.span8(), span); + + return Unicode::equal(string.span16(), span); +} + template inline bool equalIgnoringASCIICaseWithLength(std::span a, std::span b, size_t lengthToCheck) { ASSERT(a.size() >= lengthToCheck); @@ -486,11 +432,26 @@ template inline bool equalIgno return true; } -template inline bool equalIgnoringASCIICase(std::span a, std::span b) +template inline bool spanHasPrefixIgnoringASCIICase(std::span span, std::span prefix) +{ + if (span.size() < prefix.size()) + return false; + return equalIgnoringASCIICaseWithLength(span, prefix, prefix.size()); +} + +template + requires(TriviallyComparableCodeUnits) +inline bool equalIgnoringASCIICase(std::span a, std::span b) { return a.size() == b.size() && equalIgnoringASCIICaseWithLength(a, b, a.size()); } +template +inline bool equalIgnoringASCIICase(std::span a, ASCIILiteral b) +{ + return equalIgnoringASCIICase(a, byteCast(b.span())); +} + template bool equalIgnoringASCIICaseCommon(const StringClassA& a, const StringClassB& b) { @@ -509,7 +470,7 @@ bool equalIgnoringASCIICaseCommon(const StringClassA& a, const StringClassB& b) template bool equalIgnoringASCIICaseCommon(const StringClassA& a, const char* b) { - auto bSpan = span8(b); + auto bSpan = unsafeSpan(b); if (a.length() != bSpan.size()) return false; if (a.is8Bit()) @@ -517,27 +478,39 @@ template bool equalIgnoringASCIICaseCommon(const StringCl return equalIgnoringASCIICaseWithLength(a.span16(), bSpan, bSpan.size()); } -template -size_t findIgnoringASCIICase(std::span source, std::span matchCharacters, size_t startOffset) +template + requires(TriviallyComparableCodeUnits) +size_t findIgnoringASCIICase(std::span source, std::span matchCharacters, size_t startOffset = 0) { - ASSERT(source.size() >= matchCharacters.size()); + for (size_t offset = startOffset; offset <= source.size() && source.size() - offset >= matchCharacters.size(); ++offset) { + if (equalIgnoringASCIICaseWithLength(source.subspan(offset), matchCharacters, matchCharacters.size())) + return offset; + } + return notFound; +} - auto startSearchedCharacters = source.subspan(startOffset); +template +size_t findIgnoringASCIICase(std::span source, ASCIILiteral matchCharacters) +{ + return findIgnoringASCIICase(source, byteCast(matchCharacters.span())); +} - // delta is the number of additional times to test; delta == 0 means test only once. - size_t delta = startSearchedCharacters.size() - matchCharacters.size(); +template +bool containsIgnoringASCIICase(std::span source, std::span matchCharacters) +{ + return findIgnoringASCIICase(source, matchCharacters) != notFound; +} - for (size_t i = 0; i <= delta; ++i) { - if (equalIgnoringASCIICaseWithLength(startSearchedCharacters.subspan(i), matchCharacters, matchCharacters.size())) - return startOffset + i; - } - return notFound; +template +bool containsIgnoringASCIICase(std::span source, ASCIILiteral matchCharacters) +{ + return containsIgnoringASCIICase(source, byteCast(matchCharacters.span())); } inline size_t findIgnoringASCIICaseWithoutLength(const char* source, const char* matchCharacters) { - auto searchSpan = span(source); - auto matchSpan = span(matchCharacters); + auto searchSpan = unsafeSpan(source); + auto matchSpan = unsafeSpan(matchCharacters); return matchSpan.size() <= searchSpan.size() ? findIgnoringASCIICase(searchSpan, matchSpan, 0) : notFound; } @@ -700,20 +673,20 @@ ALWAYS_INLINE const double* findDouble(const double* pointer, double target, siz } #endif -WTF_EXPORT_PRIVATE const LChar* find8NonASCIIAlignedImpl(std::span); -WTF_EXPORT_PRIVATE const UChar* find16NonASCIIAlignedImpl(std::span); +WTF_EXPORT_PRIVATE const Latin1Character* find8NonASCIIAlignedImpl(std::span); +WTF_EXPORT_PRIVATE const char16_t* find16NonASCIIAlignedImpl(std::span); #if CPU(ARM64) -ALWAYS_INLINE const LChar* find8NonASCII(std::span data) +ALWAYS_INLINE const Latin1Character* find8NonASCII(std::span data) { constexpr size_t thresholdLength = 16; - static_assert(!(thresholdLength % (16 / sizeof(LChar))), "length threshold should be 16-byte aligned to make find8NonASCIIAlignedImpl simpler"); + static_assert(!(thresholdLength % (16 / sizeof(Latin1Character))), "length threshold should be 16-byte aligned to make find8NonASCIIAlignedImpl simpler"); auto* pointer = data.data(); auto length = data.size(); uintptr_t unaligned = reinterpret_cast(pointer) & 0xf; size_t index = 0; - size_t runway = std::min(thresholdLength - (unaligned / sizeof(LChar)), length); + size_t runway = std::min(thresholdLength - (unaligned / sizeof(Latin1Character)), length); for (; index < runway; ++index) { if (!isASCII(pointer[index])) return pointer + index; @@ -778,21 +751,42 @@ inline size_t find(std::span characters, CharacterType matc return notFound; } -ALWAYS_INLINE size_t find(std::span characters, LChar matchCharacter, size_t index = 0) +ALWAYS_INLINE size_t find(std::span characters, Latin1Character matchCharacter, size_t index = 0) { return find(characters, static_cast(matchCharacter), index); } -inline size_t find(std::span characters, UChar matchCharacter, size_t index = 0) +inline size_t find(std::span characters, char16_t matchCharacter, size_t index = 0) { if (!isLatin1(matchCharacter)) return notFound; - return find(characters, static_cast(matchCharacter), index); + return find(characters, static_cast(matchCharacter), index); +} + +template +inline size_t find(std::span characters, ASCIILiteral matchCharacters) +{ + return find(characters, byteCast(matchCharacters.span())); +} + +template +inline bool contains(std::span characters, CharacterType2 matchCharacter, size_t index = 0) +{ + return find(characters, matchCharacter, index) != notFound; +} + +template +inline bool contains(std::span characters, ASCIILiteral matchCharacters) +{ + return contains(characters, byteCast(matchCharacters.span())); } template ALWAYS_INLINE static size_t reverseFindInner(std::span searchCharacters, std::span matchCharacters, size_t start) { + if (searchCharacters.size() < matchCharacters.size()) + return notFound; + // Optimization: keep a running hash of the strings, // only call equal if the hashes match. @@ -817,7 +811,28 @@ ALWAYS_INLINE static size_t reverseFindInner(std::span inline bool equalLettersIgnoringASCIICaseWithLength(std::span characters, std::span lowercaseLetters, size_t length) +template + requires(TriviallyComparableCodeUnits) +ALWAYS_INLINE static size_t reverseFind(std::span searchCharacters, std::span matchCharacters) +{ + return reverseFindInner(searchCharacters, matchCharacters, std::numeric_limits::max()); +} + +template +ALWAYS_INLINE static size_t reverseFind(std::span searchCharacters, ASCIILiteral matchCharacters) +{ + return reverseFind(searchCharacters, byteCast(matchCharacters.span())); +} + +template +concept SearchableStringByOneByteCharacter = + sizeof(OneByteCharT) == 1 + && (std::is_same_v, std::remove_const_t> + || std::is_same_v, Latin1Character>); + +template + requires SearchableStringByOneByteCharacter +inline bool equalLettersIgnoringASCIICaseWithLength(std::span characters, std::span lowercaseLetters, size_t length) { ASSERT(characters.size() >= length); ASSERT(lowercaseLetters.size() >= length); @@ -828,14 +843,14 @@ template inline bool equalLettersIgnoringASCIICaseWithLe return true; } -template inline bool equalLettersIgnoringASCIICase(std::span characters, std::span lowercaseLetters) +template inline bool equalLettersIgnoringASCIICase(std::span characters, std::span lowercaseLetters) { return characters.size() == lowercaseLetters.size() && equalLettersIgnoringASCIICaseWithLength(characters, lowercaseLetters, lowercaseLetters.size()); } template inline bool equalLettersIgnoringASCIICase(std::span characters, std::span lowercaseLetters) { - return equalLettersIgnoringASCIICase(characters, byteCast(lowercaseLetters)); + return equalLettersIgnoringASCIICase(characters, byteCast(lowercaseLetters)); } template inline bool equalLettersIgnoringASCIICase(std::span characters, ASCIILiteral lowercaseLetters) @@ -843,7 +858,7 @@ template inline bool equalLettersIgnoringASCIICase(std:: return equalLettersIgnoringASCIICase(characters, lowercaseLetters.span8()); } -template bool inline hasPrefixWithLettersIgnoringASCIICaseCommon(const StringClass& string, std::span lowercaseLetters) +template bool inline hasPrefixWithLettersIgnoringASCIICaseCommon(const StringClass& string, std::span lowercaseLetters) { #if ASSERT_ENABLED ASSERT(lowercaseLetters.front()); @@ -858,14 +873,101 @@ template bool inline hasPrefixWithLettersIgnoringASCIICase } // This is intentionally not marked inline because it's used often and is not speed-critical enough to want it inlined everywhere. -template bool equalLettersIgnoringASCIICaseCommon(const StringClass& string, std::span literal) +template bool equalLettersIgnoringASCIICaseCommon(const StringClass& string, std::span literal) { if (string.length() != literal.size()) return false; return hasPrefixWithLettersIgnoringASCIICaseCommon(string, literal); } -template bool startsWithLettersIgnoringASCIICaseCommon(const StringClass& string, std::span prefix) +template + requires(TriviallyComparableCodeUnits) +bool startsWith(std::span string, std::span prefix) +{ + if (prefix.size() > string.size()) + return false; + + return equal(string.data(), prefix); +} + +template +bool startsWith(std::span string, ASCIILiteral prefix) +{ + return startsWith(string, byteCast(prefix.span())); +} + +template + requires(TriviallyComparableCodeUnits) +bool endsWith(std::span string, std::span suffix) +{ + unsigned suffixSize = suffix.size(); + unsigned referenceSize = string.size(); + if (suffixSize > referenceSize) + return false; + + unsigned startOffset = referenceSize - suffixSize; + + return equal(string.subspan(startOffset).data(), suffix); +} + +template +bool endsWith(std::span string, ASCIILiteral suffix) +{ + return endsWith(string, byteCast(suffix.span())); +} + +template + requires(TriviallyComparableCodeUnits) +bool endsWithLettersIgnoringASCIICaseCommon(std::span string, std::span suffix) +{ + unsigned suffixLength = suffix.size(); + unsigned referenceLength = string.size(); + if (suffixLength > referenceLength) + return false; + + unsigned startOffset = referenceLength - suffixLength; + + return equalIgnoringASCIICaseWithLength(string.subspan(startOffset), suffix, suffixLength); +} + +template + requires(TriviallyComparableCodeUnits) +bool endsWithLettersIgnoringASCIICase(std::span string, std::span suffix) +{ + return endsWithLettersIgnoringASCIICaseCommon(string, suffix); +} + +template +bool endsWithLettersIgnoringASCIICase(std::span string, ASCIILiteral suffix) +{ + return endsWithLettersIgnoringASCIICase(string, byteCast(suffix.span())); +} + +template + requires(TriviallyComparableCodeUnits) +bool startsWithLettersIgnoringASCIICaseCommon(std::span string, std::span prefix) +{ + if (prefix.empty()) + return true; + if (string.size() < prefix.size()) + return false; + return equalLettersIgnoringASCIICaseWithLength(string, prefix, prefix.size()); +} + +template + requires(TriviallyComparableCodeUnits) +bool startsWithLettersIgnoringASCIICase(std::span string, std::span prefix) +{ + return startsWithLettersIgnoringASCIICaseCommon(string, prefix); +} + +template +bool startsWithLettersIgnoringASCIICase(std::span string, ASCIILiteral prefix) +{ + return startsWithLettersIgnoringASCIICase(string, byteCast(prefix.span())); +} + +template bool startsWithLettersIgnoringASCIICaseCommon(const StringClass& string, std::span prefix) { if (prefix.empty()) return true; @@ -886,7 +988,7 @@ template inline bool startsWithLettersIgnoringASCIICaseCom inline bool equalIgnoringASCIICase(const char* a, const char* b) { - return equalIgnoringASCIICase(span8(a), span8(b)); + return equalIgnoringASCIICase(unsafeSpan(a), unsafeSpan(b)); } inline bool equalLettersIgnoringASCIICase(ASCIILiteral a, ASCIILiteral b) @@ -896,7 +998,7 @@ inline bool equalLettersIgnoringASCIICase(ASCIILiteral a, ASCIILiteral b) inline bool equalIgnoringASCIICase(const char* string, ASCIILiteral literal) { - return equalIgnoringASCIICase(span8(string), literal.span8()); + return equalIgnoringASCIICase(unsafeSpan(string), literal.span()); } inline bool equalIgnoringASCIICase(ASCIILiteral a, ASCIILiteral b) @@ -1116,12 +1218,12 @@ inline void copyElements(uint8_t* __restrict destination, const uint64_t* __rest *destination++ = *source++; } -inline void copyElements(UChar* __restrict destination, const LChar* __restrict source, size_t length) +inline void copyElements(char16_t* __restrict destination, const Latin1Character* __restrict source, size_t length) { copyElements(std::bit_cast(destination), std::bit_cast(source), length); } -inline void copyElements(LChar* __restrict destination, const UChar* __restrict source, size_t length) +inline void copyElements(Latin1Character* __restrict destination, const char16_t* __restrict source, size_t length) { copyElements(std::bit_cast(destination), std::bit_cast(source), length); } @@ -1181,11 +1283,22 @@ inline size_t countMatchedCharacters(std::span span, Charac } +using WTF::charactersContain; +using WTF::contains; +using WTF::containsIgnoringASCIICase; +using WTF::endsWith; +using WTF::endsWithLettersIgnoringASCIICase; using WTF::equalIgnoringASCIICase; using WTF::equalIgnoringASCIICaseWithLength; using WTF::equalLettersIgnoringASCIICase; using WTF::equalLettersIgnoringASCIICaseWithLength; +using WTF::findIgnoringASCIICase; using WTF::isLatin1; +using WTF::reverseFind; using WTF::span; -using WTF::span8; -using WTF::charactersContain; +using WTF::spanHasPrefixIgnoringASCIICase; +using WTF::startsWith; +using WTF::startsWithLettersIgnoringASCIICase; +using WTF::unsafeSpan; +using WTF::unsafeSpanIncludingNullTerminator; + diff --git a/Source/WTF/wtf/text/StringConcatenate.h b/Source/WTF/wtf/text/StringConcatenate.h index 6d4b575c606a6..ee0e78ca81b73 100644 --- a/Source/WTF/wtf/text/StringConcatenate.h +++ b/Source/WTF/wtf/text/StringConcatenate.h @@ -67,9 +67,9 @@ template<> class StringTypeAdapter { char m_character; }; -template<> class StringTypeAdapter { +template<> class StringTypeAdapter { public: - StringTypeAdapter(UChar character) + StringTypeAdapter(char16_t character) : m_character { character } { } @@ -77,16 +77,16 @@ template<> class StringTypeAdapter { unsigned length() const { return 1; } bool is8Bit() const { return isLatin1(m_character); } - void writeTo(LChar* destination) const + void writeTo(Latin1Character* destination) const { ASSERT(is8Bit()); *destination = m_character; } - void writeTo(UChar* destination) const { *destination = m_character; } + void writeTo(char16_t* destination) const { *destination = m_character; } private: - UChar m_character; + char16_t m_character; }; template<> class StringTypeAdapter { @@ -99,7 +99,7 @@ template<> class StringTypeAdapter { unsigned length() const { return U16_LENGTH(m_character); } bool is8Bit() const { return isLatin1(m_character); } - void writeTo(LChar* destination) const + void writeTo(Latin1Character* destination) const { ASSERT(is8Bit()); *destination = m_character; @@ -125,31 +125,9 @@ inline unsigned stringLength(size_t length) return static_cast(length); } -template<> class StringTypeAdapter { +template<> class StringTypeAdapter { public: - StringTypeAdapter(const LChar* characters) - : m_characters { characters } - , m_length { computeLength(characters) } - { - } - - unsigned length() const { return m_length; } - bool is8Bit() const { return true; } - template void writeTo(CharacterType* destination) const { StringImpl::copyCharacters(destination, { m_characters, m_length }); } - -private: - static unsigned computeLength(const LChar* characters) - { - return stringLength(std::strlen(byteCast(characters))); - } - - const LChar* m_characters; - unsigned m_length; -}; - -template<> class StringTypeAdapter { -public: - StringTypeAdapter(const UChar* characters) + StringTypeAdapter(const char16_t* characters) : m_characters { characters } , m_length { computeLength(characters) } { @@ -157,11 +135,11 @@ template<> class StringTypeAdapter { unsigned length() const { return m_length; } 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 }); } + void writeTo(Latin1Character*) const { ASSERT(!m_length); } + void writeTo(char16_t* destination) const { StringImpl::copyCharacters(destination, { m_characters, m_length }); } private: - static unsigned computeLength(const UChar* characters) + static unsigned computeLength(const char16_t* characters) { size_t length = 0; while (characters[length]) @@ -169,7 +147,7 @@ template<> class StringTypeAdapter { return stringLength(length); } - const UChar* m_characters; + const char16_t* m_characters; unsigned m_length; }; @@ -186,7 +164,7 @@ template class StringTypeAdapter void writeTo(DestinationCharacterType* destination) const { - using CharacterTypeForString = std::conditional_t; + using CharacterTypeForString = std::conditional_t; static_assert(sizeof(CharacterTypeForString) == sizeof(CharacterType)); StringImpl::copyCharacters(destination, { reinterpret_cast(m_characters), m_length }); } @@ -204,10 +182,10 @@ template<> class StringTypeAdapter : public StringTypeAdapter class StringTypeAdapter : public StringTypeAdapter, void> { +template<> class StringTypeAdapter : public StringTypeAdapter, void> { public: StringTypeAdapter(ASCIILiteral characters) - : StringTypeAdapter, void> { characters.span8() } + : StringTypeAdapter, void> { characters.span8() } { } }; @@ -301,8 +279,8 @@ template<> class StringTypeAdapter { unsigned length() const { return m_characters.lengthUTF16; } bool is8Bit() const { return m_characters.isAllASCII; } - void writeTo(LChar* destination) const { memcpy(destination, m_characters.characters.data(), m_characters.lengthUTF16); } - void writeTo(UChar* destination) const { Unicode::convert(m_characters.characters, std::span { destination, m_characters.lengthUTF16 }); } + void writeTo(Latin1Character* destination) const { memcpy(destination, m_characters.characters.data(), m_characters.lengthUTF16); } + void writeTo(char16_t* destination) const { Unicode::convert(m_characters.characters, std::span { destination, m_characters.lengthUTF16 }); } private: Unicode::CheckedUTF8 m_characters; @@ -354,14 +332,14 @@ template class StringTypeAdapter struct PaddingSpecification { - LChar character; + Latin1Character character; unsigned length; UnderlyingElementType underlyingElement; }; template PaddingSpecification pad(char character, unsigned length, UnderlyingElementType element) { - return { byteCast(character), length, element }; + return { byteCast(character), length, element }; } template class StringTypeAdapter> { diff --git a/Source/WTF/wtf/text/StringConcatenateNumbers.h b/Source/WTF/wtf/text/StringConcatenateNumbers.h index 26306b8ea745f..6f18ac2f01f49 100644 --- a/Source/WTF/wtf/text/StringConcatenateNumbers.h +++ b/Source/WTF/wtf/text/StringConcatenateNumbers.h @@ -80,7 +80,7 @@ class StringTypeAdapter void writeTo(CharacterType* destination) const { StringImpl::copyCharacters(destination, span()); } private: - std::span span() const { return spanReinterpretCast(std::span { m_buffer }).first(m_length); } + std::span span() const { return spanReinterpretCast(std::span { m_buffer }).first(m_length); } NumberToStringBuffer m_buffer; unsigned m_length; @@ -106,8 +106,8 @@ class FormattedNumber { } unsigned length() const { return m_length; } - const LChar* buffer() const { return byteCast(&m_buffer[0]); } - std::span span() const { return spanReinterpretCast(std::span { m_buffer }).first(m_length); } + const Latin1Character* buffer() const { return byteCast(&m_buffer[0]); } + std::span span() const { return spanReinterpretCast(std::span { m_buffer }).first(m_length); } private: NumberToStringBuffer m_buffer; @@ -141,8 +141,8 @@ class FormattedCSSNumber { } unsigned length() const { return m_length; } - const LChar* buffer() const { return byteCast(&m_buffer[0]); } - std::span span() const { return spanReinterpretCast(std::span { m_buffer }).first(m_length); } + const Latin1Character* buffer() const { return byteCast(&m_buffer[0]); } + std::span span() const { return spanReinterpretCast(std::span { m_buffer }).first(m_length); } private: NumberToCSSStringBuffer m_buffer; diff --git a/Source/WTF/wtf/text/StringHasher.h b/Source/WTF/wtf/text/StringHasher.h index 329f26494beb3..3fe42eaf7239b 100644 --- a/Source/WTF/wtf/text/StringHasher.h +++ b/Source/WTF/wtf/text/StringHasher.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include namespace WTF { diff --git a/Source/WTF/wtf/text/StringImpl.cpp b/Source/WTF/wtf/text/StringImpl.cpp index 3c4b20ae32e5f..155dd8f5a00c4 100644 --- a/Source/WTF/wtf/text/StringImpl.cpp +++ b/Source/WTF/wtf/text/StringImpl.cpp @@ -140,11 +140,11 @@ StringImpl::~StringImpl() case BufferOwned: // We use m_data8, but since it is a union with m_data16 this works either way. ASSERT(m_data8); - StringImplMalloc::free(const_cast(m_data8)); + StringImplMalloc::free(const_cast(m_data8)); break; case BufferExternal: { auto* external = static_cast(this); - external->freeExternalBuffer(const_cast(m_data8), sizeInBytes()); + external->freeExternalBuffer(const_cast(m_data8), sizeInBytes()); external->m_free.~ExternalStringImplFreeFunction(); break; } @@ -161,13 +161,13 @@ void StringImpl::destroy(StringImpl* stringImpl) StringImplMalloc::free(stringImpl); } -Ref StringImpl::createWithoutCopyingNonEmpty(std::span characters) +Ref StringImpl::createWithoutCopyingNonEmpty(std::span characters) { ASSERT(!characters.empty()); return adoptRef(*new StringImpl(characters, ConstructWithoutCopying)); } -Ref StringImpl::createWithoutCopyingNonEmpty(std::span characters) +Ref StringImpl::createWithoutCopyingNonEmpty(std::span characters) { ASSERT(!characters.empty()); return adoptRef(*new StringImpl(characters, ConstructWithoutCopying)); @@ -197,15 +197,15 @@ template inline Ref StringImpl::createUninit return constructInternal(*string, length); } -template Ref StringImpl::createUninitializedInternalNonEmpty(size_t length, std::span& data); -template Ref StringImpl::createUninitializedInternalNonEmpty(size_t length, std::span& data); +template Ref StringImpl::createUninitializedInternalNonEmpty(size_t length, std::span& data); +template Ref StringImpl::createUninitializedInternalNonEmpty(size_t length, std::span& data); -Ref StringImpl::createUninitialized(size_t length, std::span& data) +Ref StringImpl::createUninitialized(size_t length, std::span& data) { return createUninitializedInternal(length, data); } -Ref StringImpl::createUninitialized(size_t length, std::span& data) +Ref StringImpl::createUninitialized(size_t length, std::span& data) { return createUninitializedInternal(length, data); } @@ -234,15 +234,15 @@ template inline Ref StringImpl::createUninit return constructInternal(*string, length); } -template Ref StringImpl::createUninitializedInternalNonEmpty(size_t length, LChar*& data); -template Ref StringImpl::createUninitializedInternalNonEmpty(size_t length, UChar*& data); +template Ref StringImpl::createUninitializedInternalNonEmpty(size_t length, Latin1Character*& data); +template Ref StringImpl::createUninitializedInternalNonEmpty(size_t length, char16_t*& data); -Ref StringImpl::createUninitialized(size_t length, LChar*& data) +Ref StringImpl::createUninitialized(size_t length, Latin1Character*& data) { return createUninitializedInternal(length, data); } -Ref StringImpl::createUninitialized(size_t length, UChar*& data) +Ref StringImpl::createUninitialized(size_t length, char16_t*& data) { return createUninitializedInternal(length, data); } @@ -270,27 +270,27 @@ template inline Expected, UTF8Conversion return constructInternal(*string, length); } -Ref StringImpl::reallocate(Ref&& originalString, unsigned length, LChar*& data) +Ref StringImpl::reallocate(Ref&& originalString, unsigned length, Latin1Character*& data) { auto expectedStringImpl = tryReallocate(WTFMove(originalString), length, data); RELEASE_ASSERT(expectedStringImpl); return WTFMove(expectedStringImpl.value()); } -Ref StringImpl::reallocate(Ref&& originalString, unsigned length, UChar*& data) +Ref StringImpl::reallocate(Ref&& originalString, unsigned length, char16_t*& data) { auto expectedStringImpl = tryReallocate(WTFMove(originalString), length, data); RELEASE_ASSERT(expectedStringImpl); return WTFMove(expectedStringImpl.value()); } -Expected, UTF8ConversionError> StringImpl::tryReallocate(Ref&& originalString, unsigned length, LChar*& data) +Expected, UTF8ConversionError> StringImpl::tryReallocate(Ref&& originalString, unsigned length, Latin1Character*& data) { ASSERT(originalString->is8Bit()); return reallocateInternal(WTFMove(originalString), length, data); } -Expected, UTF8ConversionError> StringImpl::tryReallocate(Ref&& originalString, unsigned length, UChar*& data) +Expected, UTF8ConversionError> StringImpl::tryReallocate(Ref&& originalString, unsigned length, char16_t*& data) { ASSERT(!originalString->is8Bit()); return reallocateInternal(WTFMove(originalString), length, data); @@ -306,17 +306,39 @@ template inline Ref StringImpl::createIntern return string; } -Ref StringImpl::create(std::span characters) +Ref StringImpl::create(std::span characters) { return createInternal(characters); } -Ref StringImpl::create(std::span characters) +Ref StringImpl::create(std::span characters) { return createInternal(characters); } -Ref StringImpl::createStaticStringImpl(std::span characters) +RefPtr StringImpl::create(std::span codeUnits) +{ + RELEASE_ASSERT(codeUnits.size() <= String::MaxLength); + + if (!codeUnits.data()) + return nullptr; + if (codeUnits.empty()) + return empty(); + + if (charactersAreAllASCII(codeUnits)) + return create(byteCast(codeUnits)); + + Vector buffer(codeUnits.size()); + + auto result = Unicode::convert(codeUnits, buffer.mutableSpan()); + if (result.code != Unicode::ConversionResultCode::Success) + return nullptr; + + RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(result.buffer.size() <= codeUnits.size()); + return create(result.buffer); +} + +Ref StringImpl::createStaticStringImpl(std::span characters) { if (characters.empty()) return *empty(); @@ -326,7 +348,7 @@ Ref StringImpl::createStaticStringImpl(std::span charac return result; } -Ref StringImpl::createStaticStringImpl(std::span characters) +Ref StringImpl::createStaticStringImpl(std::span characters) { if (characters.empty()) return *empty(); @@ -336,19 +358,19 @@ Ref StringImpl::createStaticStringImpl(std::span charac return result; } -Ref StringImpl::create8BitIfPossible(std::span characters) +Ref StringImpl::create8BitIfPossible(std::span characters) { if (characters.empty()) return *empty(); - std::span data; + std::span data; auto string = createUninitializedInternalNonEmpty(characters.size(), data); size_t i = 0; for (auto character : characters) { if (!isLatin1(character)) return create(characters); - data[i++] = static_cast(character); + data[i++] = static_cast(character); } return string; @@ -390,7 +412,7 @@ Ref StringImpl::convertToLowercaseWithoutLocale() // First scan the string for uppercase and non-ASCII characters: if (is8Bit()) { for (unsigned i = 0; i < m_length; ++i) { - LChar character = m_data8[i]; + Latin1Character character = m_data8[i]; if (UNLIKELY(!isASCII(character) || isASCIIUpper(character))) return convertToLowercaseWithoutLocaleStartingAtFailingIndex8Bit(i); } @@ -402,7 +424,7 @@ Ref StringImpl::convertToLowercaseWithoutLocale() unsigned ored = 0; for (unsigned i = 0; i < m_length; ++i) { - UChar character = m_data16[i]; + char16_t character = m_data16[i]; if (UNLIKELY(isASCIIUpper(character))) noUpper = false; ored |= character; @@ -412,7 +434,7 @@ Ref StringImpl::convertToLowercaseWithoutLocale() return *this; if (!(ored & ~0x7F)) { - std::span data16; + std::span data16; auto newImpl = createUninitializedInternalNonEmpty(m_length, data16); for (unsigned i = 0; i < m_length; ++i) data16[i] = toASCIILower(m_data16[i]); @@ -424,7 +446,7 @@ Ref StringImpl::convertToLowercaseWithoutLocale() int32_t length = m_length; // Do a slower implementation for cases that include non-ASCII characters. - std::span data16; + std::span data16; auto newImpl = createUninitializedInternalNonEmpty(m_length, data16); UErrorCode status = U_ZERO_ERROR; @@ -443,7 +465,7 @@ Ref StringImpl::convertToLowercaseWithoutLocale() Ref StringImpl::convertToLowercaseWithoutLocaleStartingAtFailingIndex8Bit(unsigned failingIndex) { ASSERT(is8Bit()); - std::span data8; + std::span data8; auto newImpl = createUninitializedInternalNonEmpty(m_length, data8); for (unsigned i = 0; i < failingIndex; ++i) { @@ -453,12 +475,12 @@ Ref StringImpl::convertToLowercaseWithoutLocaleStartingAtFailingInde } for (unsigned i = failingIndex; i < m_length; ++i) { - LChar character = m_data8[i]; + Latin1Character character = m_data8[i]; if (isASCII(character)) data8[i] = toASCIILower(character); else { ASSERT(isLatin1(u_tolower(character))); - data8[i] = static_cast(u_tolower(character)); + data8[i] = static_cast(u_tolower(character)); } } @@ -478,7 +500,7 @@ Ref StringImpl::convertToUppercaseWithoutLocale() // First scan the string for uppercase and non-ASCII characters: if (is8Bit()) { for (unsigned i = 0; i < m_length; ++i) { - LChar character = m_data8[i]; + Latin1Character character = m_data8[i]; if (UNLIKELY(!isASCII(character) || isASCIILower(character))) return convertToUppercaseWithoutLocaleStartingAtFailingIndex8Bit(i); } @@ -490,7 +512,7 @@ Ref StringImpl::convertToUppercaseWithoutLocale() Ref StringImpl::convertToUppercaseWithoutLocaleStartingAtFailingIndex8Bit(unsigned failingIndex) { ASSERT(is8Bit()); - std::span destination; + std::span destination; auto newImpl = createUninitialized(m_length, destination); for (unsigned i = 0; i < failingIndex; ++i) { @@ -502,7 +524,7 @@ Ref StringImpl::convertToUppercaseWithoutLocaleStartingAtFailingInde // Do a faster loop for the case where all the characters are ASCII. unsigned ored = 0; for (unsigned i = failingIndex; i < m_length; ++i) { - LChar character = m_data8[i]; + Latin1Character character = m_data8[i]; ored |= character; destination[i] = toASCIIUpper(character); } @@ -516,16 +538,16 @@ Ref StringImpl::convertToUppercaseWithoutLocaleStartingAtFailingInde // 1. Some Latin-1 characters when converted to upper case are 16 bit characters. // 2. Lower case sharp-S converts to "SS" (two characters) for (unsigned i = 0; i < m_length; ++i) { - LChar character = m_data8[i]; + Latin1Character character = m_data8[i]; if (UNLIKELY(character == smallLetterSharpS)) ++numberSharpSCharacters; ASSERT(u_toupper(character) <= 0xFFFF); - UChar upper = u_toupper(character); + char16_t upper = u_toupper(character); if (UNLIKELY(!isLatin1(upper))) { // Since this upper-cased character does not fit in an 8-bit string, we need to take the 16-bit path. return convertToUppercaseWithoutLocaleUpconvert(); } - destination[i] = static_cast(upper); + destination[i] = static_cast(upper); } if (!numberSharpSCharacters) @@ -538,13 +560,13 @@ Ref StringImpl::convertToUppercaseWithoutLocaleStartingAtFailingInde size_t destinationIndex = 0; for (unsigned i = 0; i < m_length; ++i) { - LChar character = m_data8[i]; + Latin1Character character = m_data8[i]; if (character == smallLetterSharpS) { destination[destinationIndex++] = 'S'; destination[destinationIndex++] = 'S'; } else { ASSERT(isLatin1(u_toupper(character))); - destination[destinationIndex++] = static_cast(u_toupper(character)); + destination[destinationIndex++] = static_cast(u_toupper(character)); } } @@ -556,13 +578,13 @@ Ref StringImpl::convertToUppercaseWithoutLocaleUpconvert() auto upconvertedCharacters = StringView(*this).upconvertedCharacters(); auto source16 = upconvertedCharacters.span(); - std::span data16; + std::span data16; auto newImpl = createUninitialized(source16.size(), data16); // Do a faster loop for the case where all the characters are ASCII. unsigned ored = 0; for (unsigned i = 0; i < m_length; ++i) { - UChar character = source16[i]; + char16_t character = source16[i]; ored |= character; data16[i] = toASCIIUpper(character); } @@ -585,8 +607,8 @@ Ref StringImpl::convertToUppercaseWithoutLocaleUpconvert() static inline bool needsTurkishCasingRules(const AtomString& locale) { // Either "tr" or "az" locale, with ASCII case insensitive comparison and allowing for an ignored subtag. - UChar first = locale[0]; - UChar second = locale[1]; + char16_t first = locale[0]; + char16_t second = locale[1]; return ((isASCIIAlphaCaselessEqual(first, 't') && isASCIIAlphaCaselessEqual(second, 'r')) || (isASCIIAlphaCaselessEqual(first, 'a') && isASCIIAlphaCaselessEqual(second, 'z'))) && (locale.length() == 2 || locale[2] == '-'); @@ -628,7 +650,7 @@ Ref StringImpl::convertToLowercaseWithLocale(const AtomString& local auto upconvertedCharacters = StringView(*this).upconvertedCharacters(); auto source16 = upconvertedCharacters.span(); - std::span data16; + std::span data16; auto newString = createUninitialized(source16.size(), data16); UErrorCode status = U_ZERO_ERROR; size_t realLength = u_strToLower(data16.data(), data16.size(), source16.data(), source16.size(), locale, &status); @@ -663,7 +685,7 @@ Ref StringImpl::convertToUppercaseWithLocale(const AtomString& local auto upconvertedCharacters = StringView(*this).upconvertedCharacters(); auto source16 = upconvertedCharacters.span(); - std::span data16; + std::span data16; auto newString = createUninitialized(source16.size(), data16); UErrorCode status = U_ZERO_ERROR; size_t realLength = u_strToUpper(data16.data(), data16.size(), source16.data(), source16.size(), locale, &status); @@ -702,7 +724,7 @@ Ref StringImpl::foldCase() } if (!need16BitCharacters) { - std::span data8; + std::span data8; auto folded = createUninitializedInternalNonEmpty(m_length, data8); copyCharacters(data8.data(), { m_data8, failingIndex }); for (unsigned i = failingIndex; i < m_length; ++i) { @@ -711,7 +733,7 @@ Ref StringImpl::foldCase() data8[i] = toASCIILower(character); else { ASSERT(isLatin1(u_foldCase(character, U_FOLD_CASE_DEFAULT))); - data8[i] = static_cast(u_foldCase(character, U_FOLD_CASE_DEFAULT)); + data8[i] = static_cast(u_foldCase(character, U_FOLD_CASE_DEFAULT)); } } return folded; @@ -721,7 +743,7 @@ Ref StringImpl::foldCase() bool noUpper = true; unsigned ored = 0; for (unsigned i = 0; i < m_length; ++i) { - UChar character = m_data16[i]; + char16_t character = m_data16[i]; if (UNLIKELY(isASCIIUpper(character))) noUpper = false; ored |= character; @@ -731,7 +753,7 @@ Ref StringImpl::foldCase() // String was all ASCII and no uppercase, so just return as-is. return *this; } - std::span data16; + std::span data16; auto folded = createUninitializedInternalNonEmpty(m_length, data16); for (unsigned i = 0; i < m_length; ++i) data16[i] = toASCIILower(m_data16[i]); @@ -745,7 +767,7 @@ Ref StringImpl::foldCase() auto upconvertedCharacters = StringView(*this).upconvertedCharacters(); auto source16 = upconvertedCharacters.span(); - std::span data; + std::span data; auto folded = createUninitializedInternalNonEmpty(source16.size(), data); UErrorCode status = U_ZERO_ERROR; size_t realLength = u_strFoldCase(data.data(), source16.size(), source16.data(), source16.size(), U_FOLD_CASE_DEFAULT, &status); @@ -865,8 +887,8 @@ template inline Ref St Ref StringImpl::simplifyWhiteSpace(CodeUnitMatchFunction isWhiteSpace) { if (is8Bit()) - return StringImpl::simplifyMatchedCharactersToSpace(isWhiteSpace); - return StringImpl::simplifyMatchedCharactersToSpace(isWhiteSpace); + return StringImpl::simplifyMatchedCharactersToSpace(isWhiteSpace); + return StringImpl::simplifyMatchedCharactersToSpace(isWhiteSpace); } double StringImpl::toDouble(bool* ok) @@ -883,7 +905,7 @@ float StringImpl::toFloat(bool* ok) return charactersToFloat(span16(), ok); } -size_t StringImpl::find(std::span matchString, size_t start) +size_t StringImpl::find(std::span matchString, size_t start) { ASSERT(!matchString.empty()); ASSERT(matchString.size() <= static_cast(MaxLength)); @@ -941,7 +963,7 @@ size_t StringImpl::find(std::span matchString, size_t start) return start + i; } -size_t StringImpl::reverseFind(std::span matchString, size_t start) +size_t StringImpl::reverseFind(std::span matchString, size_t start) { ASSERT(!matchString.empty()); @@ -1015,7 +1037,7 @@ size_t StringImpl::findIgnoringASCIICase(StringView matchString, size_t start) c return ::WTF::findIgnoringASCIICase(*this, matchString, start); } -size_t StringImpl::reverseFind(UChar character, size_t start) +size_t StringImpl::reverseFind(char16_t character, size_t start) { if (is8Bit()) return WTF::reverseFind(span8(), character, start); @@ -1059,8 +1081,8 @@ ALWAYS_INLINE static bool equalInner(const StringImpl& string, unsigned start, s ASSERT(start + matchString.size() <= string.length()); if (string.is8Bit()) - return equal(string.span8().data() + start, byteCast(matchString)); - return equal(string.span16().data() + start, byteCast(matchString)); + return equal(string.span8().data() + start, byteCast(matchString)); + return equal(string.span16().data() + start, byteCast(matchString)); } ALWAYS_INLINE static bool equalInner(const StringImpl& string, unsigned start, StringView matchString) @@ -1092,7 +1114,7 @@ bool StringImpl::startsWithIgnoringASCIICase(StringView prefix) const return prefix && ::WTF::startsWithIgnoringASCIICase(*this, prefix); } -bool StringImpl::startsWith(UChar character) const +bool StringImpl::startsWith(char16_t character) const { return m_length && (*this)[0] == character; } @@ -1117,7 +1139,7 @@ bool StringImpl::endsWithIgnoringASCIICase(StringView suffix) const return suffix && ::WTF::endsWithIgnoringASCIICase(*this, suffix); } -bool StringImpl::endsWith(UChar character) const +bool StringImpl::endsWith(char16_t character) const { return m_length && (*this)[m_length - 1] == character; } @@ -1132,7 +1154,7 @@ bool StringImpl::hasInfixEndingAt(StringView matchString, size_t end) const return end >= matchString.length() && equalInner(*this, end - matchString.length(), matchString); } -Ref StringImpl::replace(UChar target, UChar replacement) +Ref StringImpl::replace(char16_t target, char16_t replacement) { if (target == replacement) return *this; @@ -1144,7 +1166,7 @@ Ref StringImpl::replace(UChar target, UChar replacement) } unsigned i; for (i = 0; i != m_length; ++i) { - if (static_cast(m_data8[i]) == target) + if (static_cast(m_data8[i]) == target) break; } if (i == m_length) @@ -1174,7 +1196,7 @@ Ref StringImpl::replace(size_t position, size_t lengthToReplace, Str CRASH(); if (is8Bit() && (!string || string.is8Bit())) { - std::span data; + std::span data; auto newImpl = createUninitialized(length() - lengthToReplace + lengthToInsert, data); copyCharacters(data.data(), { m_data8, position }); if (string) @@ -1182,7 +1204,7 @@ Ref StringImpl::replace(size_t position, size_t lengthToReplace, Str copyCharacters(data.subspan(position + lengthToInsert).data(), { m_data8 + position + lengthToReplace, length() - position - lengthToReplace }); return newImpl; } - std::span data; + std::span data; auto newImpl = createUninitialized(length() - lengthToReplace + lengthToInsert, data); if (is8Bit()) copyCharacters(data.data(), { m_data8, position }); @@ -1201,7 +1223,7 @@ Ref StringImpl::replace(size_t position, size_t lengthToReplace, Str return newImpl; } -Ref StringImpl::replace(UChar pattern, StringView replacement) +Ref StringImpl::replace(char16_t pattern, StringView replacement) { if (!replacement) return *this; @@ -1210,7 +1232,7 @@ Ref StringImpl::replace(UChar pattern, StringView replacement) return replace(pattern, replacement.span16()); } -Ref StringImpl::replace(UChar pattern, std::span replacement) +Ref StringImpl::replace(char16_t pattern, std::span replacement) { ASSERT(replacement.data()); @@ -1244,7 +1266,7 @@ Ref StringImpl::replace(UChar pattern, std::span replac size_t dstOffset = 0; if (is8Bit()) { - std::span data; + std::span data; auto newImpl = createUninitialized(newSize, data); while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) { @@ -1264,7 +1286,7 @@ Ref StringImpl::replace(UChar pattern, std::span replac return newImpl; } - std::span data; + std::span data; auto newImpl = createUninitialized(newSize, data); while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) { @@ -1286,7 +1308,7 @@ Ref StringImpl::replace(UChar pattern, std::span replac return newImpl; } -Ref StringImpl::replace(UChar pattern, std::span replacement) +Ref StringImpl::replace(char16_t pattern, std::span replacement) { ASSERT(replacement.data()); @@ -1320,7 +1342,7 @@ Ref StringImpl::replace(UChar pattern, std::span replac size_t dstOffset = 0; if (is8Bit()) { - std::span data; + std::span data; auto newImpl = createUninitialized(newSize, data); while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) { @@ -1342,7 +1364,7 @@ Ref StringImpl::replace(UChar pattern, std::span replac return newImpl; } - std::span data; + std::span data; auto newImpl = createUninitialized(newSize, data); while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) { @@ -1412,7 +1434,7 @@ Ref StringImpl::replace(StringView pattern, StringView replacement) // 4. This is 16 bit and replacement is 8 bit. if (srcIs8Bit && replacementIs8Bit) { // Case 1 - std::span data; + std::span data; auto newImpl = createUninitialized(newSize, data); while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) { srcSegmentLength = srcSegmentEnd - srcSegmentStart; @@ -1431,7 +1453,7 @@ Ref StringImpl::replace(StringView pattern, StringView replacement) return newImpl; } - std::span data; + std::span data; auto newImpl = createUninitialized(newSize, data); while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) { srcSegmentLength = srcSegmentEnd - srcSegmentStart; @@ -1489,17 +1511,17 @@ template inline bool equalInternal(const StringImpl* a, return a->span16().front() == b.front() && equal(a->span16().data() + 1, b.subspan(1)); } -bool equal(const StringImpl* a, std::span b) +bool equal(const StringImpl* a, std::span b) { return equalInternal(a, b); } -bool equal(const StringImpl* a, std::span b) +bool equal(const StringImpl* a, std::span b) { return equalInternal(a, b); } -bool equal(const StringImpl* a, const LChar* b) +bool equal(const StringImpl* a, const Latin1Character* b) { if (!a) return !b; @@ -1511,8 +1533,8 @@ bool equal(const StringImpl* a, const LChar* b) if (a->is8Bit()) { auto aSpan = a->span8(); for (unsigned i = 0; i != length; ++i) { - LChar bc = b[i]; - LChar ac = aSpan[i]; + Latin1Character bc = b[i]; + Latin1Character ac = aSpan[i]; if (!bc) return false; if (ac != bc) @@ -1524,7 +1546,7 @@ bool equal(const StringImpl* a, const LChar* b) auto aSpan = a->span16(); for (unsigned i = 0; i != length; ++i) { - LChar bc = b[i]; + Latin1Character bc = b[i]; if (!bc) return false; if (aSpan[i] != bc) @@ -1577,14 +1599,14 @@ std::optional StringImpl::defaultWritingDirection() return std::nullopt; } -Ref StringImpl::adopt(StringBuffer&& buffer) +Ref StringImpl::adopt(StringBuffer&& buffer) { if (!buffer.length()) return *empty(); return adoptRef(*new StringImpl(buffer.releaseSpan())); } -Ref StringImpl::adopt(StringBuffer&& buffer) +Ref StringImpl::adopt(StringBuffer&& buffer) { if (!buffer.length()) return *empty(); @@ -1600,21 +1622,21 @@ size_t StringImpl::sizeInBytes() const return size + sizeof(*this); } -Expected StringImpl::utf8ForCharacters(std::span source) +Expected StringImpl::utf8ForCharacters(std::span source) { return tryGetUTF8ForCharacters([] (std::span converted) { return CString { converted }; }, source); } -Expected StringImpl::utf8ForCharacters(std::span characters, ConversionMode mode) +Expected StringImpl::utf8ForCharacters(std::span characters, ConversionMode mode) { return tryGetUTF8ForCharacters([] (std::span converted) { return CString { converted }; }, characters, mode); } -Expected StringImpl::utf8ForCharactersIntoBuffer(std::span span, ConversionMode mode, Vector& bufferVector) +Expected StringImpl::utf8ForCharactersIntoBuffer(std::span span, ConversionMode mode, Vector& bufferVector) { ASSERT(bufferVector.size() == span.size() * 3); ConversionResult result; @@ -1667,7 +1689,7 @@ unsigned StringImpl::concurrentHash() const return hash; } -bool equalIgnoringNullity(std::span a, StringImpl* b) +bool equalIgnoringNullity(std::span a, StringImpl* b) { if (!b) return a.empty(); diff --git a/Source/WTF/wtf/text/StringImpl.h b/Source/WTF/wtf/text/StringImpl.h index 3e4d7e974905b..6f79fb1ea1951 100644 --- a/Source/WTF/wtf/text/StringImpl.h +++ b/Source/WTF/wtf/text/StringImpl.h @@ -89,7 +89,7 @@ template struct HashAndCharactersTranslator; // Define STRING_STATS to 1 turn on runtime statistics of string sizes and memory usage. #define STRING_STATS 0 -template bool containsOnly(std::span); +template bool containsOnly(std::span); #if STRING_STATS @@ -154,8 +154,8 @@ class STRING_IMPL_ALIGNMENT StringImplShape { static constexpr unsigned MaxLength = std::numeric_limits::max(); protected: - StringImplShape(unsigned refCount, std::span, unsigned hashAndFlags); - StringImplShape(unsigned refCount, std::span, unsigned hashAndFlags); + StringImplShape(unsigned refCount, std::span, unsigned hashAndFlags); + StringImplShape(unsigned refCount, std::span, unsigned hashAndFlags); enum ConstructWithConstExprTag { ConstructWithConstExpr }; template constexpr StringImplShape(unsigned refCount, unsigned length, const char (&characters)[characterCount], unsigned hashAndFlags, ConstructWithConstExprTag); @@ -164,8 +164,8 @@ class STRING_IMPL_ALIGNMENT StringImplShape { unsigned m_refCount; unsigned m_length; union { - const LChar* m_data8; - const UChar* m_data16; + const Latin1Character* m_data8; + const char16_t* m_data16; // It seems that reinterpret_cast prevents constexpr's compile time initialization in VC++. // These are needed to avoid reinterpret_cast. const char* m_data8Char; @@ -241,62 +241,62 @@ class StringImpl : private StringImplShape { explicit StringImpl(unsigned length); // Create a StringImpl adopting ownership of the provided buffer (BufferOwned). - template StringImpl(MallocPtr, unsigned length); - template StringImpl(MallocPtr, unsigned length); - template explicit StringImpl(MallocSpan); - template explicit StringImpl(MallocSpan); + template StringImpl(MallocPtr, unsigned length); + template StringImpl(MallocPtr, unsigned length); + template explicit StringImpl(MallocSpan); + template explicit StringImpl(MallocSpan); enum ConstructWithoutCopyingTag { ConstructWithoutCopying }; - StringImpl(std::span, ConstructWithoutCopyingTag); - StringImpl(std::span, ConstructWithoutCopyingTag); + StringImpl(std::span, ConstructWithoutCopyingTag); + StringImpl(std::span, ConstructWithoutCopyingTag); // Used to create new strings that are a substring of an existing StringImpl (BufferSubstring). - StringImpl(std::span, Ref&&); - StringImpl(std::span, Ref&&); + StringImpl(std::span, Ref&&); + StringImpl(std::span, Ref&&); public: WTF_EXPORT_PRIVATE static void destroy(StringImpl*); - WTF_EXPORT_PRIVATE static Ref create(std::span); - WTF_EXPORT_PRIVATE static Ref create(std::span); - ALWAYS_INLINE static Ref create(std::span characters) { return create(byteCast(characters)); } - WTF_EXPORT_PRIVATE static Ref create8BitIfPossible(std::span); + WTF_EXPORT_PRIVATE static Ref create(std::span); + WTF_EXPORT_PRIVATE static Ref create(std::span); + ALWAYS_INLINE static Ref create(std::span characters) { return create(byteCast(characters)); } + WTF_EXPORT_PRIVATE static Ref create8BitIfPossible(std::span); - // Not using create() naming to encourage developers to call create(ASCIILiteral) when they have a string literal. - ALWAYS_INLINE static Ref createFromCString(const char* characters) { return create(WTF::span8(characters)); } + // Construct a string with UTF-8 data, null if it contains invalid UTF-8 sequences. + WTF_EXPORT_PRIVATE static RefPtr create(std::span); static Ref createSubstringSharingImpl(StringImpl&, unsigned offset, unsigned length); ALWAYS_INLINE static Ref create(ASCIILiteral literal) { return createWithoutCopying(literal.span8()); } - static Ref createWithoutCopying(std::span characters) { return characters.empty() ? Ref { *empty() } : createWithoutCopyingNonEmpty(characters); } - static Ref createWithoutCopying(std::span characters) { return characters.empty() ? Ref { *empty() } : createWithoutCopyingNonEmpty(characters); } - ALWAYS_INLINE static Ref createWithoutCopying(std::span characters) { return createWithoutCopying(byteCast(characters)); } + static Ref createWithoutCopying(std::span characters) { return characters.empty() ? Ref { *empty() } : createWithoutCopyingNonEmpty(characters); } + static Ref createWithoutCopying(std::span characters) { return characters.empty() ? Ref { *empty() } : createWithoutCopyingNonEmpty(characters); } + ALWAYS_INLINE static Ref createWithoutCopying(std::span characters) { return createWithoutCopying(byteCast(characters)); } - WTF_EXPORT_PRIVATE static Ref createUninitialized(size_t length, LChar*&); - WTF_EXPORT_PRIVATE static Ref createUninitialized(size_t length, UChar*&); + WTF_EXPORT_PRIVATE static Ref createUninitialized(size_t length, Latin1Character*&); + WTF_EXPORT_PRIVATE static Ref createUninitialized(size_t length, char16_t*&); template static RefPtr tryCreateUninitialized(size_t length, CharacterType*&); - WTF_EXPORT_PRIVATE static Ref createUninitialized(size_t length, std::span&); - WTF_EXPORT_PRIVATE static Ref createUninitialized(size_t length, std::span&); + WTF_EXPORT_PRIVATE static Ref createUninitialized(size_t length, std::span&); + WTF_EXPORT_PRIVATE static Ref createUninitialized(size_t length, std::span&); template static RefPtr tryCreateUninitialized(size_t length, std::span&); - static Ref createByReplacingInCharacters(std::span, UChar target, UChar replacement, size_t indexOfFirstTargetCharacter); - static Ref createByReplacingInCharacters(std::span, UChar target, UChar replacement, size_t indexOfFirstTargetCharacter); + static Ref createByReplacingInCharacters(std::span, char16_t target, char16_t replacement, size_t indexOfFirstTargetCharacter); + static Ref createByReplacingInCharacters(std::span, char16_t target, char16_t replacement, size_t indexOfFirstTargetCharacter); static Ref createStaticStringImpl(std::span characters) { - ASSERT(charactersAreAllASCII(byteCast(characters))); - return createStaticStringImpl(byteCast(characters)); + ASSERT(charactersAreAllASCII(byteCast(characters))); + return createStaticStringImpl(byteCast(characters)); } - WTF_EXPORT_PRIVATE static Ref createStaticStringImpl(std::span); - WTF_EXPORT_PRIVATE static Ref createStaticStringImpl(std::span); + WTF_EXPORT_PRIVATE static Ref createStaticStringImpl(std::span); + WTF_EXPORT_PRIVATE static Ref createStaticStringImpl(std::span); // Reallocate the StringImpl. The originalString must be only owned by the Ref, // and the buffer ownership must be BufferInternal. Just like the input pointer of realloc(), // the originalString can't be used after this function. - static Ref reallocate(Ref&& originalString, unsigned length, LChar*& data); - static Ref reallocate(Ref&& originalString, unsigned length, UChar*& data); - static Expected, UTF8ConversionError> tryReallocate(Ref&& originalString, unsigned length, LChar*& data); - static Expected, UTF8ConversionError> tryReallocate(Ref&& originalString, unsigned length, UChar*& data); + static Ref reallocate(Ref&& originalString, unsigned length, Latin1Character*& data); + static Ref reallocate(Ref&& originalString, unsigned length, char16_t*& data); + static Expected, UTF8ConversionError> tryReallocate(Ref&& originalString, unsigned length, Latin1Character*& data); + static Expected, UTF8ConversionError> tryReallocate(Ref&& originalString, unsigned length, char16_t*& data); static constexpr unsigned flagsOffset() { return OBJECT_OFFSETOF(StringImpl, m_hashAndFlags); } static constexpr unsigned flagIs8Bit() { return s_hashFlag8BitBuffer; } @@ -308,16 +308,16 @@ class StringImpl : private StringImplShape { template static Ref adopt(Vector&&); - WTF_EXPORT_PRIVATE static Ref adopt(StringBuffer&&); - WTF_EXPORT_PRIVATE static Ref adopt(StringBuffer&&); + WTF_EXPORT_PRIVATE static Ref adopt(StringBuffer&&); + WTF_EXPORT_PRIVATE static Ref adopt(StringBuffer&&); unsigned length() const { return m_length; } static constexpr ptrdiff_t lengthMemoryOffset() { return OBJECT_OFFSETOF(StringImpl, m_length); } bool isEmpty() const { return !m_length; } bool is8Bit() const { return m_hashAndFlags & s_hashFlag8BitBuffer; } - ALWAYS_INLINE std::span span8() const LIFETIME_BOUND { ASSERT(is8Bit()); return { m_data8, length() }; } - ALWAYS_INLINE std::span span16() const LIFETIME_BOUND { ASSERT(!is8Bit() || isEmpty()); return { m_data16, length() }; } + ALWAYS_INLINE std::span span8() const LIFETIME_BOUND { ASSERT(is8Bit()); return { m_data8, length() }; } + ALWAYS_INLINE std::span span16() const LIFETIME_BOUND { ASSERT(!is8Bit() || isEmpty()); return { m_data16, length() }; } template std::span span() const LIFETIME_BOUND; @@ -334,14 +334,14 @@ class StringImpl : private StringImplShape { bool isSubString() const { return bufferOwnership() == BufferSubstring; } - static WTF_EXPORT_PRIVATE Expected utf8ForCharacters(std::span characters); - static WTF_EXPORT_PRIVATE Expected utf8ForCharacters(std::span characters, ConversionMode = LenientConversion); - static WTF_EXPORT_PRIVATE Expected utf8ForCharactersIntoBuffer(std::span characters, ConversionMode, Vector&); + static WTF_EXPORT_PRIVATE Expected utf8ForCharacters(std::span characters); + static WTF_EXPORT_PRIVATE Expected utf8ForCharacters(std::span characters, ConversionMode = LenientConversion); + static WTF_EXPORT_PRIVATE Expected utf8ForCharactersIntoBuffer(std::span characters, ConversionMode, Vector&); template - static Expected>, UTF8ConversionError> tryGetUTF8ForCharacters(const Func&, std::span characters); + static Expected>, UTF8ConversionError> tryGetUTF8ForCharacters(NOESCAPE const Func&, std::span characters); template - static Expected>, UTF8ConversionError> tryGetUTF8ForCharacters(const Func&, std::span characters, ConversionMode = LenientConversion); + static Expected>, UTF8ConversionError> tryGetUTF8ForCharacters(const Func&, std::span characters, ConversionMode = LenientConversion); template Expected>, UTF8ConversionError> tryGetUTF8(const Func&, ConversionMode = LenientConversion) const; @@ -421,17 +421,17 @@ class StringImpl : private StringImplShape { return copyElements(destination, source.data(), source.size()); } - ALWAYS_INLINE static void copyCharacters(UChar* destination, std::span source) + ALWAYS_INLINE static void copyCharacters(char16_t* destination, std::span source) { - static_assert(sizeof(UChar) == sizeof(uint16_t)); - static_assert(sizeof(LChar) == sizeof(uint8_t)); + static_assert(sizeof(char16_t) == sizeof(uint16_t)); + static_assert(sizeof(Latin1Character) == sizeof(uint8_t)); return copyElements(std::bit_cast(destination), source.data(), source.size()); } - ALWAYS_INLINE static void copyCharacters(LChar* destination, std::span source) + ALWAYS_INLINE static void copyCharacters(Latin1Character* destination, std::span source) { - static_assert(sizeof(UChar) == sizeof(uint16_t)); - static_assert(sizeof(LChar) == sizeof(uint8_t)); + static_assert(sizeof(char16_t) == sizeof(uint16_t)); + static_assert(sizeof(Latin1Character) == sizeof(uint8_t)); #if ASSERT_ENABLED for (auto character : source) ASSERT(isLatin1(character)); @@ -446,8 +446,8 @@ class StringImpl : private StringImplShape { WTF_EXPORT_PRIVATE Ref substring(unsigned position, unsigned length = MaxLength); - UChar at(unsigned) const; - UChar operator[](unsigned i) const { return at(i); } + char16_t at(unsigned) const; + char16_t operator[](unsigned i) const { return at(i); } WTF_EXPORT_PRIVATE char32_t characterStartingAt(unsigned); // FIXME: Like the strict functions above, these give false for "ok" when there is trailing garbage. @@ -473,12 +473,12 @@ class StringImpl : private StringImplShape { bool containsOnlyASCII() const; bool containsOnlyLatin1() const; - template bool containsOnly() const; + template bool containsOnly() const; - size_t find(LChar character, size_t start = 0); - size_t find(char character, size_t start = 0); - size_t find(UChar character, size_t start = 0); - template>* = nullptr> + size_t find(Latin1Character, size_t start = 0); + size_t find(char, size_t start = 0); + size_t find(char16_t, size_t start = 0); + template>* = nullptr> size_t find(CodeUnitMatchFunction, size_t start = 0); ALWAYS_INLINE size_t find(ASCIILiteral literal, size_t start = 0) { return find(literal.span8(), start); } WTF_EXPORT_PRIVATE size_t find(StringView); @@ -486,27 +486,27 @@ class StringImpl : private StringImplShape { WTF_EXPORT_PRIVATE size_t findIgnoringASCIICase(StringView) const; WTF_EXPORT_PRIVATE size_t findIgnoringASCIICase(StringView, size_t start) const; - WTF_EXPORT_PRIVATE size_t reverseFind(UChar, size_t start = MaxLength); + WTF_EXPORT_PRIVATE size_t reverseFind(char16_t, size_t start = MaxLength); WTF_EXPORT_PRIVATE size_t reverseFind(StringView, size_t start = MaxLength); ALWAYS_INLINE size_t reverseFind(ASCIILiteral literal, size_t start = MaxLength) { return reverseFind(literal.span8(), start); } WTF_EXPORT_PRIVATE bool startsWith(StringView) const; WTF_EXPORT_PRIVATE bool startsWithIgnoringASCIICase(StringView) const; - WTF_EXPORT_PRIVATE bool startsWith(UChar) const; + WTF_EXPORT_PRIVATE bool startsWith(char16_t) const; WTF_EXPORT_PRIVATE bool startsWith(std::span) const; WTF_EXPORT_PRIVATE bool hasInfixStartingAt(StringView, size_t start) const; WTF_EXPORT_PRIVATE bool endsWith(StringView); WTF_EXPORT_PRIVATE bool endsWithIgnoringASCIICase(StringView) const; - WTF_EXPORT_PRIVATE bool endsWith(UChar) const; + WTF_EXPORT_PRIVATE bool endsWith(char16_t) const; WTF_EXPORT_PRIVATE bool endsWith(std::span) const; WTF_EXPORT_PRIVATE bool hasInfixEndingAt(StringView, size_t end) const; - WTF_EXPORT_PRIVATE Ref replace(UChar, UChar); - WTF_EXPORT_PRIVATE Ref replace(UChar, StringView); - ALWAYS_INLINE Ref replace(UChar pattern, std::span replacement) { return replace(pattern, byteCast(replacement)); } - WTF_EXPORT_PRIVATE Ref replace(UChar, std::span); - Ref replace(UChar, std::span); + WTF_EXPORT_PRIVATE Ref replace(char16_t, char16_t); + WTF_EXPORT_PRIVATE Ref replace(char16_t, StringView); + ALWAYS_INLINE Ref replace(char16_t pattern, std::span replacement) { return replace(pattern, byteCast(replacement)); } + WTF_EXPORT_PRIVATE Ref replace(char16_t, std::span); + Ref replace(char16_t, std::span); WTF_EXPORT_PRIVATE Ref replace(StringView, StringView); WTF_EXPORT_PRIVATE Ref replace(size_t start, size_t length, StringView); @@ -533,8 +533,8 @@ class StringImpl : private StringImplShape { // Used to create new symbol string that holds an existing [[Description]] string as a substring buffer (BufferSubstring). enum CreateSymbolTag { CreateSymbol }; - StringImpl(CreateSymbolTag, std::span); - StringImpl(CreateSymbolTag, std::span); + StringImpl(CreateSymbolTag, std::span); + StringImpl(CreateSymbolTag, std::span); // Null symbol. explicit StringImpl(CreateSymbolTag); @@ -544,8 +544,8 @@ class StringImpl : private StringImplShape { template static size_t maxInternalLength(); template static constexpr size_t tailOffset(); - WTF_EXPORT_PRIVATE size_t find(std::span, size_t start); - WTF_EXPORT_PRIVATE size_t reverseFind(std::span, size_t start); + WTF_EXPORT_PRIVATE size_t find(std::span, size_t start); + WTF_EXPORT_PRIVATE size_t reverseFind(std::span, size_t start); bool requiresCopy() const; template const T* tailPointer() const; @@ -556,8 +556,8 @@ class StringImpl : private StringImplShape { enum class CaseConvertType { Upper, Lower }; template static Ref convertASCIICase(StringImpl&, std::span); - WTF_EXPORT_PRIVATE static Ref createWithoutCopyingNonEmpty(std::span); - WTF_EXPORT_PRIVATE static Ref createWithoutCopyingNonEmpty(std::span); + WTF_EXPORT_PRIVATE static Ref createWithoutCopyingNonEmpty(std::span); + WTF_EXPORT_PRIVATE static Ref createWithoutCopyingNonEmpty(std::span); template Ref trimMatchedCharacters(CodeUnitPredicate); template ALWAYS_INLINE Ref removeCharactersImpl(std::span characters, const Predicate&); @@ -619,18 +619,18 @@ template<> struct ValueCheck { #endif // ASSERT_ENABLED WTF_EXPORT_PRIVATE bool equal(const StringImpl*, const StringImpl*); -WTF_EXPORT_PRIVATE bool equal(const StringImpl*, const LChar*); -inline bool equal(const StringImpl* a, const char* b) { return equal(a, byteCast(b)); } -WTF_EXPORT_PRIVATE bool equal(const StringImpl*, std::span); -WTF_EXPORT_PRIVATE bool equal(const StringImpl*, std::span); +WTF_EXPORT_PRIVATE bool equal(const StringImpl*, const Latin1Character*); +WTF_EXPORT_PRIVATE bool equal(const StringImpl*, std::span); +WTF_EXPORT_PRIVATE bool equal(const StringImpl*, std::span); +inline bool equal(const StringImpl* a, const char* b) { return equal(a, byteCast(unsafeSpan(b))); } ALWAYS_INLINE bool equal(const StringImpl* a, ASCIILiteral b) { return equal(a, b.span8()); } -inline bool equal(const StringImpl* a, std::span b) { return equal(a, byteCast(b)); } -inline bool equal(const LChar* a, StringImpl* b) { return equal(b, a); } -inline bool equal(const char* a, StringImpl* b) { return equal(b, byteCast(a)); } +inline bool equal(const StringImpl* a, std::span b) { return equal(a, byteCast(b)); } +inline bool equal(const Latin1Character* a, StringImpl* b) { return equal(b, a); } +inline bool equal(const char* a, StringImpl* b) { return equal(b, byteCast(unsafeSpan(a))); } WTF_EXPORT_PRIVATE bool equal(const StringImpl& a, const StringImpl& b); WTF_EXPORT_PRIVATE bool equalIgnoringNullity(StringImpl*, StringImpl*); -WTF_EXPORT_PRIVATE bool equalIgnoringNullity(std::span, StringImpl*); +WTF_EXPORT_PRIVATE bool equalIgnoringNullity(std::span, StringImpl*); bool equalIgnoringASCIICase(const StringImpl&, const StringImpl&); WTF_EXPORT_PRIVATE bool equalIgnoringASCIICase(const StringImpl*, const StringImpl*); @@ -647,22 +647,22 @@ size_t find(std::span, CodeUnitMatchFunction&&, size_t start = 0 template size_t reverseFindLineTerminator(std::span, size_t start = StringImpl::MaxLength); template size_t reverseFind(std::span, CharacterType matchCharacter, size_t start = StringImpl::MaxLength); -size_t reverseFind(std::span, LChar matchCharacter, size_t start = StringImpl::MaxLength); -size_t reverseFind(std::span, UChar matchCharacter, size_t start = StringImpl::MaxLength); +size_t reverseFind(std::span, Latin1Character matchCharacter, size_t start = StringImpl::MaxLength); +size_t reverseFind(std::span, char16_t matchCharacter, size_t start = StringImpl::MaxLength); -template bool equalIgnoringNullity(const Vector&, StringImpl*); +template bool equalIgnoringNullity(const Vector&, StringImpl*); template int codePointCompare(std::span, std::span); int codePointCompare(const StringImpl*, const StringImpl*); -bool isUnicodeWhitespace(UChar); +bool isUnicodeWhitespace(char16_t); // Deprecated as this excludes U+0085 and U+00A0 which are part of Unicode's White_Space definition: // https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt -bool deprecatedIsSpaceOrNewline(UChar); +bool deprecatedIsSpaceOrNewline(char16_t); // Inverse of deprecatedIsSpaceOrNewline for predicates -bool deprecatedIsNotSpaceOrNewline(UChar); +bool deprecatedIsNotSpaceOrNewline(char16_t); // StringHash is the default hash for StringImpl* and RefPtr template struct DefaultHash; @@ -676,22 +676,22 @@ template<> struct DefaultHash>; return &impl; \ }()) -template<> ALWAYS_INLINE Ref StringImpl::constructInternal(StringImpl& string, unsigned length) +template<> ALWAYS_INLINE Ref StringImpl::constructInternal(StringImpl& string, unsigned length) { return adoptRef(*new (NotNull, &string) StringImpl { length, Force8BitConstructor }); } -template<> ALWAYS_INLINE Ref StringImpl::constructInternal(StringImpl& string, unsigned length) +template<> ALWAYS_INLINE Ref StringImpl::constructInternal(StringImpl& string, unsigned length) { return adoptRef(*new (NotNull, &string) StringImpl { length }); } -template<> ALWAYS_INLINE std::span StringImpl::span() const +template<> ALWAYS_INLINE std::span StringImpl::span() const { return span8(); } -template<> ALWAYS_INLINE std::span StringImpl::span() const +template<> ALWAYS_INLINE std::span StringImpl::span() const { return span16(); } @@ -735,19 +735,19 @@ template inline size_t reverseFind(std::span characters, LChar matchCharacter, size_t start) +ALWAYS_INLINE size_t reverseFind(std::span characters, Latin1Character matchCharacter, size_t start) { - return reverseFind(characters, static_cast(matchCharacter), start); + return reverseFind(characters, static_cast(matchCharacter), start); } -inline size_t reverseFind(std::span characters, UChar matchCharacter, size_t start) +inline size_t reverseFind(std::span characters, char16_t matchCharacter, size_t start) { if (!isLatin1(matchCharacter)) return notFound; - return reverseFind(characters, static_cast(matchCharacter), start); + return reverseFind(characters, static_cast(matchCharacter), start); } -inline size_t StringImpl::find(LChar character, size_t start) +inline size_t StringImpl::find(Latin1Character character, size_t start) { if (is8Bit()) return WTF::find(span8(), character, start); @@ -756,17 +756,17 @@ inline size_t StringImpl::find(LChar character, size_t start) ALWAYS_INLINE size_t StringImpl::find(char character, size_t start) { - return find(byteCast(character), start); + return find(byteCast(character), start); } -inline size_t StringImpl::find(UChar character, size_t start) +inline size_t StringImpl::find(char16_t character, size_t start) { if (is8Bit()) return WTF::find(span8(), character, start); return WTF::find(span16(), character, start); } -template>*> +template>*> size_t StringImpl::find(CodeUnitMatchFunction matchFunction, size_t start) { if (is8Bit()) @@ -774,7 +774,7 @@ size_t StringImpl::find(CodeUnitMatchFunction matchFunction, size_t start) return WTF::find(span16(), matchFunction, start); } -template inline bool equalIgnoringNullity(const Vector& a, StringImpl* b) +template inline bool equalIgnoringNullity(const Vector& a, StringImpl* b) { return equalIgnoringNullity(a.data(), a.size(), b); } @@ -820,25 +820,25 @@ inline int codePointCompare(const StringImpl* string1, const StringImpl* string2 return codePointCompare(string1->span16(), string2->span16()); } -// FIXME: For LChar, isUnicodeCompatibleASCIIWhitespace(character) || character == 0x0085 || character == noBreakSpace would be enough -inline bool isUnicodeWhitespace(UChar character) +// FIXME: For Latin1Character, isUnicodeCompatibleASCIIWhitespace(character) || character == 0x0085 || character == noBreakSpace would be enough +inline bool isUnicodeWhitespace(char16_t character) { return isASCII(character) ? isUnicodeCompatibleASCIIWhitespace(character) : u_isUWhiteSpace(character); } -inline bool deprecatedIsSpaceOrNewline(UChar character) +inline bool deprecatedIsSpaceOrNewline(char16_t character) { // Use isUnicodeCompatibleASCIIWhitespace() for all Latin-1 characters, which is incorrect as it // excludes U+0085 and U+00A0. return isLatin1(character) ? isUnicodeCompatibleASCIIWhitespace(character) : u_charDirection(character) == U_WHITE_SPACE_NEUTRAL; } -inline bool deprecatedIsNotSpaceOrNewline(UChar character) +inline bool deprecatedIsNotSpaceOrNewline(char16_t character) { return !deprecatedIsSpaceOrNewline(character); } -inline StringImplShape::StringImplShape(unsigned refCount, std::span data, unsigned hashAndFlags) +inline StringImplShape::StringImplShape(unsigned refCount, std::span data, unsigned hashAndFlags) : m_refCount(refCount) , m_length(data.size()) , m_data8(data.data()) @@ -847,7 +847,7 @@ inline StringImplShape::StringImplShape(unsigned refCount, std::span data, unsigned hashAndFlags) +inline StringImplShape::StringImplShape(unsigned refCount, std::span data, unsigned hashAndFlags) : m_refCount(refCount) , m_length(data.size()) , m_data16(data.data()) @@ -899,13 +899,13 @@ inline bool StringImpl::containsOnlyLatin1() const if (is8Bit()) return true; auto characters = span16(); - UChar mergedCharacterBits = 0; + char16_t mergedCharacterBits = 0; for (auto character : characters) mergedCharacterBits |= character; return isLatin1(mergedCharacterBits); } -template inline bool containsOnly(std::span characters) +template inline bool containsOnly(std::span characters) { for (auto character : characters) { if (!isSpecialCharacter(character)) @@ -914,7 +914,7 @@ template inline bool StringImpl::containsOnly() const +template inline bool StringImpl::containsOnly() const { if (is8Bit()) return WTF::containsOnly(span8()); @@ -922,7 +922,7 @@ template inline bool StringImpl::containsOnly() } inline StringImpl::StringImpl(unsigned length, Force8Bit) - : StringImplShape(s_refCountIncrement, { tailPointer(), length }, s_hashFlag8BitBuffer | StringNormal | BufferInternal) + : StringImplShape(s_refCountIncrement, { tailPointer(), length }, s_hashFlag8BitBuffer | StringNormal | BufferInternal) { ASSERT(m_data8); ASSERT(m_length); @@ -931,7 +931,7 @@ inline StringImpl::StringImpl(unsigned length, Force8Bit) } inline StringImpl::StringImpl(unsigned length) - : StringImplShape(s_refCountIncrement, { tailPointer(), length }, s_hashZeroValue | StringNormal | BufferInternal) + : StringImplShape(s_refCountIncrement, { tailPointer(), length }, s_hashZeroValue | StringNormal | BufferInternal) { ASSERT(m_data16); ASSERT(m_length); @@ -940,13 +940,13 @@ inline StringImpl::StringImpl(unsigned length) } template -inline StringImpl::StringImpl(MallocPtr characters, unsigned length) - : StringImplShape(s_refCountIncrement, { static_cast(nullptr), length }, s_hashFlag8BitBuffer | StringNormal | BufferOwned) +inline StringImpl::StringImpl(MallocPtr characters, unsigned length) + : StringImplShape(s_refCountIncrement, { static_cast(nullptr), length }, s_hashFlag8BitBuffer | StringNormal | BufferOwned) { if constexpr (std::is_same_v) m_data8 = characters.leakPtr(); else { - auto data8 = static_cast(StringImplMalloc::malloc(length * sizeof(LChar))); + auto data8 = static_cast(StringImplMalloc::malloc(length * sizeof(Latin1Character))); copyCharacters(data8, { characters.get(), length }); m_data8 = data8; } @@ -958,13 +958,13 @@ inline StringImpl::StringImpl(MallocPtr characters, unsigned leng } template -inline StringImpl::StringImpl(MallocSpan characters) - : StringImplShape(s_refCountIncrement, { static_cast(nullptr), characters.span().size() }, s_hashFlag8BitBuffer | StringNormal | BufferOwned) +inline StringImpl::StringImpl(MallocSpan characters) + : StringImplShape(s_refCountIncrement, { static_cast(nullptr), characters.span().size() }, s_hashFlag8BitBuffer | StringNormal | BufferOwned) { if constexpr (std::is_same_v) m_data8 = characters.leakSpan().data(); else { - auto* data8 = static_cast(StringImplMalloc::malloc(characters.sizeInBytes())); + auto* data8 = static_cast(StringImplMalloc::malloc(characters.sizeInBytes())); copyCharacters(data8, characters.span()); m_data8 = data8; } @@ -975,7 +975,7 @@ inline StringImpl::StringImpl(MallocSpan characters) STRING_STATS_ADD_8BIT_STRING(m_length); } -inline StringImpl::StringImpl(std::span characters, ConstructWithoutCopyingTag) +inline StringImpl::StringImpl(std::span characters, ConstructWithoutCopyingTag) : StringImplShape(s_refCountIncrement, characters, s_hashZeroValue | StringNormal | BufferInternal) { ASSERT(m_data16); @@ -984,7 +984,7 @@ inline StringImpl::StringImpl(std::span characters, ConstructWithou STRING_STATS_ADD_16BIT_STRING(m_length); } -inline StringImpl::StringImpl(std::span characters, ConstructWithoutCopyingTag) +inline StringImpl::StringImpl(std::span characters, ConstructWithoutCopyingTag) : StringImplShape(s_refCountIncrement, characters, s_hashFlag8BitBuffer | StringNormal | BufferInternal) { ASSERT(m_data8); @@ -994,13 +994,13 @@ inline StringImpl::StringImpl(std::span characters, ConstructWithou } template -inline StringImpl::StringImpl(MallocPtr characters, unsigned length) - : StringImplShape(s_refCountIncrement, { static_cast(nullptr), length }, s_hashZeroValue | StringNormal | BufferOwned) +inline StringImpl::StringImpl(MallocPtr characters, unsigned length) + : StringImplShape(s_refCountIncrement, { static_cast(nullptr), length }, s_hashZeroValue | StringNormal | BufferOwned) { if constexpr (std::is_same_v) m_data16 = characters.leakPtr(); else { - auto data16 = static_cast(StringImplMalloc::malloc(length * sizeof(UChar))); + auto data16 = static_cast(StringImplMalloc::malloc(length * sizeof(char16_t))); copyCharacters(data16, { characters.get(), length }); m_data16 = data16; } @@ -1012,13 +1012,13 @@ inline StringImpl::StringImpl(MallocPtr characters, unsigned leng } template -inline StringImpl::StringImpl(MallocSpan characters) - : StringImplShape(s_refCountIncrement, { static_cast(nullptr), characters.span().size() }, s_hashZeroValue | StringNormal | BufferOwned) +inline StringImpl::StringImpl(MallocSpan characters) + : StringImplShape(s_refCountIncrement, { static_cast(nullptr), characters.span().size() }, s_hashZeroValue | StringNormal | BufferOwned) { if constexpr (std::is_same_v) m_data16 = characters.leakSpan().data(); else { - auto* data16 = static_cast(StringImplMalloc::malloc(characters.sizeInBytes())); + auto* data16 = static_cast(StringImplMalloc::malloc(characters.sizeInBytes())); copyCharacters(data16, characters.span()); m_data16 = data16; } @@ -1029,7 +1029,7 @@ inline StringImpl::StringImpl(MallocSpan characters) STRING_STATS_ADD_16BIT_STRING(m_length); } -inline StringImpl::StringImpl(std::span characters, Ref&& base) +inline StringImpl::StringImpl(std::span characters, Ref&& base) : StringImplShape(s_refCountIncrement, characters, s_hashFlag8BitBuffer | StringNormal | BufferSubstring) { ASSERT(is8Bit()); @@ -1042,7 +1042,7 @@ inline StringImpl::StringImpl(std::span characters, Ref STRING_STATS_ADD_8BIT_STRING2(m_length, true); } -inline StringImpl::StringImpl(std::span characters, Ref&& base) +inline StringImpl::StringImpl(std::span characters, Ref&& base) : StringImplShape(s_refCountIncrement, characters, s_hashZeroValue | StringNormal | BufferSubstring) { ASSERT(!is8Bit()); @@ -1065,10 +1065,10 @@ ALWAYS_INLINE Ref StringImpl::createSubstringSharingImpl(StringImpl& // Copying the thing would save more memory sometimes, largely due to the size of pointer. size_t substringSize = allocationSize(1); if (rep.is8Bit()) { - if (substringSize >= allocationSize(length)) + if (substringSize >= allocationSize(length)) return create(rep.span8().subspan(offset, length)); } else { - if (substringSize >= allocationSize(length)) + if (substringSize >= allocationSize(length)) return create(rep.span16().subspan(offset, length)); } @@ -1229,13 +1229,13 @@ inline void StringImpl::deref() m_refCount = tempRefCount; } -inline UChar StringImpl::at(unsigned i) const +inline char16_t StringImpl::at(unsigned i) const { RELEASE_ASSERT(i < m_length); return is8Bit() ? m_data8[i] : m_data16[i]; } -inline StringImpl::StringImpl(CreateSymbolTag, std::span characters) +inline StringImpl::StringImpl(CreateSymbolTag, std::span characters) : StringImplShape(s_refCountIncrement, characters, s_hashFlag8BitBuffer | StringSymbol | BufferSubstring) { ASSERT(is8Bit()); @@ -1243,7 +1243,7 @@ inline StringImpl::StringImpl(CreateSymbolTag, std::span characters STRING_STATS_ADD_8BIT_STRING2(m_length, true); } -inline StringImpl::StringImpl(CreateSymbolTag, std::span characters) +inline StringImpl::StringImpl(CreateSymbolTag, std::span characters) : StringImplShape(s_refCountIncrement, characters, s_hashZeroValue | StringSymbol | BufferSubstring) { ASSERT(!is8Bit()); @@ -1282,8 +1282,8 @@ inline bool StringImpl::requiresCopy() const return true; if (is8Bit()) - return m_data8 == tailPointer(); - return m_data16 == tailPointer(); + return m_data8 == tailPointer(); + return m_data16 == tailPointer(); } template inline const T* StringImpl::tailPointer() const @@ -1405,23 +1405,23 @@ inline Ref StringImpl::removeCharacters(const Predicate& findMatch) return removeCharactersImpl(span16(), findMatch); } -inline Ref StringImpl::createByReplacingInCharacters(std::span characters, UChar target, UChar replacement, size_t indexOfFirstTargetCharacter) +inline Ref StringImpl::createByReplacingInCharacters(std::span characters, char16_t target, char16_t replacement, size_t indexOfFirstTargetCharacter) { ASSERT(indexOfFirstTargetCharacter < characters.size()); if (isLatin1(replacement)) { - std::span data; - LChar oldChar = target; - LChar newChar = replacement; + std::span data; + Latin1Character oldChar = target; + Latin1Character newChar = replacement; auto newImpl = createUninitializedInternalNonEmpty(characters.size(), data); memcpySpan(data, characters.first(indexOfFirstTargetCharacter)); for (size_t i = indexOfFirstTargetCharacter; i != characters.size(); ++i) { - LChar character = characters[i]; + Latin1Character character = characters[i]; data[i] = character == oldChar ? newChar : character; } return newImpl; } - std::span data; + std::span data; auto newImpl = createUninitializedInternalNonEmpty(characters.size(), data); size_t i = 0; for (auto character : characters) @@ -1429,14 +1429,14 @@ inline Ref StringImpl::createByReplacingInCharacters(std::span StringImpl::createByReplacingInCharacters(std::span characters, UChar target, UChar replacement, size_t indexOfFirstTargetCharacter) +inline Ref StringImpl::createByReplacingInCharacters(std::span characters, char16_t target, char16_t replacement, size_t indexOfFirstTargetCharacter) { ASSERT(indexOfFirstTargetCharacter < characters.size()); - std::span data; + std::span data; auto newImpl = createUninitializedInternalNonEmpty(characters.size(), data); copyCharacters(data.data(), characters.first(indexOfFirstTargetCharacter)); for (size_t i = indexOfFirstTargetCharacter; i != characters.size(); ++i) { - UChar character = characters[i]; + char16_t character = characters[i]; data[i] = character == target ? replacement : character; } return newImpl; @@ -1457,13 +1457,13 @@ static inline std::span nonNullEmptyUTF8Span() } template -inline Expected>, UTF8ConversionError> StringImpl::tryGetUTF8ForCharacters(const Func& function, std::span characters) +inline Expected>, UTF8ConversionError> StringImpl::tryGetUTF8ForCharacters(NOESCAPE const Func& function, std::span characters) { if (characters.empty()) return function(nonNullEmptyUTF8Span()); // Allocate a buffer big enough to hold all the characters - // (an individual LChar can only expand to 2 UTF-8 bytes). + // (an individual Latin1Character can only expand to 2 UTF-8 bytes). // Optimization ideas, if we find this function is hot: // * We could speculatively create a CStringBuffer to contain 'length' // characters, and resize if necessary (i.e. if the buffer contains @@ -1495,7 +1495,7 @@ inline Expected>, UTF8Conver } template -inline Expected>, UTF8ConversionError> StringImpl::tryGetUTF8ForCharacters(const Func& function, std::span characters, ConversionMode mode) +inline Expected>, UTF8ConversionError> StringImpl::tryGetUTF8ForCharacters(const Func& function, std::span characters, ConversionMode mode) { if (characters.empty()) return function(nonNullEmptyUTF8Span()); diff --git a/Source/WTF/wtf/text/StringToIntegerConversion.h b/Source/WTF/wtf/text/StringToIntegerConversion.h index bc59617ed838f..3ca6e78fe8448 100644 --- a/Source/WTF/wtf/text/StringToIntegerConversion.h +++ b/Source/WTF/wtf/text/StringToIntegerConversion.h @@ -26,36 +26,39 @@ #pragma once #include +#include #include namespace WTF { -// The parseInteger function template allows leading and trailing spaces as defined by isUnicodeCompatibleASCIIWhitespace, and, after the leading spaces, allows a single leading "+". +// The parseInteger function template may allow leading and trailing spaces as defined by isUnicodeCompatibleASCIIWhitespace, and, after the leading spaces, allows a single leading "+". // The parseIntegerAllowingTrailingJunk function template is like parseInteger, but allows any characters after the integer. // FIXME: Should we add a version that does not allow "+"? // FIXME: Should we add a version that allows other definitions of spaces, like isASCIIWhitespace or isASCIIWhitespaceWithoutFF? -// FIXME: Should we add a version that does not allow leading and trailing spaces? -template std::optional parseInteger(StringView, uint8_t base = 10); +enum class ParseIntegerWhitespacePolicy : bool { Disallow, Allow }; + +template std::optional parseInteger(StringView, uint8_t base = 10, ParseIntegerWhitespacePolicy = ParseIntegerWhitespacePolicy::Allow); template std::optional parseIntegerAllowingTrailingJunk(StringView, uint8_t base = 10); +template std::optional parseInteger(std::span, uint8_t base = 10, ParseIntegerWhitespacePolicy = ParseIntegerWhitespacePolicy::Allow); +template std::optional parseIntegerAllowingTrailingJunk(std::span, uint8_t base = 10); -enum class TrailingJunkPolicy { Disallow, Allow }; +enum class TrailingJunkPolicy : bool { Disallow, Allow }; -template std::optional parseInteger(std::span data, uint8_t base, TrailingJunkPolicy policy) +template std::optional parseInteger(std::span data, uint8_t base, TrailingJunkPolicy policy, ParseIntegerWhitespacePolicy whitespacePolicy = ParseIntegerWhitespacePolicy::Allow) { if (!data.data()) return std::nullopt; - while (!data.empty() && isUnicodeCompatibleASCIIWhitespace(data.front())) - data = data.subspan(1); + if (whitespacePolicy == ParseIntegerWhitespacePolicy::Allow) + skipWhile(data); bool isNegative = false; - if (std::is_signed_v && !data.empty() && data.front() == '-') { - data = data.subspan(1); + if (std::is_signed_v && skipExactly(data, '-')) isNegative = true; - } else if (!data.empty() && data.front() == '+') - data = data.subspan(1); + else + skipExactly(data, '+'); auto isCharacterAllowedInBase = [] (auto character, auto base) { if (isASCIIDigit(character)) @@ -68,8 +71,8 @@ template std::optional value; do { - IntegralType digitValue = isASCIIDigit(data.front()) ? data.front() - '0' : toASCIILowerUnchecked(data.front()) - 'a' + 10; - data = data.subspan(1); + auto c = consume(data); + IntegralType digitValue = isASCIIDigit(c) ? c - '0' : toASCIILowerUnchecked(c) - 'a' + 10; value *= static_cast(base); if (isNegative) value -= digitValue; @@ -77,12 +80,12 @@ template std::optional(data); if (!data.empty()) return std::nullopt; } @@ -90,18 +93,32 @@ template std::optional std::optional parseInteger(StringView string, uint8_t base) +template +std::optional parseInteger(std::span data, uint8_t base, ParseIntegerWhitespacePolicy whitespacePolicy) +{ + return parseInteger(data, base, TrailingJunkPolicy::Disallow, whitespacePolicy); +} + +template +std::optional parseIntegerAllowingTrailingJunk(std::span data, uint8_t base) +{ + return parseInteger(data, base, TrailingJunkPolicy::Allow); +} + +template +std::optional parseInteger(StringView string, uint8_t base, ParseIntegerWhitespacePolicy whitespacePolicy) { if (string.is8Bit()) - return parseInteger(string.span8(), base, TrailingJunkPolicy::Disallow); - return parseInteger(string.span16(), base, TrailingJunkPolicy::Disallow); + return parseInteger(string.span8(), base, whitespacePolicy); + return parseInteger(string.span16(), base, whitespacePolicy); } -template std::optional parseIntegerAllowingTrailingJunk(StringView string, uint8_t base) +template +std::optional parseIntegerAllowingTrailingJunk(StringView string, uint8_t base) { if (string.is8Bit()) - return parseInteger(string.span8(), base, TrailingJunkPolicy::Allow); - return parseInteger(string.span16(), base, TrailingJunkPolicy::Allow); + return parseIntegerAllowingTrailingJunk(string.span8(), base); + return parseIntegerAllowingTrailingJunk(string.span16(), base); } } diff --git a/Source/WTF/wtf/text/StringView.cpp b/Source/WTF/wtf/text/StringView.cpp index 746976ce5a06b..56f72e71851a3 100644 --- a/Source/WTF/wtf/text/StringView.cpp +++ b/Source/WTF/wtf/text/StringView.cpp @@ -62,7 +62,7 @@ size_t StringView::findIgnoringASCIICase(StringView matchString, unsigned startO return ::WTF::findIgnoringASCIICase(*this, matchString, startOffset); } -bool StringView::startsWith(UChar character) const +bool StringView::startsWith(char16_t character) const { return m_length && (*this)[0] == character; } @@ -77,7 +77,7 @@ bool StringView::startsWithIgnoringASCIICase(StringView prefix) const return ::WTF::startsWithIgnoringASCIICase(*this, prefix); } -bool StringView::endsWith(UChar character) const +bool StringView::endsWith(char16_t character) const { return m_length && (*this)[m_length - 1] == character; } @@ -138,7 +138,7 @@ size_t StringView::find(AdaptiveStringSearcherTables& tables, StringView matchSt return searchString(tables, span16(), matchString.span16(), start); } -size_t StringView::find(std::span match, unsigned start) const +size_t StringView::find(std::span match, unsigned start) const { ASSERT(!match.empty()); auto length = this->length(); @@ -154,7 +154,7 @@ size_t StringView::find(std::span match, unsigned start) const return findInner(span16().subspan(start), match, start); } -size_t StringView::reverseFind(std::span match, unsigned start) const +size_t StringView::reverseFind(std::span match, unsigned start) const { ASSERT(!match.empty()); if (match.size() > length()) @@ -317,21 +317,21 @@ AtomString StringView::convertToASCIILowercaseAtom() const template void getCharactersWithASCIICaseInternal(StringView::CaseConvertType type, DestinationCharacterType* destination, std::span source) { - static_assert(std::is_same::value || std::is_same::value); - static_assert(std::is_same::value || std::is_same::value); + static_assert(std::is_same::value || std::is_same::value); + static_assert(std::is_same::value || std::is_same::value); static_assert(sizeof(DestinationCharacterType) >= sizeof(SourceCharacterType)); auto caseConvert = (type == StringView::CaseConvertType::Lower) ? toASCIILower : toASCIIUpper; for (auto character : source) *destination++ = caseConvert(character); } -void StringView::getCharactersWithASCIICase(CaseConvertType type, LChar* destination) const +void StringView::getCharactersWithASCIICase(CaseConvertType type, Latin1Character* destination) const { ASSERT(is8Bit()); getCharactersWithASCIICaseInternal(type, destination, span8()); } -void StringView::getCharactersWithASCIICase(CaseConvertType type, UChar* destination) const +void StringView::getCharactersWithASCIICase(CaseConvertType type, char16_t* destination) const { if (is8Bit()) { getCharactersWithASCIICaseInternal(type, destination, span8()); @@ -343,21 +343,21 @@ void StringView::getCharactersWithASCIICase(CaseConvertType type, UChar* destina template void getCharactersWithASCIICaseInternal(StringView::CaseConvertType type, std::span destination, std::span source) { - static_assert(std::is_same::value || std::is_same::value); - static_assert(std::is_same::value || std::is_same::value); + static_assert(std::is_same::value || std::is_same::value); + static_assert(std::is_same::value || std::is_same::value); static_assert(sizeof(DestinationCharacterType) >= sizeof(SourceCharacterType)); auto caseConvert = (type == StringView::CaseConvertType::Lower) ? toASCIILower : toASCIIUpper; for (auto [destinationCharacter, character] : zippedRange(destination, source)) destinationCharacter = caseConvert(character); } -void StringView::getCharactersWithASCIICase(CaseConvertType type, std::span destination) const +void StringView::getCharactersWithASCIICase(CaseConvertType type, std::span destination) const { ASSERT(is8Bit()); getCharactersWithASCIICaseInternal(type, destination, span8()); } -void StringView::getCharactersWithASCIICase(CaseConvertType type, std::span destination) const +void StringView::getCharactersWithASCIICase(CaseConvertType type, std::span destination) const { if (is8Bit()) { getCharactersWithASCIICaseInternal(type, destination, span8()); @@ -385,7 +385,7 @@ StringViewWithUnderlyingString normalizedNFC(StringView string) unsigned normalizedLength = unorm2_normalize(normalizer, span.data(), span.size(), nullptr, 0, &status); ASSERT(needsToGrowToProduceBuffer(status)); - UChar* characters; + char16_t* characters; String result = String::createUninitialized(normalizedLength, characters); status = U_ZERO_ERROR; @@ -440,7 +440,7 @@ size_t StringView::reverseFind(StringView matchString, unsigned start) const return reverseFindInner(span16(), matchString.span16(), start); } -String makeStringByReplacingAll(StringView string, UChar target, UChar replacement) +String makeStringByReplacingAll(StringView string, char16_t target, char16_t replacement) { if (string.is8Bit()) { if (!isLatin1(target)) { @@ -511,8 +511,8 @@ template static String makeStringBySimplifyingNewLinesSl String makeStringBySimplifyingNewLinesSlowCase(const String& string, unsigned firstCarriageReturn) { if (string.is8Bit()) - return makeStringBySimplifyingNewLinesSlowCase(string, firstCarriageReturn); - return makeStringBySimplifyingNewLinesSlowCase(string, firstCarriageReturn); + return makeStringBySimplifyingNewLinesSlowCase(string, firstCarriageReturn); + return makeStringBySimplifyingNewLinesSlowCase(string, firstCarriageReturn); } #if CHECK_STRINGVIEW_LIFETIME diff --git a/Source/WTF/wtf/text/StringView.h b/Source/WTF/wtf/text/StringView.h index f64a10cafb621..4a48dc3d61433 100644 --- a/Source/WTF/wtf/text/StringView.h +++ b/Source/WTF/wtf/text/StringView.h @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include @@ -67,9 +67,9 @@ class StringView final { StringView(const String&); StringView(const StringImpl&); StringView(const StringImpl*); - StringView(std::span); - StringView(std::span); - StringView(std::span); // FIXME: Consider dropping this overload. Callers should pass LChars/UChars instead. + StringView(std::span); + StringView(std::span); + StringView(std::span); // FIXME: Consider dropping this overload. Callers should pass Latin1Characters/char16_ts instead. StringView(const void*, unsigned length, bool is8bit); StringView(ASCIILiteral); @@ -81,8 +81,8 @@ class StringView final { explicit operator bool() const; bool isNull() const; - UChar characterAt(unsigned index) const; - UChar operator[](unsigned index) const; + char16_t characterAt(unsigned index) const; + char16_t operator[](unsigned index) const; class CodeUnits; CodeUnits codeUnits() const; @@ -94,10 +94,10 @@ class StringView final { GraphemeClusters graphemeClusters() const; bool is8Bit() const; - const void* rawCharacters() const { return m_characters; } - std::span span8() const; - std::span span16() const; - template std::span span() const; + const void* rawCharacters() const LIFETIME_BOUND { return m_characters; } + std::span span8() const LIFETIME_BOUND; + std::span span16() const LIFETIME_BOUND; + template std::span span() const LIFETIME_BOUND; unsigned hash() const; @@ -141,10 +141,10 @@ class StringView final { template void getCharacters16(std::span) const; enum class CaseConvertType { Upper, Lower }; - WTF_EXPORT_PRIVATE void getCharactersWithASCIICase(CaseConvertType, LChar*) const; - WTF_EXPORT_PRIVATE void getCharactersWithASCIICase(CaseConvertType, UChar*) const; - WTF_EXPORT_PRIVATE void getCharactersWithASCIICase(CaseConvertType, std::span) const; - WTF_EXPORT_PRIVATE void getCharactersWithASCIICase(CaseConvertType, std::span) const; + WTF_EXPORT_PRIVATE void getCharactersWithASCIICase(CaseConvertType, Latin1Character*) const; + WTF_EXPORT_PRIVATE void getCharactersWithASCIICase(CaseConvertType, char16_t*) const; + WTF_EXPORT_PRIVATE void getCharactersWithASCIICase(CaseConvertType, std::span) const; + WTF_EXPORT_PRIVATE void getCharactersWithASCIICase(CaseConvertType, std::span) const; StringView substring(unsigned start, unsigned length = std::numeric_limits::max()) const; StringView left(unsigned length) const { return substring(0, length); } @@ -154,19 +154,19 @@ class StringView final { StringView trim(const MatchedCharacterPredicate&) const; class SplitResult; - SplitResult split(UChar) const; - SplitResult splitAllowingEmptyEntries(UChar) const; + SplitResult split(char16_t) const; + SplitResult splitAllowingEmptyEntries(char16_t) const; - size_t find(UChar, unsigned start = 0) const; - size_t find(LChar, unsigned start = 0) const; - ALWAYS_INLINE size_t find(char c, unsigned start = 0) const { return find(byteCast(c), start); } - template>* = nullptr> + size_t find(char16_t, unsigned start = 0) const; + size_t find(Latin1Character, unsigned start = 0) const; + ALWAYS_INLINE size_t find(char c, unsigned start = 0) const { return find(byteCast(c), start); } + template>* = nullptr> size_t find(CodeUnitMatchFunction&&, unsigned start = 0) const; ALWAYS_INLINE size_t find(ASCIILiteral literal, unsigned start = 0) const { return find(literal.span8(), start); } WTF_EXPORT_PRIVATE size_t find(StringView, unsigned start = 0) const; WTF_EXPORT_PRIVATE size_t find(AdaptiveStringSearcherTables&, StringView, unsigned start = 0) const; - size_t reverseFind(UChar, unsigned index = std::numeric_limits::max()) const; + size_t reverseFind(char16_t, unsigned index = std::numeric_limits::max()) const; ALWAYS_INLINE size_t reverseFind(ASCIILiteral literal, unsigned start = std::numeric_limits::max()) const { return reverseFind(literal.span8(), start); } WTF_EXPORT_PRIVATE size_t reverseFind(StringView, unsigned start = std::numeric_limits::max()) const; @@ -177,8 +177,8 @@ class StringView final { WTF_EXPORT_PRIVATE String convertToASCIIUppercase() const; WTF_EXPORT_PRIVATE AtomString convertToASCIILowercaseAtom() const; - bool contains(UChar) const; - template>* = nullptr> + bool contains(char16_t) const; + template>* = nullptr> bool contains(CodeUnitMatchFunction&&) const; bool contains(ASCIILiteral literal) const { return find(literal) != notFound; } bool contains(StringView string) const { return find(string) != notFound; } @@ -186,13 +186,13 @@ class StringView final { WTF_EXPORT_PRIVATE bool containsIgnoringASCIICase(StringView) const; WTF_EXPORT_PRIVATE bool containsIgnoringASCIICase(StringView, unsigned start) const; - template bool containsOnly() const; + template bool containsOnly() const; - WTF_EXPORT_PRIVATE bool startsWith(UChar) const; + WTF_EXPORT_PRIVATE bool startsWith(char16_t) const; WTF_EXPORT_PRIVATE bool startsWith(StringView) const; WTF_EXPORT_PRIVATE bool startsWithIgnoringASCIICase(StringView) const; - WTF_EXPORT_PRIVATE bool endsWith(UChar) const; + WTF_EXPORT_PRIVATE bool endsWith(char16_t) const; WTF_EXPORT_PRIVATE bool endsWith(StringView) const; WTF_EXPORT_PRIVATE bool endsWithIgnoringASCIICase(StringView) const; @@ -211,18 +211,18 @@ class StringView final { // Clients should use StringView(ASCIILiteral) or StringView::fromLatin1() instead. explicit StringView(const char*); - UChar unsafeCharacterAt(unsigned index) const; + char16_t unsafeCharacterAt(unsigned index) const; friend bool equal(StringView, StringView); friend bool equal(StringView, StringView, unsigned length); friend WTF_EXPORT_PRIVATE bool equalRespectingNullity(StringView, StringView); friend size_t findCommon(StringView haystack, StringView needle, unsigned start); - void initialize(std::span); - void initialize(std::span); + void initialize(std::span); + void initialize(std::span); - WTF_EXPORT_PRIVATE size_t find(std::span match, unsigned start) const; - WTF_EXPORT_PRIVATE size_t reverseFind(std::span match, unsigned start) const; + WTF_EXPORT_PRIVATE size_t find(std::span match, unsigned start) const; + WTF_EXPORT_PRIVATE size_t reverseFind(std::span match, unsigned start) const; template StringView trim(std::span, const MatchedCharacterPredicate&) const; @@ -256,7 +256,7 @@ class StringView final { template void append(Vector&, StringView); bool equal(StringView, StringView); -bool equal(StringView, const LChar* b); +bool equal(StringView, std::span); bool equalIgnoringASCIICase(StringView, StringView); bool equalIgnoringASCIICase(StringView, ASCIILiteral); @@ -386,38 +386,38 @@ inline StringView& StringView::operator=(const StringView& other) #endif // CHECK_STRINGVIEW_LIFETIME -inline void StringView::initialize(std::span characters) +inline void StringView::initialize(std::span characters) { m_characters = characters.data(); m_length = characters.size(); m_is8Bit = true; } -inline void StringView::initialize(std::span characters) +inline void StringView::initialize(std::span characters) { m_characters = characters.data(); m_length = characters.size(); m_is8Bit = false; } -inline StringView::StringView(std::span characters) +inline StringView::StringView(std::span characters) { initialize(characters); } -inline StringView::StringView(std::span characters) +inline StringView::StringView(std::span characters) { initialize(characters); } inline StringView::StringView(const char* characters) + : StringView { unsafeSpan(characters) } { - initialize(WTF::span8(characters)); } inline StringView::StringView(std::span characters) { - initialize(byteCast(characters)); + initialize(byteCast(characters)); } inline StringView::StringView(const void* characters, unsigned length, bool is8bit) @@ -479,18 +479,18 @@ inline void StringView::clear() m_is8Bit = true; } -inline std::span StringView::span8() const +inline std::span StringView::span8() const { ASSERT(is8Bit()); ASSERT(underlyingStringIsValid()); - return { static_cast(m_characters), m_length }; + return { static_cast(m_characters), m_length }; } -inline std::span StringView::span16() const +inline std::span StringView::span16() const { ASSERT(!is8Bit() || isEmpty()); ASSERT(underlyingStringIsValid()); - return { static_cast(m_characters), m_length }; + return { static_cast(m_characters), m_length }; } inline unsigned StringView::hash() const @@ -500,12 +500,12 @@ inline unsigned StringView::hash() const return StringHasher::computeHashAndMaskTop8Bits(span16()); } -template<> ALWAYS_INLINE std::span StringView::span() const +template<> ALWAYS_INLINE std::span StringView::span() const { return span8(); } -template<> ALWAYS_INLINE std::span StringView::span() const +template<> ALWAYS_INLINE std::span StringView::span() const { return span16(); } @@ -522,14 +522,14 @@ class StringView::UpconvertedCharactersWithSize { WTF_MAKE_FAST_ALLOCATED; public: explicit UpconvertedCharactersWithSize(StringView); - operator const UChar*() const { return m_characters.data(); } - const UChar* get() const { return m_characters.data(); } - operator std::span() const { return m_characters; } - std::span span() const { return m_characters; } + operator const char16_t*() const { return m_characters.data(); } + const char16_t* get() const { return m_characters.data(); } + operator std::span() const { return m_characters; } + std::span span() const { return m_characters; } private: - Vector m_upconvertedCharacters; - std::span m_characters; + Vector m_upconvertedCharacters; + std::span m_characters; }; template @@ -585,14 +585,14 @@ inline StringView StringView::substring(unsigned start, unsigned length) const return result; } -inline UChar StringView::characterAt(unsigned index) const +inline char16_t StringView::characterAt(unsigned index) const { if (is8Bit()) return span8()[index]; return span16()[index]; } -inline UChar StringView::unsafeCharacterAt(unsigned index) const +inline char16_t StringView::unsafeCharacterAt(unsigned index) const { ASSERT(index < length()); if (is8Bit()) @@ -600,23 +600,23 @@ inline UChar StringView::unsafeCharacterAt(unsigned index) const return span16().data()[index]; } -inline UChar StringView::operator[](unsigned index) const +inline char16_t StringView::operator[](unsigned index) const { return characterAt(index); } -inline bool StringView::contains(UChar character) const +inline bool StringView::contains(char16_t character) const { return find(character) != notFound; } -template>*> +template>*> inline bool StringView::contains(CodeUnitMatchFunction&& function) const { return find(std::forward(function)) != notFound; } -template inline bool StringView::containsOnly() const +template inline bool StringView::containsOnly() const { if (is8Bit()) return WTF::containsOnly(span8()); @@ -713,21 +713,21 @@ inline String StringView::toStringWithoutCopying() const return StringImpl::createWithoutCopying(span16()); } -inline size_t StringView::find(UChar character, unsigned start) const +inline size_t StringView::find(char16_t character, unsigned start) const { if (is8Bit()) return WTF::find(span8(), character, start); return WTF::find(span16(), character, start); } -inline size_t StringView::find(LChar character, unsigned start) const +inline size_t StringView::find(Latin1Character character, unsigned start) const { if (is8Bit()) return WTF::find(span8(), character, start); return WTF::find(span16(), character, start); } -template>*> +template>*> inline size_t StringView::find(CodeUnitMatchFunction&& matchFunction, unsigned start) const { if (is8Bit()) @@ -735,7 +735,7 @@ inline size_t StringView::find(CodeUnitMatchFunction&& matchFunction, unsigned s return WTF::find(span16(), std::forward(matchFunction), start); } -inline size_t StringView::reverseFind(UChar character, unsigned start) const +inline size_t StringView::reverseFind(char16_t character, unsigned start) const { if (is8Bit()) return WTF::reverseFind(span8(), character, start); @@ -792,25 +792,24 @@ ALWAYS_INLINE bool equal(StringView a, StringView b) return equalCommon(a, b); } -inline bool equal(StringView a, const LChar* b) +inline bool equal(StringView a, std::span b) { - if (!b) + if (!b.data()) return !a.isEmpty(); if (a.isEmpty()) - return !b; + return !b.data(); - auto bSpan = span8(byteCast(b)); - if (a.length() != bSpan.size()) + if (a.length() != b.size()) return false; if (a.is8Bit()) - return equal(a.span8().data(), bSpan); - return equal(a.span16().data(), bSpan); + return equal(a.span8().data(), b); + return equal(a.span16().data(), b); } ALWAYS_INLINE bool equal(StringView a, ASCIILiteral b) { - return equal(a, b.span8().data()); + return equal(a, b.span8()); } inline bool equalIgnoringASCIICase(StringView a, StringView b) @@ -826,7 +825,7 @@ inline bool equalIgnoringASCIICase(StringView a, ASCIILiteral b) class StringView::SplitResult { WTF_MAKE_FAST_ALLOCATED; public: - SplitResult(StringView, UChar separator, bool allowEmptyEntries); + SplitResult(StringView, char16_t separator, bool allowEmptyEntries); class Iterator; Iterator begin() const; @@ -834,7 +833,7 @@ class StringView::SplitResult { private: StringView m_string; - UChar m_separator; + char16_t m_separator; bool m_allowEmptyEntries; }; @@ -954,7 +953,7 @@ class StringView::CodeUnits::Iterator { public: Iterator(StringView, unsigned index); - UChar operator*() const; + char16_t operator*() const; Iterator& operator++(); bool operator==(const Iterator&) const; @@ -1006,11 +1005,11 @@ inline StringView::CodePoints::Iterator::Iterator(StringView stringView, unsigne #endif { if (m_is8Bit) { - const LChar* begin = stringView.span8().data(); + const Latin1Character* begin = stringView.span8().data(); m_current = begin + index; m_end = begin + stringView.length(); } else { - const UChar* begin = stringView.span16().data(); + const char16_t* begin = stringView.span16().data(); m_current = begin + index; m_end = begin + stringView.length(); } @@ -1023,12 +1022,12 @@ inline auto StringView::CodePoints::Iterator::operator++() -> Iterator& #endif ASSERT(m_current < m_end); if (m_is8Bit) - m_current = static_cast(m_current) + 1; + m_current = static_cast(m_current) + 1; else { unsigned i = 0; - size_t length = static_cast(m_end) - static_cast(m_current); - U16_FWD_1(static_cast(m_current), i, length); - m_current = static_cast(m_current) + i; + size_t length = static_cast(m_end) - static_cast(m_current); + U16_FWD_1(static_cast(m_current), i, length); + m_current = static_cast(m_current) + i; } return *this; } @@ -1040,10 +1039,10 @@ inline char32_t StringView::CodePoints::Iterator::operator*() const #endif ASSERT(m_current < m_end); if (m_is8Bit) - return *static_cast(m_current); + return *static_cast(m_current); char32_t codePoint; - size_t length = static_cast(m_end) - static_cast(m_current); - U16_GET(static_cast(m_current), 0, 0, length, codePoint); + size_t length = static_cast(m_end) - static_cast(m_current); + U16_GET(static_cast(m_current), 0, 0, length, codePoint); return codePoint; } @@ -1084,7 +1083,7 @@ inline auto StringView::CodeUnits::Iterator::operator++() -> Iterator& return *this; } -inline UChar StringView::CodeUnits::Iterator::operator*() const +inline char16_t StringView::CodeUnits::Iterator::operator*() const { return m_stringView.unsafeCharacterAt(m_index); } @@ -1106,17 +1105,17 @@ inline auto StringView::CodeUnits::end() const -> Iterator return Iterator(m_stringView, m_stringView.length()); } -inline auto StringView::split(UChar separator) const -> SplitResult +inline auto StringView::split(char16_t separator) const -> SplitResult { return SplitResult { *this, separator, false }; } -inline auto StringView::splitAllowingEmptyEntries(UChar separator) const -> SplitResult +inline auto StringView::splitAllowingEmptyEntries(char16_t separator) const -> SplitResult { return SplitResult { *this, separator, true }; } -inline StringView::SplitResult::SplitResult(StringView stringView, UChar separator, bool allowEmptyEntries) +inline StringView::SplitResult::SplitResult(StringView stringView, char16_t separator, bool allowEmptyEntries) : m_string { stringView } , m_separator { separator } , m_allowEmptyEntries { allowEmptyEntries } @@ -1190,8 +1189,8 @@ template StringView StringView::trim(const MatchedCharacterPredicate& predicate) const { if (is8Bit()) - return trim(span8(), predicate); - return trim(span16(), predicate); + return trim(span8(), predicate); + return trim(span16(), predicate); } inline bool equalLettersIgnoringASCIICase(StringView string, ASCIILiteral literal) @@ -1229,7 +1228,7 @@ inline size_t findCommon(StringView haystack, StringView needle, unsigned start) unsigned needleLength = needle.length(); if (needleLength == 1) { - UChar firstCharacter = needle.unsafeCharacterAt(0); + char16_t firstCharacter = needle.unsafeCharacterAt(0); if (haystack.is8Bit()) return WTF::find(haystack.span8(), firstCharacter, start); return WTF::find(haystack.span16(), firstCharacter, start); @@ -1403,14 +1402,14 @@ inline String WARN_UNUSED_RETURN makeStringByReplacing(const String& string, uns return string; } -inline String WARN_UNUSED_RETURN makeStringByReplacingAll(const String& string, UChar target, StringView replacement) +inline String WARN_UNUSED_RETURN makeStringByReplacingAll(const String& string, char16_t target, StringView replacement) { if (auto* impl = string.impl()) return String { impl->replace(target, replacement) }; return string; } -WTF_EXPORT_PRIVATE String WARN_UNUSED_RETURN makeStringByReplacingAll(StringView, UChar target, UChar replacement); +WTF_EXPORT_PRIVATE String WARN_UNUSED_RETURN makeStringByReplacingAll(StringView, char16_t target, char16_t replacement); WTF_EXPORT_PRIVATE String WARN_UNUSED_RETURN makeStringBySimplifyingNewLinesSlowCase(const String&, unsigned firstCarriageReturnOffset); inline String WARN_UNUSED_RETURN makeStringBySimplifyingNewLines(const String& string) diff --git a/Source/WTF/wtf/text/SuperFastHash.h b/Source/WTF/wtf/text/SuperFastHash.h index 73edc24c80d44..c72da30dbbb1d 100644 --- a/Source/WTF/wtf/text/SuperFastHash.h +++ b/Source/WTF/wtf/text/SuperFastHash.h @@ -29,7 +29,7 @@ namespace WTF { // Paul Hsieh's SuperFastHash // http://www.azillionmonkeys.com/qed/hash.html -// LChar data is interpreted as Latin-1-encoded (zero-extended to 16 bits). +// Latin1Character data is interpreted as Latin-1-encoded (zero-extended to 16 bits). // NOTE: The hash computation here must stay in sync with the create_hash_table script in // JavaScriptCore and the CodeGeneratorJS.pm script in WebCore. diff --git a/Source/WTF/wtf/text/SymbolImpl.h b/Source/WTF/wtf/text/SymbolImpl.h index 828675b2d3b20..b821cef8549a9 100644 --- a/Source/WTF/wtf/text/SymbolImpl.h +++ b/Source/WTF/wtf/text/SymbolImpl.h @@ -74,8 +74,8 @@ class SUPPRESS_REFCOUNTED_WITHOUT_VIRTUAL_DESTRUCTOR SymbolImpl : public Uniqued friend class StringImpl; - inline SymbolImpl(std::span, Ref&&, Flags = s_flagDefault); - inline SymbolImpl(std::span, Ref&&, Flags = s_flagDefault); + inline SymbolImpl(std::span, Ref&&, Flags = s_flagDefault); + inline SymbolImpl(std::span, Ref&&, Flags = s_flagDefault); inline SymbolImpl(Flags = s_flagDefault); // The pointer to the owner string should be immediately following after the StringImpl layout, @@ -86,7 +86,7 @@ class SUPPRESS_REFCOUNTED_WITHOUT_VIRTUAL_DESTRUCTOR SymbolImpl : public Uniqued }; static_assert(sizeof(SymbolImpl) == sizeof(SymbolImpl::StaticSymbolImpl)); -inline SymbolImpl::SymbolImpl(std::span characters, Ref&& base, Flags flags) +inline SymbolImpl::SymbolImpl(std::span characters, Ref&& base, Flags flags) : UniquedStringImpl(CreateSymbol, characters) , m_owner(&base.leakRef()) , m_hashForSymbolShiftedWithFlagCount(nextHashForSymbol()) @@ -134,7 +134,7 @@ class PrivateSymbolImpl final : public SymbolImpl { WTF_EXPORT_PRIVATE static Ref create(StringImpl& rep); private: - PrivateSymbolImpl(std::span characters, Ref&& base) + PrivateSymbolImpl(std::span characters, Ref&& base) : SymbolImpl(characters, WTFMove(base), s_flagIsPrivate) { } @@ -157,7 +157,7 @@ class RegisteredSymbolImpl final : public SymbolImpl { static Ref create(StringImpl& rep, SymbolRegistry&); static Ref createPrivate(StringImpl& rep, SymbolRegistry&); - RegisteredSymbolImpl(std::span characters, Ref&& base, SymbolRegistry& registry, Flags flags = s_flagIsRegistered) + RegisteredSymbolImpl(std::span characters, Ref&& base, SymbolRegistry& registry, Flags flags = s_flagIsRegistered) : SymbolImpl(characters, WTFMove(base), flags) , m_symbolRegistry(®istry) { diff --git a/Source/WTF/wtf/text/TextStream.cpp b/Source/WTF/wtf/text/TextStream.cpp index ba792aa95dbb4..c3647c8eb778a 100644 --- a/Source/WTF/wtf/text/TextStream.cpp +++ b/Source/WTF/wtf/text/TextStream.cpp @@ -108,7 +108,7 @@ TextStream& TextStream::operator<<(double d) TextStream& TextStream::operator<<(const char* string) { - m_text.append(span(string)); + m_text.append(unsafeSpan(string)); return *this; } diff --git a/Source/WTF/wtf/text/UniquedStringImpl.h b/Source/WTF/wtf/text/UniquedStringImpl.h index b08b4666ea5f1..3a93933621c34 100644 --- a/Source/WTF/wtf/text/UniquedStringImpl.h +++ b/Source/WTF/wtf/text/UniquedStringImpl.h @@ -35,12 +35,12 @@ class SUPPRESS_REFCOUNTED_WITHOUT_VIRTUAL_DESTRUCTOR UniquedStringImpl : public private: UniquedStringImpl() = delete; protected: - inline UniquedStringImpl(CreateSymbolTag, std::span); - inline UniquedStringImpl(CreateSymbolTag, std::span); + inline UniquedStringImpl(CreateSymbolTag, std::span); + inline UniquedStringImpl(CreateSymbolTag, std::span); inline UniquedStringImpl(CreateSymbolTag); }; -inline UniquedStringImpl::UniquedStringImpl(CreateSymbolTag, std::span characters) +inline UniquedStringImpl::UniquedStringImpl(CreateSymbolTag, std::span characters) : StringImpl(CreateSymbol, characters) { } diff --git a/Source/WTF/wtf/text/WTFString.cpp b/Source/WTF/wtf/text/WTFString.cpp index 6f63dfd07be54..46e0443addc61 100644 --- a/Source/WTF/wtf/text/WTFString.cpp +++ b/Source/WTF/wtf/text/WTFString.cpp @@ -46,19 +46,26 @@ String::String(std::span characters) } // Construct a string with latin1 data. -String::String(std::span characters) +String::String(std::span characters) : m_impl(characters.data() ? RefPtr { StringImpl::create(characters) } : nullptr) { } +// Construct a string with UTF-8 data. +String::String(std::span characters) + : m_impl(StringImpl::create(characters)) +{ +} + +// Construct a string with Latin-1 data. String::String(std::span characters) - : m_impl(characters.data() ? RefPtr { StringImpl::create(byteCast(characters)) } : nullptr) + : m_impl(characters.data() ? RefPtr { StringImpl::create(byteCast(characters)) } : nullptr) { } // Construct a string with Latin-1 data, from a null-terminated source. String::String(const char* nullTerminatedString) - : m_impl(nullTerminatedString ? RefPtr { StringImpl::createFromCString(nullTerminatedString) } : nullptr) + : m_impl(nullTerminatedString ? RefPtr { StringImpl::create(byteCast(unsafeSpan(nullTerminatedString))) } : nullptr) { } @@ -392,9 +399,9 @@ CString String::ascii() const CString result = CString::newUninitialized(characters.size(), characterBuffer); for (auto character : characters) - *characterBuffer++ = character && (character < 0x20 || character > 0x7f) ? '?' : character; + *characterBuffer++ = character && (character < 0x20 || character > 0x7f) ? '?' : byteCast(character); - return result; + return result; } auto characters = span16(); @@ -447,7 +454,7 @@ CString String::utf8(ConversionMode mode) const String String::make8Bit(std::span source) { - LChar* destination; + Latin1Character* destination; String result = String::createUninitialized(source.size(), destination); StringImpl::copyCharacters(destination, source); return result; @@ -463,22 +470,27 @@ void String::convertTo16Bit() *this = WTFMove(convertedString); } -template -String fromUTF8Impl(std::span string) +String String::fromUTF8(std::span codeUnits) +{ + return codeUnits; +} + +String String::fromUTF8ReplacingInvalidSequences(std::span string) { + if (!string.data()) + return { }; + RELEASE_ASSERT(string.size() <= String::MaxLength); if (string.empty()) return emptyString(); if (charactersAreAllASCII(string)) - return StringImpl::create(spanReinterpretCast(string)); + return StringImpl::create(spanReinterpretCast(string)); - Vector buffer(string.size()); - - auto result = replaceInvalidSequences - ? Unicode::convertReplacingInvalidSequences(string, buffer.mutableSpan()) - : Unicode::convert(string, buffer.mutableSpan()); + Vector buffer(string.size()); + + auto result = Unicode::convertReplacingInvalidSequences(string, buffer.mutableSpan()); if (result.code != Unicode::ConversionResultCode::Success) return { }; @@ -486,27 +498,13 @@ String fromUTF8Impl(std::span string) return StringImpl::create(result.buffer); } -String String::fromUTF8(std::span string) -{ - if (!string.data()) - return { }; - return fromUTF8Impl(string); -} - -String String::fromUTF8ReplacingInvalidSequences(std::span characters) -{ - if (!characters.data()) - return { }; - return fromUTF8Impl(characters); -} - String String::fromUTF8WithLatin1Fallback(std::span string) { - String utf8 = fromUTF8(string); + String utf8 { string }; if (!utf8) { // Do this assertion before chopping the size_t down to unsigned. RELEASE_ASSERT(string.size() <= String::MaxLength); - return spanReinterpretCast(string); + return spanReinterpretCast(string); } return utf8; } @@ -542,10 +540,10 @@ static inline double toDoubleType(std::span data, bool* ok, return number; } -double charactersToDouble(std::span data, bool* ok) +double charactersToDouble(std::span data, bool* ok) { size_t parsedLength; - return toDoubleType(data, ok, parsedLength); + return toDoubleType(data, ok, parsedLength); } double charactersToDouble(std::span data, bool* ok) @@ -554,11 +552,11 @@ double charactersToDouble(std::span data, bool* ok) return toDoubleType(data, ok, parsedLength); } -float charactersToFloat(std::span data, bool* ok) +float charactersToFloat(std::span data, bool* ok) { // FIXME: This will return ok even when the string fits into a double but not a float. size_t parsedLength; - return static_cast(toDoubleType(data, ok, parsedLength)); + return static_cast(toDoubleType(data, ok, parsedLength)); } float charactersToFloat(std::span data, bool* ok) @@ -568,10 +566,10 @@ float charactersToFloat(std::span data, bool* ok) return static_cast(toDoubleType(data, ok, parsedLength)); } -float charactersToFloat(std::span data, size_t& parsedLength) +float charactersToFloat(std::span data, size_t& parsedLength) { // FIXME: This will return ok even when the string fits into a double but not a float. - return static_cast(toDoubleType(data, nullptr, parsedLength)); + return static_cast(toDoubleType(data, nullptr, parsedLength)); } float charactersToFloat(std::span data, size_t& parsedLength) diff --git a/Source/WTF/wtf/text/WTFString.h b/Source/WTF/wtf/text/WTFString.h index a97e53572ba33..969e3b6b5a2d8 100644 --- a/Source/WTF/wtf/text/WTFString.h +++ b/Source/WTF/wtf/text/WTFString.h @@ -39,12 +39,12 @@ namespace WTF { // Declarations of string operations -WTF_EXPORT_PRIVATE double charactersToDouble(std::span, bool* ok = nullptr); -WTF_EXPORT_PRIVATE double charactersToDouble(std::span, bool* ok = nullptr); -WTF_EXPORT_PRIVATE float charactersToFloat(std::span, bool* ok = nullptr); -WTF_EXPORT_PRIVATE float charactersToFloat(std::span, bool* ok = nullptr); -WTF_EXPORT_PRIVATE float charactersToFloat(std::span, size_t& parsedLength); -WTF_EXPORT_PRIVATE float charactersToFloat(std::span, size_t& parsedLength); +WTF_EXPORT_PRIVATE double charactersToDouble(std::span, bool* ok = nullptr); +WTF_EXPORT_PRIVATE double charactersToDouble(std::span, bool* ok = nullptr); +WTF_EXPORT_PRIVATE float charactersToFloat(std::span, bool* ok = nullptr); +WTF_EXPORT_PRIVATE float charactersToFloat(std::span, bool* ok = nullptr); +WTF_EXPORT_PRIVATE float charactersToFloat(std::span, size_t& parsedLength); +WTF_EXPORT_PRIVATE float charactersToFloat(std::span, size_t& parsedLength); template bool containsOnly(std::span); @@ -60,10 +60,13 @@ class String final { WTF_EXPORT_PRIVATE String(std::span characters); // Construct a string with Latin-1 data. - WTF_EXPORT_PRIVATE String(std::span characters); + WTF_EXPORT_PRIVATE String(std::span characters); WTF_EXPORT_PRIVATE String(std::span characters); ALWAYS_INLINE static String fromLatin1(const char* characters) { return String { characters }; } + // Construct a string with UTF-8 data, null string if it contains invalid UTF-8 sequences. + WTF_EXPORT_PRIVATE String(std::span); + // Construct a string referencing an existing StringImpl. String(StringImpl&); String(StringImpl*); @@ -88,8 +91,8 @@ class String final { void swap(String& o) { m_impl.swap(o.m_impl); } - static String adopt(StringBuffer&& buffer) { return StringImpl::adopt(WTFMove(buffer)); } - static String adopt(StringBuffer&& buffer) { return StringImpl::adopt(WTFMove(buffer)); } + static String adopt(StringBuffer&& buffer) { return StringImpl::adopt(WTFMove(buffer)); } + static String adopt(StringBuffer&& buffer) { return StringImpl::adopt(WTFMove(buffer)); } template static String adopt(Vector&& vector) { return StringImpl::adopt(WTFMove(vector)); } @@ -100,15 +103,15 @@ class String final { RefPtr releaseImpl() { return WTFMove(m_impl); } unsigned length() const { return m_impl ? m_impl->length() : 0; } - std::span span8() const { return m_impl ? m_impl->span8() : std::span(); } - std::span span16() const { return m_impl ? m_impl->span16() : std::span(); } + std::span span8() const LIFETIME_BOUND { return m_impl ? m_impl->span8() : std::span(); } + std::span span16() const LIFETIME_BOUND { return m_impl ? m_impl->span16() : std::span(); } // Return span8() or span16() depending on CharacterType. template std::span span() const; bool is8Bit() const { return !m_impl || m_impl->is8Bit(); } - unsigned sizeInBytes() const { return m_impl ? m_impl->length() * (is8Bit() ? sizeof(LChar) : sizeof(UChar)) : 0; } + unsigned sizeInBytes() const { return m_impl ? m_impl->length() * (is8Bit() ? sizeof(Latin1Character) : sizeof(char16_t)) : 0; } WTF_EXPORT_PRIVATE CString ascii() const; WTF_EXPORT_PRIVATE CString latin1() const; @@ -139,8 +142,8 @@ class String final { AtomString toExistingAtomString() const; // Find a single character or string, also with match function & latin1 forms. - size_t find(UChar character, unsigned start = 0) const { return m_impl ? m_impl->find(character, start) : notFound; } - size_t find(LChar character, unsigned start = 0) const { return m_impl ? m_impl->find(character, start) : notFound; } + size_t find(char16_t character, unsigned start = 0) const { return m_impl ? m_impl->find(character, start) : notFound; } + size_t find(Latin1Character character, unsigned start = 0) const { return m_impl ? m_impl->find(character, start) : notFound; } size_t find(char character, unsigned start = 0) const { return m_impl ? m_impl->find(character, start) : notFound; } size_t find(StringView) const; @@ -205,8 +208,8 @@ class String final { // 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); } - static String createUninitialized(unsigned length, LChar*& data) { return StringImpl::createUninitialized(length, data); } + static String createUninitialized(unsigned length, char16_t*& data) { return StringImpl::createUninitialized(length, data); } + static String createUninitialized(unsigned length, Latin1Character*& data) { return StringImpl::createUninitialized(length, data); } using SplitFunctor = WTF::Function; @@ -262,16 +265,20 @@ class String final { WTF_EXPORT_PRIVATE void convertTo16Bit(); // String::fromUTF8 will return a null string if the input data contains invalid UTF-8 sequences. + // FIXME: Deprecated: Use constructor that takes span. WTF_EXPORT_PRIVATE static String fromUTF8(std::span); - static String fromUTF8(std::span characters) { return fromUTF8(byteCast(characters)); } - static String fromUTF8(std::span characters) { return fromUTF8(byteCast(characters)); } - static String fromUTF8(const char* string) { return fromUTF8(WTF::span8(string)); } + static String fromUTF8(std::span characters) { return byteCast(characters); } + static String fromUTF8(std::span characters) { return byteCast(characters); } + static String fromUTF8(const char* string) { return byteCast(unsafeSpan(string)); } + + // Convert each invalid UTF-8 sequence into a replacement character. static String fromUTF8ReplacingInvalidSequences(std::span); - static String fromUTF8ReplacingInvalidSequences(std::span characters) { return fromUTF8ReplacingInvalidSequences(byteCast(characters)); } + static String fromUTF8ReplacingInvalidSequences(std::span characters) { return fromUTF8ReplacingInvalidSequences(byteCast(characters)); } // Tries to convert the passed in string to UTF-8, but will fall back to Latin-1 if the string is not valid UTF-8. + // FIXME: Deprecated: Use fromUTF8ReplacingInvalidSequences. WTF_EXPORT_PRIVATE static String fromUTF8WithLatin1Fallback(std::span); - static String fromUTF8WithLatin1Fallback(std::span characters) { return fromUTF8WithLatin1Fallback(byteCast(characters)); } + static String fromUTF8WithLatin1Fallback(std::span characters) { return fromUTF8WithLatin1Fallback(byteCast(characters)); } static String fromUTF8WithLatin1Fallback(std::span characters) { return fromUTF8WithLatin1Fallback(byteCast(characters)); } WTF_EXPORT_PRIVATE static String fromCodePoint(char32_t codePoint); @@ -371,7 +378,7 @@ template<> struct VectorTraits : VectorTraitsBase { template<> struct IntegerToStringConversionTrait { using ReturnType = String; using AdditionalArgumentType = void; - static String flush(std::span characters, void*) { return characters; } + static String flush(std::span characters, void*) { return characters; } }; #ifdef __OBJC__ @@ -431,7 +438,7 @@ inline String::String(ASCIILiteral characters) { } -template<> inline std::span String::span() const +template<> inline std::span String::span() const { return span8(); } diff --git a/Source/WTF/wtf/text/WYHash.h b/Source/WTF/wtf/text/WYHash.h index 4ac0a7989f4f3..91ccd7e49be35 100644 --- a/Source/WTF/wtf/text/WYHash.h +++ b/Source/WTF/wtf/text/WYHash.h @@ -178,8 +178,8 @@ class WYHash { } }; - // LChar data is interpreted as Latin-1-encoded (zero-extended to 16 bits). - // To match the hash value of UChar with same content, extend 16 bits (0xff) + // Latin1Character data is interpreted as Latin-1-encoded (zero-extended to 16 bits). + // To match the hash value of char16_t with same content, extend 16 bits (0xff) // to 32 bits (0x00ff). template struct Reader8Bit { diff --git a/Source/WTF/wtf/text/cf/StringCF.cpp b/Source/WTF/wtf/text/cf/StringCF.cpp index 1bda58f59bf20..96a403441df65 100644 --- a/Source/WTF/wtf/text/cf/StringCF.cpp +++ b/Source/WTF/wtf/text/cf/StringCF.cpp @@ -41,9 +41,9 @@ String::String(CFStringRef str) } { - StringBuffer buffer(size); + StringBuffer buffer(size); CFIndex usedBufLen; - CFIndex convertedSize = CFStringGetBytes(str, CFRangeMake(0, size), kCFStringEncodingISOLatin1, 0, false, buffer.characters(), size, &usedBufLen); + CFIndex convertedSize = CFStringGetBytes(str, CFRangeMake(0, size), kCFStringEncodingISOLatin1, 0, false, byteCast(buffer.characters()), size, &usedBufLen); if (convertedSize == size && usedBufLen == size) { m_impl = StringImpl::adopt(WTFMove(buffer)); return; diff --git a/Source/WTF/wtf/text/cf/StringConcatenateCF.h b/Source/WTF/wtf/text/cf/StringConcatenateCF.h index 02a81d226d734..fd200068f55a2 100644 --- a/Source/WTF/wtf/text/cf/StringConcatenateCF.h +++ b/Source/WTF/wtf/text/cf/StringConcatenateCF.h @@ -47,7 +47,7 @@ inline StringTypeAdapter::StringTypeAdapter(CFStringRef string) { } -template<> inline void StringTypeAdapter::writeTo(LChar* destination) const +template<> inline void StringTypeAdapter::writeTo(Latin1Character* destination) const { if (m_string) std::memcpy(destination, CFStringGetCStringPtr(m_string, kCFStringEncodingISOLatin1), CFStringGetLength(m_string)); diff --git a/Source/WTF/wtf/text/cf/StringImplCF.cpp b/Source/WTF/wtf/text/cf/StringImplCF.cpp index 425ee52899cb0..acb0b66aa0371 100644 --- a/Source/WTF/wtf/text/cf/StringImplCF.cpp +++ b/Source/WTF/wtf/text/cf/StringImplCF.cpp @@ -120,7 +120,7 @@ RetainPtr StringImpl::createCFString() if (!m_length || !isMainThread()) { if (is8Bit()) { auto characters = span8(); - return adoptCF(CFStringCreateWithBytes(nullptr, characters.data(), characters.size(), kCFStringEncodingISOLatin1, false)); + return adoptCF(CFStringCreateWithBytes(nullptr, byteCast(characters.data()), characters.size(), kCFStringEncodingISOLatin1, false)); } auto characters = span16(); return adoptCF(CFStringCreateWithCharacters(nullptr, reinterpret_cast(characters.data()), characters.size())); @@ -134,7 +134,7 @@ RetainPtr StringImpl::createCFString() RetainPtr string; if (is8Bit()) { auto characters = span8(); - string = adoptCF(CFStringCreateWithBytesNoCopy(allocator, characters.data(), characters.size(), kCFStringEncodingISOLatin1, false, kCFAllocatorNull)); + string = adoptCF(CFStringCreateWithBytesNoCopy(allocator, byteCast(characters.data()), characters.size(), kCFStringEncodingISOLatin1, false, kCFAllocatorNull)); } else { auto characters = span16(); string = adoptCF(CFStringCreateWithCharactersNoCopy(allocator, reinterpret_cast(characters.data()), characters.size(), kCFAllocatorNull)); diff --git a/Source/WTF/wtf/text/cf/StringViewCF.cpp b/Source/WTF/wtf/text/cf/StringViewCF.cpp index 381d2e1b5e7e6..6111de46bfd85 100644 --- a/Source/WTF/wtf/text/cf/StringViewCF.cpp +++ b/Source/WTF/wtf/text/cf/StringViewCF.cpp @@ -37,7 +37,7 @@ RetainPtr StringView::createCFString() const { if (is8Bit()) { auto characters = span8(); - return adoptCF(CFStringCreateWithBytes(kCFAllocatorDefault, characters.data(), characters.size(), kCFStringEncodingISOLatin1, false)); + return adoptCF(CFStringCreateWithBytes(kCFAllocatorDefault, byteCast(characters.data()), characters.size(), kCFStringEncodingISOLatin1, false)); } auto characters = span16(); return adoptCF(CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast(characters.data()), characters.size())); @@ -47,7 +47,7 @@ RetainPtr StringView::createCFStringWithoutCopying() const { if (is8Bit()) { auto characters = span8(); - return adoptCF(CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, characters.data(), characters.size(), kCFStringEncodingISOLatin1, false, kCFAllocatorNull)); + return adoptCF(CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, byteCast(characters.data()), characters.size(), kCFStringEncodingISOLatin1, false, kCFAllocatorNull)); } auto characters = span16(); return adoptCF(CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, reinterpret_cast(characters.data()), characters.size(), kCFAllocatorNull)); diff --git a/Source/WTF/wtf/text/cocoa/ASCIILiteralCocoa.mm b/Source/WTF/wtf/text/cocoa/ASCIILiteralCocoa.mm index 9d965b52f8322..8d14c00a3c3e4 100644 --- a/Source/WTF/wtf/text/cocoa/ASCIILiteralCocoa.mm +++ b/Source/WTF/wtf/text/cocoa/ASCIILiteralCocoa.mm @@ -33,7 +33,7 @@ RetainPtr ASCIILiteral::createNSString() const { auto span = span8(); - return adoptNS([[NSString alloc] initWithBytesNoCopy:const_cast(span.data()) length:span.size() encoding:NSISOLatin1StringEncoding freeWhenDone:NO]); + return adoptNS([[NSString alloc] initWithBytesNoCopy:const_cast(span.data()) length:span.size() encoding:NSISOLatin1StringEncoding freeWhenDone:NO]); } } // namespace WTF diff --git a/Source/WTF/wtf/text/cocoa/StringViewCocoa.mm b/Source/WTF/wtf/text/cocoa/StringViewCocoa.mm index 70dca7f191857..55a61357656ce 100644 --- a/Source/WTF/wtf/text/cocoa/StringViewCocoa.mm +++ b/Source/WTF/wtf/text/cocoa/StringViewCocoa.mm @@ -34,7 +34,7 @@ { if (is8Bit()) { auto characters = span8(); - return adoptNS([[NSString alloc] initWithBytes:const_cast(characters.data()) length:characters.size() encoding:NSISOLatin1StringEncoding]); + return adoptNS([[NSString alloc] initWithBytes:const_cast(characters.data()) length:characters.size() encoding:NSISOLatin1StringEncoding]); } auto characters = span16(); return adoptNS([[NSString alloc] initWithCharacters:reinterpret_cast(const_cast(characters.data())) length:characters.size()]); @@ -44,7 +44,7 @@ { if (is8Bit()) { auto characters = span8(); - return adoptNS([[NSString alloc] initWithBytesNoCopy:const_cast(characters.data()) length:characters.size() encoding:NSISOLatin1StringEncoding freeWhenDone:NO]); + return adoptNS([[NSString alloc] initWithBytesNoCopy:const_cast(characters.data()) length:characters.size() encoding:NSISOLatin1StringEncoding freeWhenDone:NO]); } auto characters = span16(); return adoptNS([[NSString alloc] initWithCharactersNoCopy:reinterpret_cast(const_cast(characters.data())) length:characters.size() freeWhenDone:NO]); diff --git a/Source/WTF/wtf/text/icu/UTextProviderLatin1.cpp b/Source/WTF/wtf/text/icu/UTextProviderLatin1.cpp index 67cbd1b5e662f..977abbe2673dd 100644 --- a/Source/WTF/wtf/text/icu/UTextProviderLatin1.cpp +++ b/Source/WTF/wtf/text/icu/UTextProviderLatin1.cpp @@ -36,7 +36,7 @@ namespace WTF { static UText* uTextLatin1Clone(UText*, const UText*, UBool, UErrorCode*); static int64_t uTextLatin1NativeLength(UText*); static UBool uTextLatin1Access(UText*, int64_t, UBool); -static int32_t uTextLatin1Extract(UText*, int64_t, int64_t, UChar*, int32_t, UErrorCode*); +static int32_t uTextLatin1Extract(UText*, int64_t, int64_t, char16_t*, int32_t, UErrorCode*); static int64_t uTextLatin1MapOffsetToNative(const UText*); static int32_t uTextLatin1MapNativeIndexToUTF16(const UText*, int64_t); static void uTextLatin1Close(UText*); @@ -67,7 +67,7 @@ static UText* uTextLatin1Clone(UText* destination, const UText* source, UBool de if (U_FAILURE(*status)) return nullptr; - UText* result = utext_setup(destination, sizeof(UChar) * UTextWithBufferInlineCapacity, status); + UText* result = utext_setup(destination, sizeof(char16_t) * UTextWithBufferInlineCapacity, status); if (U_FAILURE(*status)) return destination; @@ -81,8 +81,8 @@ static UText* uTextLatin1Clone(UText* destination, const UText* source, UBool de result->context = source->context; result->a = source->a; result->pFuncs = &uTextLatin1Funcs; - result->chunkContents = static_cast(result->pExtra); - memset(const_cast(result->chunkContents), 0, sizeof(UChar) * UTextWithBufferInlineCapacity); + result->chunkContents = static_cast(result->pExtra); + memset(const_cast(result->chunkContents), 0, sizeof(char16_t) * UTextWithBufferInlineCapacity); return result; } @@ -140,14 +140,14 @@ static UBool uTextLatin1Access(UText* uText, int64_t index, UBool forward) } uText->chunkLength = static_cast(uText->chunkNativeLimit - uText->chunkNativeStart); - StringImpl::copyCharacters(const_cast(uText->chunkContents), { static_cast(uText->context) + uText->chunkNativeStart, static_cast(uText->chunkLength) }); + StringImpl::copyCharacters(const_cast(uText->chunkContents), { static_cast(uText->context) + uText->chunkNativeStart, static_cast(uText->chunkLength) }); uText->nativeIndexingLimit = uText->chunkLength; return true; } -static int32_t uTextLatin1Extract(UText* uText, int64_t start, int64_t limit, UChar* dest, int32_t destCapacity, UErrorCode* status) +static int32_t uTextLatin1Extract(UText* uText, int64_t start, int64_t limit, char16_t* dest, int32_t destCapacity, UErrorCode* status) { int64_t length = uText->a; if (U_FAILURE(*status)) @@ -178,7 +178,7 @@ static int32_t uTextLatin1Extract(UText* uText, int64_t start, int64_t limit, UC if (trimmedLength > destCapacity) trimmedLength = destCapacity; - StringImpl::copyCharacters(dest, { static_cast(uText->context) + start, static_cast(trimmedLength) }); + StringImpl::copyCharacters(dest, { static_cast(uText->context) + start, static_cast(trimmedLength) }); } if (length < destCapacity) { @@ -211,7 +211,7 @@ static void uTextLatin1Close(UText* uText) uText->context = nullptr; } -UText* openLatin1UTextProvider(UTextWithBuffer* utWithBuffer, std::span string, UErrorCode* status) +UText* openLatin1UTextProvider(UTextWithBuffer* utWithBuffer, std::span string, UErrorCode* status) { if (U_FAILURE(*status)) return nullptr; @@ -228,8 +228,8 @@ UText* openLatin1UTextProvider(UTextWithBuffer* utWithBuffer, std::spancontext = string.data(); text->a = string.size(); text->pFuncs = &uTextLatin1Funcs; - text->chunkContents = static_cast(text->pExtra); - memset(const_cast(text->chunkContents), 0, sizeof(UChar) * UTextWithBufferInlineCapacity); + text->chunkContents = static_cast(text->pExtra); + memset(const_cast(text->chunkContents), 0, sizeof(char16_t) * UTextWithBufferInlineCapacity); return text; } @@ -240,7 +240,7 @@ UText* openLatin1UTextProvider(UTextWithBuffer* utWithBuffer, std::spanchunkNativeStart = nativeIndex; - text->chunkNativeLimit = nativeIndex + text->extraSize / sizeof(UChar); + text->chunkNativeLimit = nativeIndex + text->extraSize / sizeof(char16_t); if (text->chunkNativeLimit > nativeLength) text->chunkNativeLimit = nativeLength; } else { text->chunkNativeLimit = nativeIndex; - text->chunkNativeStart = nativeIndex - text->extraSize / sizeof(UChar); + text->chunkNativeStart = nativeIndex - text->extraSize / sizeof(char16_t); if (text->chunkNativeStart < text->b) text->chunkNativeStart = text->b; } @@ -291,13 +291,13 @@ static void textLatin1ContextAwareMoveInPrimaryContext(UText* text, int64_t nati text->chunkLength = length < std::numeric_limits::max() ? static_cast(length) : 0; text->nativeIndexingLimit = text->chunkLength; text->chunkOffset = forward ? 0 : text->chunkLength; - StringImpl::copyCharacters(const_cast(text->chunkContents), { static_cast(text->p) + (text->chunkNativeStart - text->b), static_cast(text->chunkLength) }); + StringImpl::copyCharacters(const_cast(text->chunkContents), { static_cast(text->p) + (text->chunkNativeStart - text->b), static_cast(text->chunkLength) }); } static void textLatin1ContextAwareSwitchToPrimaryContext(UText* text, int64_t nativeIndex, int64_t nativeLength, UBool forward) { ASSERT(!text->chunkContents || text->chunkContents == text->q); - text->chunkContents = static_cast(text->pExtra); + text->chunkContents = static_cast(text->pExtra); textLatin1ContextAwareMoveInPrimaryContext(text, nativeIndex, nativeLength, forward); } @@ -319,7 +319,7 @@ static void textLatin1ContextAwareMoveInPriorContext(UText* text, int64_t native static void textLatin1ContextAwareSwitchToPriorContext(UText* text, int64_t nativeIndex, int64_t nativeLength, UBool forward) { ASSERT(!text->chunkContents || text->chunkContents == text->pExtra); - text->chunkContents = static_cast(text->q); + text->chunkContents = static_cast(text->q); textLatin1ContextAwareMoveInPriorContext(text, nativeIndex, nativeLength, forward); } @@ -359,7 +359,7 @@ static UBool uTextLatin1ContextAwareAccess(UText* text, int64_t nativeIndex, UBo return true; } -static int32_t uTextLatin1ContextAwareExtract(UText*, int64_t, int64_t, UChar*, int32_t, UErrorCode* errorCode) +static int32_t uTextLatin1ContextAwareExtract(UText*, int64_t, int64_t, char16_t*, int32_t, UErrorCode* errorCode) { // In the present context, this text provider is used only with ICU functions // that do not perform an extract operation. @@ -373,7 +373,7 @@ static void uTextLatin1ContextAwareClose(UText* text) text->context = nullptr; } -UText* openLatin1ContextAwareUTextProvider(UTextWithBuffer* utWithBuffer, std::span string, std::span priorContext, UErrorCode* status) +UText* openLatin1ContextAwareUTextProvider(UTextWithBuffer* utWithBuffer, std::span string, std::span priorContext, UErrorCode* status) { if (U_FAILURE(*status)) return nullptr; diff --git a/Source/WTF/wtf/text/icu/UTextProviderLatin1.h b/Source/WTF/wtf/text/icu/UTextProviderLatin1.h index eda22404eee2f..f8126a5e7b8d2 100644 --- a/Source/WTF/wtf/text/icu/UTextProviderLatin1.h +++ b/Source/WTF/wtf/text/icu/UTextProviderLatin1.h @@ -26,7 +26,7 @@ #pragma once #include -#include +#include namespace WTF { @@ -38,7 +38,7 @@ struct UTextWithBuffer { UChar buffer[UTextWithBufferInlineCapacity]; }; -UText* openLatin1UTextProvider(UTextWithBuffer* utWithBuffer, std::span string, UErrorCode* status); -WTF_EXPORT_PRIVATE UText* openLatin1ContextAwareUTextProvider(UTextWithBuffer* utWithBuffer, std::span string, std::span priorContext, UErrorCode* status); +UText* openLatin1UTextProvider(UTextWithBuffer* utWithBuffer, std::span string, UErrorCode* status); +WTF_EXPORT_PRIVATE UText* openLatin1ContextAwareUTextProvider(UTextWithBuffer* utWithBuffer, std::span string, std::span priorContext, UErrorCode* status); } // namespace WTF diff --git a/Source/WTF/wtf/unicode/UTF8Conversion.cpp b/Source/WTF/wtf/unicode/UTF8Conversion.cpp index f903eb1038c2a..6f245d180d6c5 100644 --- a/Source/WTF/wtf/unicode/UTF8Conversion.cpp +++ b/Source/WTF/wtf/unicode/UTF8Conversion.cpp @@ -41,7 +41,7 @@ enum class Replacement : bool { None, ReplaceInvalidSequences }; template static char32_t next(std::span, size_t& offset); template static bool append(std::span, size_t& offset, char32_t character); -template<> char32_t next(std::span characters, size_t& offset) +template<> char32_t next(std::span characters, size_t& offset) { return characters[offset++]; } @@ -135,7 +135,7 @@ ConversionResult convert(std::span source, std::span convert(std::span source, std::span buffer) +ConversionResult convert(std::span source, std::span buffer) { return convertInternal(source, buffer); } @@ -203,7 +203,7 @@ bool equal(std::span a, std::span b) return equalInternal(a, b); } -bool equal(std::span a, std::span b) +bool equal(std::span a, std::span b) { return equalInternal(a, b); } diff --git a/Source/WTF/wtf/unicode/UTF8Conversion.h b/Source/WTF/wtf/unicode/UTF8Conversion.h index 007b8fe3292f3..f507b6b97236e 100644 --- a/Source/WTF/wtf/unicode/UTF8Conversion.h +++ b/Source/WTF/wtf/unicode/UTF8Conversion.h @@ -25,7 +25,7 @@ #pragma once -#include +#include namespace WTF { namespace Unicode { @@ -44,14 +44,14 @@ template struct ConversionResult { WTF_EXPORT_PRIVATE ConversionResult convert(std::span, std::span); WTF_EXPORT_PRIVATE ConversionResult convert(std::span, std::span); -WTF_EXPORT_PRIVATE ConversionResult convert(std::span, std::span); +WTF_EXPORT_PRIVATE ConversionResult convert(std::span, std::span); // Invalid sequences are converted to the replacement character. WTF_EXPORT_PRIVATE ConversionResult convertReplacingInvalidSequences(std::span, std::span); WTF_EXPORT_PRIVATE ConversionResult convertReplacingInvalidSequences(std::span, std::span); WTF_EXPORT_PRIVATE bool equal(std::span, std::span); -WTF_EXPORT_PRIVATE bool equal(std::span, std::span); +WTF_EXPORT_PRIVATE bool equal(std::span, std::span); // The checkUTF8 function checks the UTF-8 and returns a span of the valid complete // UTF-8 sequences at the start of the passed-in characters, along with the UTF-16 diff --git a/Source/WTF/wtf/unicode/icu/CollatorICU.cpp b/Source/WTF/wtf/unicode/icu/CollatorICU.cpp index a03fbbea6c0b9..0c5b31e4cd5ea 100644 --- a/Source/WTF/wtf/unicode/icu/CollatorICU.cpp +++ b/Source/WTF/wtf/unicode/icu/CollatorICU.cpp @@ -183,7 +183,7 @@ static UChar32 currentLatin1(UCharIterator* iterator) ASSERT(iterator->index >= iterator->start); if (iterator->index >= iterator->limit) return U_SENTINEL; - return static_cast(iterator->context)[iterator->index]; + return static_cast(iterator->context)[iterator->index]; } static UChar32 nextLatin1(UCharIterator* iterator) @@ -191,14 +191,14 @@ static UChar32 nextLatin1(UCharIterator* iterator) ASSERT(iterator->index >= iterator->start); if (iterator->index >= iterator->limit) return U_SENTINEL; - return static_cast(iterator->context)[iterator->index++]; + return static_cast(iterator->context)[iterator->index++]; } static UChar32 previousLatin1(UCharIterator* iterator) { if (iterator->index <= iterator->start) return U_SENTINEL; - return static_cast(iterator->context)[--iterator->index]; + return static_cast(iterator->context)[--iterator->index]; } static uint32_t getStateLatin1(const UCharIterator* iterator) @@ -211,7 +211,7 @@ static void setStateLatin1(UCharIterator* iterator, uint32_t state, UErrorCode*) iterator->index = state; } -static UCharIterator createLatin1Iterator(std::span characters) +static UCharIterator createLatin1Iterator(std::span characters) { UCharIterator iterator; iterator.context = characters.data(); diff --git a/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.cpp b/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.cpp index b18017bed2aba..1af12539c3ef3 100644 --- a/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.cpp +++ b/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.cpp @@ -69,9 +69,9 @@ static std::optional>> extractKeyIDsKeyids(const Shared // https://w3c.github.io/encrypted-media/format-registry/initdata/keyids.html#format if (buffer.size() > std::numeric_limits::max()) return std::nullopt; - String json { buffer.span() }; - auto value = JSON::Value::parseJSON(json); + // FIXME: Specification says this should be parsed as UTF-8, not Latin-1. + auto value = JSON::Value::parseJSON(byteCast(buffer.span())); if (!value) return std::nullopt; diff --git a/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp b/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp index 984d024419054..f2882095c93af 100644 --- a/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp +++ b/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp @@ -253,7 +253,7 @@ static IDBError createOrMigrateRecordsTableIfNecessary(SQLiteDatabase& database) String tableStatement = database.tableSQL("Records"_s); if (tableStatement.isEmpty()) { if (!database.executeCommand(v3RecordsTableSchema())) - return IDBError { ExceptionCode::UnknownError, makeString("Error creating Records table ("_s, database.lastError(), ") - "_s, span(database.lastErrorMsg())) }; + return IDBError { ExceptionCode::UnknownError, makeString("Error creating Records table ("_s, database.lastError(), ") - "_s, unsafeSpan(database.lastErrorMsg())) }; return IDBError { }; } @@ -273,16 +273,16 @@ static IDBError createOrMigrateRecordsTableIfNecessary(SQLiteDatabase& database) // Create a temporary table with the correct schema and migrate all existing content over. if (!database.executeCommand(v3RecordsTableSchemaTemp())) - return IDBError { ExceptionCode::UnknownError, makeString("Error creating temporary Records table ("_s, database.lastError(), ") - "_s, span(database.lastErrorMsg())) }; + return IDBError { ExceptionCode::UnknownError, makeString("Error creating temporary Records table ("_s, database.lastError(), ") - "_s, unsafeSpan(database.lastErrorMsg())) }; if (!database.executeCommand("INSERT INTO _Temp_Records (objectStoreID, key, value) SELECT objectStoreID, CAST(key AS TEXT), value FROM Records"_s)) - return IDBError { ExceptionCode::UnknownError, makeString("Error migrating Records table ("_s, database.lastError(), ") - "_s, span(database.lastErrorMsg())) }; + return IDBError { ExceptionCode::UnknownError, makeString("Error migrating Records table ("_s, database.lastError(), ") - "_s, unsafeSpan(database.lastErrorMsg())) }; if (!database.executeCommand("DROP TABLE Records"_s)) - return IDBError { ExceptionCode::UnknownError, makeString("Error dropping Records table ("_s, database.lastError(), ") - "_s, span(database.lastErrorMsg())) }; + return IDBError { ExceptionCode::UnknownError, makeString("Error dropping Records table ("_s, database.lastError(), ") - "_s, unsafeSpan(database.lastErrorMsg())) }; if (!database.executeCommand("ALTER TABLE _Temp_Records RENAME TO Records"_s)) - return IDBError { ExceptionCode::UnknownError, makeString("Error renaming temporary Records table ("_s, database.lastError(), ") - "_s, span(database.lastErrorMsg())) }; + return IDBError { ExceptionCode::UnknownError, makeString("Error renaming temporary Records table ("_s, database.lastError(), ") - "_s, unsafeSpan(database.lastErrorMsg())) }; transaction.commit(); @@ -297,7 +297,7 @@ IDBError SQLiteIDBBackingStore::ensureValidBlobTables() String recordsTableStatement = m_sqliteDB->tableSQL("BlobRecords"_s); if (recordsTableStatement.isEmpty()) { if (!m_sqliteDB->executeCommand(blobRecordsTableSchema())) - return IDBError { ExceptionCode::UnknownError, makeString("Error creating BlobRecords table ("_s, m_sqliteDB->lastError(), ") - "_s, span(m_sqliteDB->lastErrorMsg())) }; + return IDBError { ExceptionCode::UnknownError, makeString("Error creating BlobRecords table ("_s, m_sqliteDB->lastError(), ") - "_s, unsafeSpan(m_sqliteDB->lastErrorMsg())) }; recordsTableStatement = blobRecordsTableSchema(); } @@ -307,7 +307,7 @@ IDBError SQLiteIDBBackingStore::ensureValidBlobTables() String filesTableStatement = m_sqliteDB->tableSQL("BlobFiles"_s); if (filesTableStatement.isEmpty()) { if (!m_sqliteDB->executeCommand(blobFilesTableSchema())) - return IDBError { ExceptionCode::UnknownError, makeString("Error creating BlobFiles table ("_s, m_sqliteDB->lastError(), ") - "_s, span(m_sqliteDB->lastErrorMsg())) }; + return IDBError { ExceptionCode::UnknownError, makeString("Error creating BlobFiles table ("_s, m_sqliteDB->lastError(), ") - "_s, unsafeSpan(m_sqliteDB->lastErrorMsg())) }; filesTableStatement = blobFilesTableSchema(); } @@ -328,7 +328,7 @@ IDBError SQLiteIDBBackingStore::ensureValidRecordsTable() // Whether the updated records table already existed or if it was just created and the data migrated over, // make sure the uniqueness index exists. if (!m_sqliteDB->executeCommand("CREATE UNIQUE INDEX IF NOT EXISTS RecordsIndex ON Records (objectStoreID, key);"_s)) - error = IDBError { ExceptionCode::UnknownError, makeString("Error creating RecordsIndex on Records table ("_s, m_sqliteDB->lastError(), ") - "_s, span(m_sqliteDB->lastErrorMsg())) }; + error = IDBError { ExceptionCode::UnknownError, makeString("Error creating RecordsIndex on Records table ("_s, m_sqliteDB->lastError(), ") - "_s, unsafeSpan(m_sqliteDB->lastErrorMsg())) }; return error; } @@ -341,7 +341,7 @@ IDBError SQLiteIDBBackingStore::ensureValidIndexRecordsTable() String tableStatement = m_sqliteDB->tableSQL("IndexRecords"_s); if (tableStatement.isEmpty()) { if (!m_sqliteDB->executeCommand(v3IndexRecordsTableSchema())) - return IDBError { ExceptionCode::UnknownError, makeString("Error creating IndexRecords table ("_s, m_sqliteDB->lastError(), ") - "_s, span(m_sqliteDB->lastErrorMsg())) }; + return IDBError { ExceptionCode::UnknownError, makeString("Error creating IndexRecords table ("_s, m_sqliteDB->lastError(), ") - "_s, unsafeSpan(m_sqliteDB->lastErrorMsg())) }; return IDBError { }; } @@ -357,16 +357,16 @@ IDBError SQLiteIDBBackingStore::ensureValidIndexRecordsTable() // Create a temporary table with the correct schema and migrate all existing content over. if (!m_sqliteDB->executeCommand(v3IndexRecordsTableSchemaTemp())) - return IDBError { ExceptionCode::UnknownError, makeString("Error creating temporary IndexRecords table ("_s, m_sqliteDB->lastError(), ") - "_s, span(m_sqliteDB->lastErrorMsg())) }; + return IDBError { ExceptionCode::UnknownError, makeString("Error creating temporary IndexRecords table ("_s, m_sqliteDB->lastError(), ") - "_s, unsafeSpan(m_sqliteDB->lastErrorMsg())) }; if (!m_sqliteDB->executeCommand("INSERT INTO _Temp_IndexRecords SELECT IndexRecords.indexID, IndexRecords.objectStoreID, IndexRecords.key, IndexRecords.value, Records.rowid FROM IndexRecords INNER JOIN Records ON Records.key = IndexRecords.value AND Records.objectStoreID = IndexRecords.objectStoreID"_s)) - return IDBError { ExceptionCode::UnknownError, makeString("Error migrating IndexRecords table ("_s, m_sqliteDB->lastError(), ") - "_s, span(m_sqliteDB->lastErrorMsg())) }; + return IDBError { ExceptionCode::UnknownError, makeString("Error migrating IndexRecords table ("_s, m_sqliteDB->lastError(), ") - "_s, unsafeSpan(m_sqliteDB->lastErrorMsg())) }; if (!m_sqliteDB->executeCommand("DROP TABLE IndexRecords"_s)) - return IDBError { ExceptionCode::UnknownError, makeString("Error dropping IndexRecords table ("_s, m_sqliteDB->lastError(), ") - "_s, span(m_sqliteDB->lastErrorMsg())) }; + return IDBError { ExceptionCode::UnknownError, makeString("Error dropping IndexRecords table ("_s, m_sqliteDB->lastError(), ") - "_s, unsafeSpan(m_sqliteDB->lastErrorMsg())) }; if (!m_sqliteDB->executeCommand("ALTER TABLE _Temp_IndexRecords RENAME TO IndexRecords"_s)) - return IDBError { ExceptionCode::UnknownError, makeString("Error renaming temporary IndexRecords table ("_s, m_sqliteDB->lastError(), ") - "_s, span(m_sqliteDB->lastErrorMsg())) }; + return IDBError { ExceptionCode::UnknownError, makeString("Error renaming temporary IndexRecords table ("_s, m_sqliteDB->lastError(), ") - "_s, unsafeSpan(m_sqliteDB->lastErrorMsg())) }; transaction.commit(); @@ -383,10 +383,10 @@ IDBError SQLiteIDBBackingStore::ensureValidIndexRecordsIndex() return IDBError { }; if (!m_sqliteDB->executeCommand("DROP INDEX IF EXISTS IndexRecordsIndex"_s)) - return IDBError { ExceptionCode::UnknownError, makeString("Error dropping IndexRecordsIndex index ("_s, m_sqliteDB->lastError(), ") - "_s, span(m_sqliteDB->lastErrorMsg())) }; + return IDBError { ExceptionCode::UnknownError, makeString("Error dropping IndexRecordsIndex index ("_s, m_sqliteDB->lastError(), ") - "_s, unsafeSpan(m_sqliteDB->lastErrorMsg())) }; if (!m_sqliteDB->executeCommand(IndexRecordsIndexSchema)) - return IDBError { ExceptionCode::UnknownError, makeString("Error creating IndexRecordsIndex index ("_s, m_sqliteDB->lastError(), ") - "_s, span(m_sqliteDB->lastErrorMsg())) }; + return IDBError { ExceptionCode::UnknownError, makeString("Error creating IndexRecordsIndex index ("_s, m_sqliteDB->lastError(), ") - "_s, unsafeSpan(m_sqliteDB->lastErrorMsg())) }; return IDBError { }; } @@ -401,10 +401,10 @@ IDBError SQLiteIDBBackingStore::ensureValidIndexRecordsRecordIndex() return IDBError { }; if (!m_sqliteDB->executeCommand("DROP INDEX IF EXISTS IndexRecordsRecordIndex"_s)) - return IDBError { ExceptionCode::UnknownError, makeString("Error dropping IndexRecordsRecordIndex index ("_s, m_sqliteDB->lastError(), ") - "_s, span(m_sqliteDB->lastErrorMsg())) }; + return IDBError { ExceptionCode::UnknownError, makeString("Error dropping IndexRecordsRecordIndex index ("_s, m_sqliteDB->lastError(), ") - "_s, unsafeSpan(m_sqliteDB->lastErrorMsg())) }; if (!m_sqliteDB->executeCommand(v1IndexRecordsRecordIndexSchema)) - return IDBError { ExceptionCode::UnknownError, makeString("Error creating IndexRecordsRecordIndex index ("_s, m_sqliteDB->lastError(), ") - "_s, span(m_sqliteDB->lastErrorMsg())) }; + return IDBError { ExceptionCode::UnknownError, makeString("Error creating IndexRecordsRecordIndex index ("_s, m_sqliteDB->lastError(), ") - "_s, unsafeSpan(m_sqliteDB->lastErrorMsg())) }; return IDBError { }; } diff --git a/Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp b/Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp index d9c85af5c3a2d..2220c492cf5e6 100644 --- a/Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp +++ b/Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp @@ -225,7 +225,7 @@ void PeerConnectionBackend::handleLogMessage(const WTFLogChannel& channel, WTFLo // Check if the third message is a multi-lines string, concatenating such message would look ugly in log events. if (values.size() >= 3 && values[2].value.find("\r\n"_s) != notFound) - event = generateJSONLogEvent(MessageLogEvent { values[1].value, { values[2].value.span8() } }, false); + event = generateJSONLogEvent(MessageLogEvent { values[1].value, { byteCast(values[2].value.span8()) } }, false); else { StringBuilder builder; for (auto& value : values.subvector(1)) diff --git a/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformerCocoa.cpp b/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformerCocoa.cpp index 06c0d81e7d56a..a866431b4184a 100644 --- a/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformerCocoa.cpp +++ b/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformerCocoa.cpp @@ -35,12 +35,12 @@ namespace WebCore { ExceptionOr> RTCRtpSFrameTransformer::computeSaltKey(const Vector& rawKey) { - return deriveHDKFSHA256Bits(rawKey.subspan(0, 16), "SFrame10"_span, "salt"_span, 96); + return deriveHDKFSHA256Bits(rawKey.subspan(0, 16), byteCast("SFrame10"_span), byteCast("salt"_span), 96); } static ExceptionOr> createBaseSFrameKey(const Vector& rawKey) { - return deriveHDKFSHA256Bits(rawKey.subspan(0, 16), "SFrame10"_span, "key"_span, 128); + return deriveHDKFSHA256Bits(rawKey.subspan(0, 16), byteCast("SFrame10"_span), byteCast("key"_span), 128); } ExceptionOr> RTCRtpSFrameTransformer::computeAuthenticationKey(const Vector& rawKey) @@ -49,7 +49,7 @@ ExceptionOr> RTCRtpSFrameTransformer::computeAuthenticationKey(c if (key.hasException()) return key; - return deriveHDKFSHA256Bits(key.returnValue().subspan(0, 16), "SFrame10 AES CM AEAD"_span, "auth"_span, 256); + return deriveHDKFSHA256Bits(key.returnValue().subspan(0, 16), byteCast("SFrame10 AES CM AEAD"_span), byteCast("auth"_span), 256); } ExceptionOr> RTCRtpSFrameTransformer::computeEncryptionKey(const Vector& rawKey) @@ -58,7 +58,7 @@ ExceptionOr> RTCRtpSFrameTransformer::computeEncryptionKey(const if (key.hasException()) return key; - return deriveHDKFSHA256Bits(key.returnValue().subspan(0, 16), "SFrame10 AES CM AEAD"_span, "enc"_span, 128); + return deriveHDKFSHA256Bits(key.returnValue().subspan(0, 16), byteCast("SFrame10 AES CM AEAD"_span), byteCast("enc"_span), 128); } ExceptionOr> RTCRtpSFrameTransformer::decryptData(std::span data, const Vector& iv, const Vector& key) diff --git a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerDataChannelHandler.cpp b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerDataChannelHandler.cpp index 18ba69021e0ab..d00233411525b 100644 --- a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerDataChannelHandler.cpp +++ b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerDataChannelHandler.cpp @@ -30,6 +30,7 @@ #include "RTCPriorityType.h" #include +#include GST_DEBUG_CATEGORY(webkit_webrtc_data_channel_debug); #define GST_CAT_DEFAULT webkit_webrtc_data_channel_debug @@ -111,7 +112,7 @@ GStreamerDataChannelHandler::GStreamerDataChannelHandler(GRefPtronMessageData(bytes); }), this); g_signal_connect_swapped(m_channel.get(), "on-message-string", G_CALLBACK(+[](GStreamerDataChannelHandler* handler, const char* message) { - handler->onMessageString(message); + handler->onMessageString(CStringView::unsafeFromUTF8(message)); }), this); g_signal_connect_swapped(m_channel.get(), "on-error", G_CALLBACK(+[](GStreamerDataChannelHandler* handler, GError* error) { handler->onError(error); @@ -293,8 +294,8 @@ bool GStreamerDataChannelHandler::checkState() } #ifndef GST_DISABLE_GST_DEBUG - GUniquePtr stateString(g_enum_to_string(GST_TYPE_WEBRTC_DATA_CHANNEL_STATE, channelState)); - DC_DEBUG("Dispatching state change to %s on channel %p", stateString.get(), m_channel.get()); + auto stateString = GMallocString::unsafeAdoptFromUTF8(g_enum_to_string(GST_TYPE_WEBRTC_DATA_CHANNEL_STATE, channelState)); + DC_DEBUG("Dispatching state change to %s on channel %p", stateString.utf8(), m_channel.get()); #endif postTask([client = m_client, state] { if (!*client) { @@ -366,26 +367,26 @@ void GStreamerDataChannelHandler::onMessageData(GBytes* bytes) }); } -void GStreamerDataChannelHandler::onMessageString(const char* message) +void GStreamerDataChannelHandler::onMessageString(CStringView message) { Locker locker { m_clientLock }; - DC_TRACE("Incoming string: %s", message); + DC_TRACE("Incoming string: %s", message.utf8()); if (!m_client) { DC_DEBUG("No client yet, keeping as buffered message"); - m_pendingMessages.append(String::fromUTF8(message)); + m_pendingMessages.append(String(message.span())); return; } if (!*m_client) return; - DC_DEBUG("Dispatching string of size %zu", strlen(message)); - postTask([client = m_client, string = String::fromUTF8(message)] { + DC_DEBUG("Dispatching string of size %zu", message.lengthInBytes()); + postTask([client = m_client, string = String(message.span())] mutable { if (!*client) return; - client.value()->didReceiveStringData(string); + client.value()->didReceiveStringData(WTFMove(string)); }); } diff --git a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerDataChannelHandler.h b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerDataChannelHandler.h index 8396b6b20eefc..a3d787dbcae98 100644 --- a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerDataChannelHandler.h +++ b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerDataChannelHandler.h @@ -60,7 +60,7 @@ class GStreamerDataChannelHandler final : public RTCDataChannelHandler { void close() final; void onMessageData(GBytes*); - void onMessageString(const char*); + void onMessageString(CStringView); void onError(GError*); void onClose(); diff --git a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerDtlsTransportBackend.cpp b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerDtlsTransportBackend.cpp index ce40b272f6054..dd8aa58839a35 100644 --- a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerDtlsTransportBackend.cpp +++ b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerDtlsTransportBackend.cpp @@ -25,6 +25,7 @@ #include "GStreamerIceTransportBackend.h" #include "GStreamerWebRTCUtils.h" #include +#include #include namespace WebCore { @@ -68,8 +69,8 @@ void GStreamerDtlsTransportBackendObserver::stateChanged() g_object_get(m_backend.get(), "state", &state, nullptr); #ifndef GST_DISABLE_GST_DEBUG - GUniquePtr desc(g_enum_to_string(GST_TYPE_WEBRTC_DTLS_TRANSPORT_STATE, state)); - GST_DEBUG_OBJECT(m_backend.get(), "DTLS transport state changed to %s", desc.get()); + auto desc = GMallocString::unsafeAdoptFromUTF8(g_enum_to_string(GST_TYPE_WEBRTC_DTLS_TRANSPORT_STATE, state)); + GST_DEBUG_OBJECT(m_backend.get(), "DTLS transport state changed to %s", desc.utf8()); #endif Vector> certificates; @@ -80,12 +81,11 @@ void GStreamerDtlsTransportBackendObserver::stateChanged() GUniqueOutPtr remoteCertificate; GUniqueOutPtr certificate; g_object_get(m_backend.get(), "remote-certificate", &remoteCertificate.outPtr(), "certificate", &certificate.outPtr(), nullptr); - if (remoteCertificate) - certificates.append(JSC::ArrayBuffer::create(span8(remoteCertificate.get()))); + certificates.append(JSC::ArrayBuffer::create(byteCast(span8(remoteCertificate.get())))); if (certificate) - certificates.append(JSC::ArrayBuffer::create(span8(certificate.get()))); + certificates.append(JSC::ArrayBuffer::create(byteCast(span8(certificate.get())))); } m_client->onStateChanged(toRTCDtlsTransportState(state), WTFMove(certificates)); }); diff --git a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerIceAgent.cpp b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerIceAgent.cpp new file mode 100644 index 0000000000000..20654d469f6d9 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerIceAgent.cpp @@ -0,0 +1,821 @@ +/* + * Copyright (C) 2025 Igalia S.L. All rights reserved. + * Copyright (C) 2025 Metrological Group B.V. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "GStreamerIceAgent.h" + +#if USE(GSTREAMER_WEBRTC) && USE(LIBRICE) + +#include "GRefPtrGStreamer.h" +#include "GRefPtrRice.h" +#include "GStreamerIceStream.h" +#include "GStreamerWebRTCUtils.h" +#include "GUniquePtrRice.h" +#include "NotImplemented.h" +#include "RiceGioBackend.h" +#include "RiceUtilities.h" +#include "ScriptExecutionContext.h" +#include "SharedMemory.h" +#include "SocketProvider.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace WTF; +using namespace WebCore; + +using WebKitGstRiceStream = struct _WebKitGstRiceStream { + WTF_MAKE_NONCOPYABLE(_WebKitGstRiceStream); + WTF_MAKE_STRUCT_TZONE_ALLOCATED(_WebKitGstRiceStream); + + _WebKitGstRiceStream(unsigned streamId, GRefPtr&& stream) + : riceStreamId(streamId) + , stream(WTFMove(stream)) + { + } + + unsigned riceStreamId; + GRefPtr stream; +}; + +using StreamHashMap = HashMap, WTF::IntHash, WTF::UnsignedWithZeroKeyHashTraits>; + +typedef struct _WebKitGstIceAgentPrivate { + ~_WebKitGstIceAgentPrivate() + { + if (onCandidateNotify) + onCandidateNotify(onCandidateData); + + if (recvSource) + g_source_destroy(recvSource.get()); + + for (const auto& [sessionId, stream] : streams) + iceBackend->finalizeStream(stream->stream->stream_id); + } + + RefPtr backendClient; + Markable identifier; + RefPtr socketProvider; + GRefPtr agent; + + StreamHashMap streams; + + RefPtr runLoop; + + Atomic agentIsClosed; + GRefPtr closePromise; + + GstWebRTCICEOnCandidateFunc onCandidate; + gpointer onCandidateData; + GDestroyNotify onCandidateNotify; + + RefPtr iceBackend; + + String stunServer; + String turnServer; + + HashSet turnServers; + Vector> turnConfigs; + + GRefPtr recvSource; +} WebKitGstIceAgentPrivate; + +typedef struct _WebKitGstIceAgent { + GstWebRTCICE parent; + WebKitGstIceAgentPrivate* priv; +} WebKitGstIceAgent; + +typedef struct _WebKitGstIceAgentClass { + GstWebRTCICEClass parentClass; +} WebKitGstIceAgentClass; + +GST_DEBUG_CATEGORY(webkit_webrtc_rice_debug); +#define GST_CAT_DEFAULT webkit_webrtc_rice_debug + +WEBKIT_DEFINE_TYPE_WITH_CODE(WebKitGstIceAgent, webkit_gst_webrtc_ice_backend, GST_TYPE_WEBRTC_ICE, GST_DEBUG_CATEGORY_INIT(webkit_webrtc_rice_debug, "webkitwebrtcrice", 0, "WebRTC Rice ICE backend")) + +using namespace WebCore; + +static void webkitGstWebRTCIceAgentSetOnIceCandidate(GstWebRTCICE* ice, GstWebRTCICEOnCandidateFunc callback, gpointer userData, GDestroyNotify notifyCallback) +{ + auto backend = WEBKIT_GST_WEBRTC_ICE_BACKEND(ice); + auto priv = backend->priv; + if (priv->onCandidateNotify) + priv->onCandidateNotify(priv->onCandidateData); + priv->onCandidateNotify = notifyCallback; + priv->onCandidateData = userData; + priv->onCandidate = callback; +} + +static void webkitGstWebRTCIceAgentSetForceRelay(GstWebRTCICE*, gboolean) +{ + GST_FIXME("Not implemented yet."); +} + +static void webkitGstWebRTCIceAgentSetRiceStunServer(WebKitGstIceAgent* agent, StringView host, uint16_t port) +{ + const auto& iceAgent = agent->priv->agent; + if (!iceAgent) [[unlikely]] + return; + + auto address = makeString(host, ':', port); + auto addressString = address.ascii(); + GUniquePtr stunAddress(rice_address_new_from_string(addressString.data())); + if (!stunAddress) { + GST_WARNING_OBJECT(agent, "Unable to make use of STUN server %s", addressString.data()); + return; + } + + rice_agent_add_stun_server(iceAgent.get(), RICE_TRANSPORT_TYPE_UDP, stunAddress.get()); + rice_agent_add_stun_server(iceAgent.get(), RICE_TRANSPORT_TYPE_TCP, stunAddress.get()); +} + +static void webkitGstWebRTCIceAgentSetStunServer(GstWebRTCICE* ice, const gchar* uri) +{ + auto backend = WEBKIT_GST_WEBRTC_ICE_BACKEND(ice); + backend->priv->stunServer = String::fromUTF8(uri); + GST_INFO_OBJECT(ice, "Setting STUN server address to %s", uri); + + URL url(backend->priv->stunServer); + ASSERT(url.isValid()); + const auto& host = url.host(); + auto port = url.port().value_or(3478); + + if (URL::hostIsIPAddress(host)) { + webkitGstWebRTCIceAgentSetRiceStunServer(backend, host, port); + return; + } + + backend->priv->iceBackend->resolveAddress(host.toString(), [weakAgent = GThreadSafeWeakPtr(backend), port](ExceptionOr&& result) mutable { + auto agent = weakAgent.get(); + if (!agent) [[unlikely]] + return; + if (result.hasException()) { + GST_WARNING_OBJECT(agent.get(), "Unable to configure STUN server on ICE agent: %s", result.exception().message().utf8().data()); + return; + } + + auto address = result.returnValue(); + auto addressString = address.ascii(); + GST_DEBUG_OBJECT(agent.get(), "STUN address resolved to %s", addressString.data()); + webkitGstWebRTCIceAgentSetRiceStunServer(agent.get(), address, port); + }); +} + +static gchar* webkitGstWebRTCIceAgentGetStunServer(GstWebRTCICE* ice) +{ + auto backend = WEBKIT_GST_WEBRTC_ICE_BACKEND(ice); + return g_strdup(backend->priv->stunServer.utf8().data()); +} + +enum class ValidationErrorCode { + ParseError, + UnknownScheme, + UnknownTransport, + UnknownParameter, + MissingUsername, + MissingPassword +}; + +struct URLValidationError { + ValidationErrorCode code; + String data; +}; + +Expected validateTurnServerURL(const String& turnUrl) +{ + URL url(turnUrl); + + if (!url.isValid()) + return makeUnexpected(URLValidationError { ValidationErrorCode::ParseError, { } }); + + bool isTLS = false; + if (url.protocolIs("turns"_s)) + isTLS = true; + else if (url.protocol() != "turn"_s) + return makeUnexpected(URLValidationError { ValidationErrorCode::UnknownScheme, url.protocol().toStringWithoutCopying() }); + + for (const auto& [key, value] : queryParameters(url)) { + if (key != "transport"_s) + return makeUnexpected(URLValidationError { ValidationErrorCode::UnknownParameter, key }); + if (value != "udp"_s && value != "tcp"_s) + return makeUnexpected(URLValidationError { ValidationErrorCode::UnknownTransport, value }); + } + + if (url.user().isEmpty()) + return makeUnexpected(URLValidationError { ValidationErrorCode::MissingUsername, { } }); + if (url.password().isEmpty()) + return makeUnexpected(URLValidationError { ValidationErrorCode::MissingPassword, { } }); + + if (url.port()) + return url; + + if (isTLS) + url.setPort(5349); + else + url.setPort(3478); + + return url; +} + +static void webkitGstWebRTCIceAgentAddRiceTurnServer(WebKitGstIceAgent* agent, const String& address, bool isTurns, const String& user, const String& password, const std::array& relays, unsigned nRelay) +{ + const auto& iceAgent = agent->priv->agent; + if (!iceAgent) [[unlikely]] + return; + + GUniquePtr riceAddress(rice_address_new_from_string(address.ascii().data())); + GUniquePtr credentials(rice_credentials_new(g_strdup(user.utf8().data()), g_strdup(password.utf8().data()))); + GRefPtr tlsConfig; + if (isTurns) + tlsConfig = adoptGRef(rice_tls_config_new_rustls_with_ip(riceAddress.get())); + + auto family = rice_address_get_family(riceAddress.get()); + for (unsigned i = 0; i < nRelay; i++) { + auto config = adoptGRef(rice_turn_config_new(relays[i], riceAddress.get(), credentials.get(), 1, &family, tlsConfig.get())); + agent->priv->turnConfigs.append(WTFMove(config)); + } +} + +static void addTurnServer(WebKitGstIceAgent* agent, const URL& url) +{ + GST_INFO_OBJECT(agent, "Adding TURN server %s", url.string().utf8().data()); + if (!url.host()) + return; + + std::array relays = { static_cast(0), }; + unsigned nRelay = 0; + bool isTurns = url.protocolIs("turns"_s); + StringView transport; + for (const auto& [key, value] : queryParameters(url)) { + if (key == "transport"_s) { + transport = value; + break; + } + } + if (!transport || transport == "udp"_s) + relays[nRelay++] = RICE_TRANSPORT_TYPE_UDP; + if (!transport || transport == "tcp"_s) + relays[nRelay++] = RICE_TRANSPORT_TYPE_TCP; + + RELEASE_ASSERT(url.port()); + auto port = url.port().value(); + + const auto& host = url.host(); + if (URL::hostIsIPAddress(host)) { + webkitGstWebRTCIceAgentAddRiceTurnServer(agent, url.hostAndPort(), isTurns, url.user(), url.password(), relays, nRelay); + return; + } + + agent->priv->iceBackend->resolveAddress(url.host().toString(), [weakAgent = GThreadSafeWeakPtr(agent), isTurns, port, nRelay, user = url.user(), password = url.password(), relays = WTFMove(relays)](ExceptionOr&& result) mutable { + auto agent = weakAgent.get(); + if (!agent) [[unlikely]] + return; + if (result.hasException()) { + GST_WARNING_OBJECT(agent.get(), "Unable to configure TURN server on ICE agent: %s", result.exception().message().utf8().data()); + return; + } + + auto turnAddress = makeString(result.returnValue(), ':', port); + GST_DEBUG_OBJECT(agent.get(), "TURN address resolved to %s", turnAddress.ascii().data()); + webkitGstWebRTCIceAgentAddRiceTurnServer(agent.get(), turnAddress, isTurns, user, password, relays, nRelay); + }); +} + +static gboolean webkitGstWebRTCIceAgentAddTurnServer(GstWebRTCICE* ice, const gchar* uri) +{ + auto backend = WEBKIT_GST_WEBRTC_ICE_BACKEND(ice); + if (!backend->priv->iceBackend) + return FALSE; + + auto validationResult = validateTurnServerURL(String::fromUTF8(uri)); + if (!validationResult.has_value()) { + GST_ERROR_OBJECT(ice, "Error validating TURN URI: %s", validationResult.error().data.utf8().data()); + return FALSE; + } + auto url = *validationResult; + auto wasAdded = backend->priv->turnServers.add(url).isNewEntry; + if (!wasAdded) { + GST_DEBUG_OBJECT(ice, "%s was already registered, no need to add it again", uri); + return FALSE; + } + + addTurnServer(backend, url); + return TRUE; +} + +static void webkitGstWebRTCIceAgentSetTurnServer(GstWebRTCICE* ice, const gchar* uri) +{ + auto backend = WEBKIT_GST_WEBRTC_ICE_BACKEND(ice); + if (!backend->priv->iceBackend) + return; + + auto turnUrl = String::fromUTF8(uri); + auto validationResult = validateTurnServerURL(turnUrl); + if (!validationResult.has_value()) { + GST_ERROR_OBJECT(ice, "Error validating TURN URI: %s", validationResult.error().data.utf8().data()); + return; + } + backend->priv->turnServer = WTFMove(turnUrl); +} + +static gchar* webkitGstWebRTCIceAgentGetTurnServer(GstWebRTCICE* ice) +{ + auto backend = WEBKIT_GST_WEBRTC_ICE_BACKEND(ice); + return g_strdup(backend->priv->turnServer.utf8().data()); +} + +static GstWebRTCICEStream* webkitGstWebRTCIceAgentAddStream(GstWebRTCICE* ice, guint sessionId) +{ + auto backend = WEBKIT_GST_WEBRTC_ICE_BACKEND(ice); + if (!backend->priv->iceBackend) + return nullptr; + + if (backend->priv->streams.contains(sessionId)) { + GST_ERROR_OBJECT(ice, "Stream already added for session %u", sessionId); + return nullptr; + } + + auto riceStream = adoptGRef(rice_agent_add_stream(backend->priv->agent.get())); + auto streamId = static_cast(rice_stream_get_id(riceStream.get())); + [[maybe_unused]] auto component = adoptGRef(rice_stream_add_component(riceStream.get())); + + auto stream = adoptGRef(GST_WEBRTC_ICE_STREAM(webkitGstWebRTCCreateIceStream(backend, WTFMove(riceStream)))); + backend->priv->streams.add(sessionId, WTF::makeUnique(streamId, WTFMove(stream))); + auto item = backend->priv->streams.find(sessionId); + + // Until GStreamer 1.26.10 the GstWebRTC transport stream wasn't complying with the transfer full annotation for this function. + // https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10312 + if (gst_check_version(1, 26, 10)) + return item->value->stream.ref(); + return item->value->stream.get(); +} + +static gboolean webkitGstWebRTCIceAgentGetIsController(GstWebRTCICE* ice) +{ + auto backend = WEBKIT_GST_WEBRTC_ICE_BACKEND(ice); + return static_cast(rice_agent_get_controlling(backend->priv->agent.get())); +} + +static void webkitGstWebRTCIceAgentSetIsController(GstWebRTCICE*, gboolean) +{ + GST_FIXME("Not implemented yet."); +} + +struct CandidateAddress { + String prefix; + String address; + String suffix; +}; + +static Expected getCandidateAddress(StringView candidate) +{ + if (!candidate.startsWith("a=candidate:"_s)) + return makeUnexpected(ExceptionData { ExceptionCode::NotSupportedError, "Candidate does not start with \"a=candidate:\""_s }); + + auto tokens = candidate.toStringWithoutCopying().substring(12).split(' '); + if (tokens.size() < 6) + return makeUnexpected(ExceptionData { ExceptionCode::DataError, makeString("Candidate \""_s, candidate, "\" tokenization resulted in not enough tokens"_s) }); + + CandidateAddress result; + result.address = tokens[4]; + + StringBuilder prefixBuilder; + for (unsigned i = 0; i < 4; i++) + prefixBuilder.append(tokens[i]); + result.prefix = prefixBuilder.toString(); + + StringBuilder suffixBuilder; + for (unsigned i = 5; i < tokens.size(); i++) + suffixBuilder.append(tokens[i]); + result.suffix = suffixBuilder.toString(); + return result; +} + +static void webkitGstWebRTCIceAgentAddCandidate(GstWebRTCICE* ice, GstWebRTCICEStream* iceStream, const gchar* candidateSdp, GstPromise* promise) +{ + GRefPtr riceStream = webkitGstWebRTCIceStreamGetRiceStream(WEBKIT_GST_WEBRTC_ICE_STREAM(iceStream)); + if (!riceStream) [[unlikely]] { + GST_DEBUG_OBJECT(ice, "ICE stream not found"); + gst_promise_reply(promise, nullptr); + return; + } + if (!candidateSdp) { + GST_DEBUG_OBJECT(ice, "Signaling end-of-candidates"); + rice_stream_end_of_remote_candidates(riceStream.get()); + gst_promise_reply(promise, nullptr); + return; + } + + GST_DEBUG_OBJECT(ice, "Processing SDP ICE candidate: %s", candidateSdp); + auto backend = WEBKIT_GST_WEBRTC_ICE_BACKEND(ice); + GUniquePtr candidate(rice_candidate_new_from_sdp_string(candidateSdp)); + if (candidate) { + GST_DEBUG_OBJECT(ice, "Adding remote candidate: %s", candidateSdp); + rice_stream_add_remote_candidate(riceStream.get(), candidate.get()); + g_main_context_wakeup(backend->priv->runLoop->mainContext()); + gst_promise_reply(promise, nullptr); + return; + } + + GST_DEBUG_OBJECT(ice, "Failed to build RiceCandidate from SDP, it might contain a FQDN. Attempting address resolution"); + auto localAddressResult = getCandidateAddress(StringView::fromLatin1(candidateSdp)); + if (!localAddressResult.has_value()) { + auto errorMessage = makeString("Failed to retrieve address from candidate: "_s, localAddressResult.error().message); + auto errorMessageString = errorMessage.utf8(); + GST_ERROR_OBJECT(ice, "%s", errorMessageString.data()); + GUniquePtr error(g_error_new(GST_WEBRTC_ERROR, GST_WEBRTC_ERROR_INTERNAL_FAILURE, "%s", errorMessageString.data())); + gst_promise_reply(promise, gst_structure_new("application/x-gst-promise", "error", G_TYPE_ERROR, error.get(), nullptr)); + return; + } + + auto localAddress = localAddressResult.value(); + if (!localAddress.address.endsWith(".local"_s)) { + auto errorMessage = makeString("Candidate address \""_s, localAddress.address, "\" does not end with '.local'"_s); + auto errorMessageString = errorMessage.utf8(); + GST_ERROR_OBJECT(ice, "%s", errorMessageString.data()); + GUniquePtr error(g_error_new(GST_WEBRTC_ERROR, GST_WEBRTC_ERROR_INTERNAL_FAILURE, "%s", errorMessageString.data())); + gst_promise_reply(promise, gst_structure_new("application/x-gst-promise", "error", G_TYPE_ERROR, error.get(), nullptr)); + return; + } + + auto iceBackend = backend->priv->iceBackend; + if (!iceBackend) [[unlikely]] { + gst_promise_reply(promise, nullptr); + return; + } + + iceBackend->resolveAddress(WTFMove(localAddress.address), [promise = GRefPtr(promise), riceStream = WTFMove(riceStream), prefix = WTFMove(localAddress.prefix), suffix = WTFMove(localAddress.suffix), backend](auto&& result) mutable { + if (result.hasException()) { + auto& errorMessage = result.exception().message(); + auto errorMessageString = errorMessage.utf8(); + GST_ERROR("%s", errorMessageString.data()); + GUniquePtr error(g_error_new(GST_WEBRTC_ERROR, GST_WEBRTC_ERROR_INTERNAL_FAILURE, "%s", errorMessageString.data())); + + gst_promise_reply(promise.get(), gst_structure_new("application/x-gst-promise", "error", G_TYPE_ERROR, error.get(), nullptr)); + return; + } + + auto newCandidateSdp = makeString(prefix, ' ', result.returnValue(), ' ', suffix); + auto newCandidateSdpString = newCandidateSdp.utf8(); + GST_DEBUG("SDP for resolved address: %s", newCandidateSdpString.data()); + GUniquePtr newCandidate(rice_candidate_new_from_sdp_string(newCandidateSdpString.data())); + if (newCandidate) { + rice_stream_add_remote_candidate(riceStream.get(), newCandidate.get()); + gst_promise_reply(promise.get(), nullptr); + g_main_context_wakeup(backend->priv->runLoop->mainContext()); + } else { + auto errorMessage = "Unable to create Rice candidate from SDP"_s; + GST_ERROR("%s", errorMessage.characters()); + GUniquePtr error(g_error_new(GST_WEBRTC_ERROR, GST_WEBRTC_ERROR_INTERNAL_FAILURE, "%s", errorMessage.characters())); + gst_promise_reply(promise.get(), gst_structure_new("application/x-gst-promise", "error", G_TYPE_ERROR, error.get(), nullptr)); + } + }); +} + +static GstWebRTCICETransport* webkitGstWebRTCIceAgentFindTransport(GstWebRTCICE*, GstWebRTCICEStream* stream, GstWebRTCICEComponent component) +{ + return webkitGstWebRTCIceStreamFindTransport(stream, component); +} + +static void webkitGstWebRTCIceAgentSetTos(GstWebRTCICE*, GstWebRTCICEStream*, guint) +{ + GST_FIXME("Not implemented yet."); +} + +static gboolean webkitGstWebRTCIceAgentSetLocalCredentials(GstWebRTCICE*, GstWebRTCICEStream* stream, const gchar* ufrag, const gchar* pwd) +{ + webkitGstWebRTCIceStreamSetLocalCredentials(WEBKIT_GST_WEBRTC_ICE_STREAM(stream), String::fromLatin1(ufrag), String::fromLatin1(pwd)); + return TRUE; +} + +static gboolean webkitGstWebRTCIceAgentSetRemoteCredentials(GstWebRTCICE*, GstWebRTCICEStream* stream, const gchar* ufrag, const gchar* pwd) +{ + webkitGstWebRTCIceStreamSetRemoteCredentials(WEBKIT_GST_WEBRTC_ICE_STREAM(stream), String::fromLatin1(ufrag), String::fromLatin1(pwd)); + return TRUE; +} + +static gboolean webkitGstWebRTCIceAgentGatherCandidates(GstWebRTCICE*, GstWebRTCICEStream* stream) +{ + return webkitGstWebRTCIceStreamGatherCandidates(WEBKIT_GST_WEBRTC_ICE_STREAM(stream)); +} + +static void webkitGstWebRTCIceAgentSetHttpProxy(GstWebRTCICE*, const gchar*) +{ + GST_FIXME("Not implemented yet."); +} + +static gchar* webkitGstWebRTCIceAgentGetHttpProxy(GstWebRTCICE*) +{ + GST_FIXME("Not implemented yet."); + return nullptr; +} + +static ASCIILiteral getRelayProtocol(WebKitGstIceAgent* agent) +{ + if (agent->priv->turnServer.isEmpty()) + return "none"_s; + + URL url(agent->priv->turnServer); + if (url.protocolIs("turns"_s)) + return "tls"_s; + + ASSERT(url.protocolIs("turn"_s)); + StringView transport; + for (const auto& [key, value] : queryParameters(url)) { + if (key == "transport"_s) { + transport = value; + break; + } + } + if (!transport || transport == "udp"_s) + return "udp"_s; + if (!transport || transport == "tcp"_s) + return "tcp"_s; + + return "none"_s; +} + +static gboolean webkitGstWebRTCIceAgentGetSelectedPair(GstWebRTCICE* ice, GstWebRTCICEStream* stream, GstWebRTCICECandidateStats** localStats, GstWebRTCICECandidateStats** remoteStats) +{ + if (!stream) + return FALSE; + + auto result = webkitGstWebRTCIceStreamGetSelectedPair(WEBKIT_GST_WEBRTC_ICE_STREAM(stream), localStats, remoteStats); + if (!result) + return result; + + auto backend = WEBKIT_GST_WEBRTC_ICE_BACKEND(ice); + auto relayProtocol = getRelayProtocol(backend); + (*localStats)->relay_proto = relayProtocol; + (*remoteStats)->relay_proto = relayProtocol; + return TRUE; +} + +void webkitGstWebRTCIceAgentClosed(WebKitGstIceAgent* agent) +{ + agent->priv->agentIsClosed.exchange(true); + agent->priv->streams.clear(); + + if (!agent->priv->closePromise) + return; + + gst_promise_reply(agent->priv->closePromise.get(), nullptr); + agent->priv->closePromise.clear(); +} + +#if GST_CHECK_VERSION(1, 27, 0) +static void webkitGstWebRTCIceAgentClose(GstWebRTCICE* ice, GstPromise* promise) +{ + auto backend = WEBKIT_GST_WEBRTC_ICE_BACKEND(ice); + + auto isClosed = backend->priv->agentIsClosed.load(); + if (isClosed) + return; + + bool shouldWait = promise == nullptr; + backend->priv->closePromise = adoptGRef(promise); + auto now = WTF::MonotonicTime::now().secondsSinceEpoch(); + rice_agent_close(backend->priv->agent.get(), now.nanoseconds()); + webkitGstWebRTCIceAgentWakeup(backend); + + isClosed = backend->priv->agentIsClosed.load(); + if (!shouldWait || isClosed) + return; + + while (!isClosed) { + g_main_context_iteration(backend->priv->runLoop->mainContext(), FALSE); + isClosed = backend->priv->agentIsClosed.load(); + } +} +#endif + +static void webkitGstWebRTCIceAgentConstructed(GObject* object) +{ + G_OBJECT_CLASS(webkit_gst_webrtc_ice_backend_parent_class)->constructed(object); + + auto backend = WEBKIT_GST_WEBRTC_ICE_BACKEND(object); + auto priv = backend->priv; + + priv->agentIsClosed.exchange(false); + + static Atomic counter = 0; + auto id = counter.load(); + auto threadName = makeString("webrtc-rice-"_s, id); + auto threadNameCString = threadName.ascii(); + counter.exchangeAdd(1); + + static HashSet threadNames; + threadNames.add(threadNameCString); + + // FIXME: We are abusing ASCIILiteral here, it would be good to have String support for the + // RunLoop name. + priv->runLoop = RunLoop::create(ASCIILiteral::fromLiteralUnsafe(threadNameCString.data())); + priv->agent = adoptGRef(rice_agent_new(true, true)); +} + +static void findStreamAndApply(const StreamHashMap& streams, unsigned streamId, Function callback) +{ + for (auto& riceStream : streams.values()) { + if (riceStream->riceStreamId != streamId) + continue; + + callback(WEBKIT_GST_WEBRTC_ICE_STREAM(riceStream->stream.get())); + return; + } +} + +static bool webkitGstWebRTCIceAgentConfigure(WebKitGstIceAgent* backend, RefPtr&& socketProvider, ScriptExecutionContextIdentifier identifier) +{ + auto priv = backend->priv; + priv->socketProvider = WTFMove(socketProvider); + priv->identifier = identifier; + priv->backendClient = RiceBackendClient::create(); + priv->iceBackend = priv->socketProvider->createRiceBackend(*priv->backendClient); + if (!priv->iceBackend) + return false; + + priv->backendClient->setIncomingDataCallback([weakThis = GThreadSafeWeakPtr(backend)](unsigned streamId, RTCIceProtocol protocol, String&& from, String&& to, SharedMemory::Handle&& data) mutable { + auto self = weakThis.get(); + if (!self) + return; + findStreamAndApply(self->priv->streams, streamId, [protocol, from = WTFMove(from), to = WTFMove(to), data = WTFMove(data)](const auto* stream) mutable { + webkitGstWebRTCIceStreamHandleIncomingData(stream, protocol, WTFMove(from), WTFMove(to), WTFMove(data)); + }); + }); + + priv->recvSource = agentSourceNew(GThreadSafeWeakPtr(backend)); + g_source_attach(priv->recvSource.get(), priv->runLoop->mainContext()); + return true; +} + +static void webkit_gst_webrtc_ice_backend_class_init(WebKitGstIceAgentClass* klass) +{ + auto gobjectClass = G_OBJECT_CLASS(klass); + gobjectClass->constructed = webkitGstWebRTCIceAgentConstructed; + + auto iceClass = GST_WEBRTC_ICE_CLASS(klass); + iceClass->set_on_ice_candidate = webkitGstWebRTCIceAgentSetOnIceCandidate; + iceClass->set_force_relay = webkitGstWebRTCIceAgentSetForceRelay; + iceClass->set_stun_server = webkitGstWebRTCIceAgentSetStunServer; + iceClass->get_stun_server = webkitGstWebRTCIceAgentGetStunServer; + iceClass->add_turn_server = webkitGstWebRTCIceAgentAddTurnServer; + iceClass->add_stream = webkitGstWebRTCIceAgentAddStream; + iceClass->get_is_controller = webkitGstWebRTCIceAgentGetIsController; + iceClass->set_is_controller = webkitGstWebRTCIceAgentSetIsController; + iceClass->add_candidate = webkitGstWebRTCIceAgentAddCandidate; + iceClass->find_transport = webkitGstWebRTCIceAgentFindTransport; + iceClass->gather_candidates = webkitGstWebRTCIceAgentGatherCandidates; + iceClass->get_turn_server = webkitGstWebRTCIceAgentGetTurnServer; + iceClass->set_turn_server = webkitGstWebRTCIceAgentSetTurnServer; + iceClass->set_tos = webkitGstWebRTCIceAgentSetTos; + iceClass->set_local_credentials = webkitGstWebRTCIceAgentSetLocalCredentials; + iceClass->set_remote_credentials = webkitGstWebRTCIceAgentSetRemoteCredentials; + iceClass->set_http_proxy = webkitGstWebRTCIceAgentSetHttpProxy; + iceClass->get_http_proxy = webkitGstWebRTCIceAgentGetHttpProxy; + iceClass->get_selected_pair = webkitGstWebRTCIceAgentGetSelectedPair; + // TODO: + // - get_local_candidates + // - get_remote_candidates +#if GST_CHECK_VERSION(1, 27, 0) + iceClass->close = webkitGstWebRTCIceAgentClose; +#endif +} + +WebKitGstIceAgent* webkitGstWebRTCCreateIceAgent(const String& name, ScriptExecutionContext* context) +{ + if (!context) + return nullptr; + + RefPtr socketProvider = context->socketProvider(); + if (!socketProvider) + return nullptr; + + auto agent = reinterpret_cast(g_object_new(WEBKIT_TYPE_GST_WEBRTC_ICE_BACKEND, "name", name.ascii().data(), nullptr)); + gst_object_ref_sink(agent); + if (!webkitGstWebRTCIceAgentConfigure(agent, WTFMove(socketProvider), context->identifier())) { + gst_object_unref(agent); + return nullptr; + } + return agent; +} + +const GRefPtr& webkitGstWebRTCIceAgentGetRiceAgent(WebKitGstIceAgent* agent) +{ + return agent->priv->agent; +} + +Vector> webkitGstWebRTCIceAgentGetTurnConfigs(WebKitGstIceAgent* agent) +{ + Vector> result; + result.reserveInitialCapacity(agent->priv->turnConfigs.size()); + for (const auto& config : agent->priv->turnConfigs) + result.append(GRefPtr(config)); + + return result; +} + +Vector webkitGstWebRTCIceAgentGatherSocketAddresses(WebKitGstIceAgent* agent, unsigned streamId) +{ + auto backend = agent->priv->iceBackend; + if (!backend) + return { }; + + return backend->gatherSocketAddresses(streamId); +} + +GstWebRTCICETransport* webkitGstWebRTCIceAgentCreateTransport(WebKitGstIceAgent* agent, GThreadSafeWeakPtr&& stream, RTCIceComponent component) +{ + if (!agent->priv->iceBackend) + return nullptr; + + GstWebRTCICEComponent gstComponent; + switch (component) { + case RTCIceComponent::Rtp: + gstComponent = GST_WEBRTC_ICE_COMPONENT_RTP; + break; + case RTCIceComponent::Rtcp: + gstComponent = GST_WEBRTC_ICE_COMPONENT_RTCP; + break; + }; + auto isController = webkitGstWebRTCIceAgentGetIsController(GST_WEBRTC_ICE(agent)); + return GST_WEBRTC_ICE_TRANSPORT(webkitGstWebRTCCreateIceTransport(agent, WTFMove(stream), gstComponent, isController)); +} + +void webkitGstWebRTCIceAgentSend(WebKitGstIceAgent* agent, unsigned streamId, RTCIceProtocol protocol, String&& from, String&& to, SharedMemory::Handle&& data) +{ + auto backend = agent->priv->iceBackend; + if (!backend) + return; + + backend->send(streamId, protocol, WTFMove(from), WTFMove(to), WTFMove(data)); +} + +void webkitGstWebRTCIceAgentWakeup(WebKitGstIceAgent* agent) +{ + g_main_context_wakeup(agent->priv->runLoop->mainContext()); +} + +void webkitGstWebRTCIceAgentGatheringDoneForStream(WebKitGstIceAgent* agent, unsigned streamId) +{ + findStreamAndApply(agent->priv->streams, streamId, [](const auto* stream) { + webkitGstWebRTCIceStreamGatheringDone(stream); + }); +} + +void webkitGstWebRTCIceAgentLocalCandidateGatheredForStream(WebKitGstIceAgent* agent, unsigned streamId, RiceAgentGatheredCandidate& candidate) +{ + findStreamAndApply(agent->priv->streams, streamId, [&](const auto* stream) { + auto sdp = GMallocString::unsafeAdoptFromUTF8(rice_candidate_to_sdp_string(&candidate.gathered.candidate)); + ASSERT(startsWith(sdp.span(), "a="_s)); + String strippedSdp(sdp.span().subspan(2)); + + agent->priv->onCandidate(GST_WEBRTC_ICE(agent), streamId, strippedSdp.utf8().data(), agent->priv->onCandidateData); + webkitGstWebRTCIceStreamAddLocalGatheredCandidate(stream, candidate.gathered); + }); +} + +void webkitGstWebRTCIceAgentNewSelectedPairForStream(WebKitGstIceAgent* agent, unsigned streamId, RiceAgentSelectedPair& selectedPair) +{ + findStreamAndApply(agent->priv->streams, streamId, [&](const auto* stream) { + webkitGstWebRTCIceStreamNewSelectedPair(stream, selectedPair); + }); +} + +void webkitGstWebRTCIceAgentComponentStateChangedForStream(WebKitGstIceAgent* agent, unsigned streamId, RiceAgentComponentStateChange& change) +{ + findStreamAndApply(agent->priv->streams, streamId, [&](const auto* stream) { + webkitGstWebRTCIceStreamComponentStateChanged(stream, change); + }); +} + +#undef GST_CAT_DEFAULT + +#endif // USE(GSTREAMER_WEBRTC) && USE(LIBRICE) diff --git a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerIceTransportBackend.cpp b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerIceTransportBackend.cpp index 9c6e2de55fe9b..a63ab1d64f74f 100644 --- a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerIceTransportBackend.cpp +++ b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerIceTransportBackend.cpp @@ -26,6 +26,7 @@ #include "NotImplemented.h" #include #include +#include #include namespace WebCore { @@ -88,8 +89,8 @@ void GStreamerIceTransportBackend::registerClient(RTCIceTransportBackendClient& return; #ifndef GST_DISABLE_GST_DEBUG - GUniquePtr desc(g_enum_to_string(GST_TYPE_WEBRTC_ICE_CONNECTION_STATE, transportState)); - GST_DEBUG_OBJECT(weakThis->m_backend.get(), "Initial ICE transport state: %s", desc.get()); + auto desc = GMallocString::unsafeAdoptFromUTF8(g_enum_to_string(GST_TYPE_WEBRTC_ICE_CONNECTION_STATE, transportState)); + GST_DEBUG_OBJECT(weakThis->m_backend.get(), "Initial ICE transport state: %s", desc.utf8()); #endif // We start observing a bit late and might miss the checking state. Synthesize it as needed. @@ -116,8 +117,8 @@ void GStreamerIceTransportBackend::stateChanged() const g_object_get(m_iceTransport.get(), "state", &transportState, nullptr); #ifndef GST_DISABLE_GST_DEBUG - GUniquePtr desc(g_enum_to_string(GST_TYPE_WEBRTC_ICE_CONNECTION_STATE, transportState)); - GST_DEBUG_OBJECT(m_backend.get(), "ICE transport state changed to %s", desc.get()); + auto desc = GMallocString::unsafeAdoptFromUTF8(g_enum_to_string(GST_TYPE_WEBRTC_ICE_CONNECTION_STATE, transportState)); + GST_DEBUG_OBJECT(m_backend.get(), "ICE transport state changed to %s", desc.utf8()); #endif callOnMainThread([weakThis = WeakPtr { *this }, transportState] { diff --git a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerMediaEndpoint.cpp b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerMediaEndpoint.cpp index a1a8c15423e70..fc515078f904f 100644 --- a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerMediaEndpoint.cpp +++ b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerMediaEndpoint.cpp @@ -58,6 +58,7 @@ #include #include #include +#include #include #include @@ -116,22 +117,22 @@ void GStreamerMediaEndpoint::maybeInsertNetSimForElement(GstBin* bin, GstElement return; // Unlink the element, add a netsim element in bin and link it to the element to simulate varying network conditions. - const char* padName = isSource ? "src" : "sink"; - auto pad = adoptGRef(gst_element_get_static_pad(element, padName)); + ASCIILiteral padName = isSource ? "src"_s : "sink"_s; + auto pad = adoptGRef(gst_element_get_static_pad(element, padName.characters())); auto peer = adoptGRef(gst_pad_get_peer(pad.get())); if (UNLIKELY(!peer)) return; gst_pad_unlink(pad.get(), peer.get()); - auto netsim = makeGStreamerElement("netsim", nullptr); + auto netsim = makeGStreamerElement("netsim"_s); gst_bin_add(GST_BIN_CAST(bin), netsim); GST_DEBUG_OBJECT(m_pipeline.get(), "Configuring %" GST_PTR_FORMAT " for transport element %" GST_PTR_FORMAT, netsim, element); for (const auto& [key, value] : options) gst_util_set_object_arg(G_OBJECT(netsim), key.ascii().data(), value.ascii().data()); - pad = adoptGRef(gst_element_get_static_pad(netsim, padName)); + pad = adoptGRef(gst_element_get_static_pad(netsim, padName.characters())); if (isSource) { gst_element_link(element, netsim); gst_pad_link(pad.get(), peer.get()); @@ -160,7 +161,7 @@ bool GStreamerMediaEndpoint::initializePipeline() }); auto binName = makeString("webkit-webrtcbin-"_s, nPipeline++); - m_webrtcBin = makeGStreamerElement("webrtcbin", binName.ascii().data()); + m_webrtcBin = makeGStreamerElement("webrtcbin"_s, binName); if (!m_webrtcBin) return false; @@ -172,9 +173,8 @@ bool GStreamerMediaEndpoint::initializePipeline() if (!m_srcNetSimOptions.isEmpty() || !m_sinkNetSimOptions.isEmpty()) { if (auto factory = adoptGRef(gst_element_factory_find("netsim"))) { g_signal_connect_swapped(m_webrtcBin.get(), "deep-element-added", G_CALLBACK(+[](GStreamerMediaEndpoint* self, GstBin* bin, GstElement* element) { - GUniquePtr elementName(gst_element_get_name(element)); - auto view = StringView::fromLatin1(elementName.get()); - if (view.startsWith("nice"_s)) + auto elementName = GMallocString::unsafeAdoptFromUTF8(gst_element_get_name(element)); + if (startsWith(elementName.span(), "nice"_s)) self->maybeInsertNetSimForElement(bin, element); }), this); } else @@ -187,7 +187,7 @@ bool GStreamerMediaEndpoint::initializePipeline() return false; } - if (gstObjectHasProperty(rtpBin.get(), "add-reference-timestamp-meta")) + if (gstObjectHasProperty(rtpBin.get(), "add-reference-timestamp-meta"_s)) g_object_set(rtpBin.get(), "add-reference-timestamp-meta", TRUE, nullptr); g_signal_connect(rtpBin.get(), "new-jitterbuffer", G_CALLBACK(+[](GstElement*, GstElement* element, unsigned, unsigned ssrc, GStreamerMediaEndpoint* endPoint) { @@ -260,8 +260,8 @@ bool GStreamerMediaEndpoint::initializePipeline() g_signal_connect(m_webrtcBin.get(), "notify::connection-state", G_CALLBACK(+[](GstElement* webrtcBin, GParamSpec*, GStreamerMediaEndpoint* endPoint) { GstWebRTCPeerConnectionState state; g_object_get(webrtcBin, "connection-state", &state, nullptr); - GUniquePtr desc(g_enum_to_string(GST_TYPE_WEBRTC_PEER_CONNECTION_STATE, state)); - auto dotFilename = makeString(span(GST_ELEMENT_NAME(endPoint->pipeline())), '-', span(desc.get())); + auto desc = GMallocString::unsafeAdoptFromUTF8(g_enum_to_string(GST_TYPE_WEBRTC_PEER_CONNECTION_STATE, state)); + auto dotFilename = makeString(unsafeSpan(GST_ELEMENT_NAME(endPoint->pipeline())), '-', desc.span()); GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN_CAST(endPoint->pipeline()), GST_DEBUG_GRAPH_SHOW_ALL, dotFilename.ascii().data()); }), this); #endif @@ -403,14 +403,14 @@ static std::optional> fetchDescription(GstElement* unsigned totalAttributesNumber = gst_sdp_message_attributes_len(description->sdp); for (unsigned i = 0; i < totalAttributesNumber; i++) { const auto attribute = gst_sdp_message_get_attribute(description->sdp, i); - if (!g_strcmp0(attribute->key, "end-of-candidates")) { + if (equal(unsafeSpan(attribute->key), "end-of-candidates"_s)) { gst_sdp_message_remove_attribute(description->sdp, i); i--; } } - GUniquePtr sdpString(gst_sdp_message_as_text(description->sdp)); - return { { fromSessionDescriptionType(*description.get()), String::fromUTF8(sdpString.get()) } }; + auto sdpString = GMallocString::unsafeAdoptFromUTF8(gst_sdp_message_as_text(description->sdp)); + return { { fromSessionDescriptionType(*description.get()), sdpString.span() } }; } static GstWebRTCSignalingState fetchSignalingState(GstElement* webrtcBin) @@ -418,8 +418,8 @@ static GstWebRTCSignalingState fetchSignalingState(GstElement* webrtcBin) GstWebRTCSignalingState state; g_object_get(webrtcBin, "signaling-state", &state, nullptr); #ifndef GST_DISABLE_GST_DEBUG - GUniquePtr desc(g_enum_to_string(GST_TYPE_WEBRTC_SIGNALING_STATE, state)); - GST_DEBUG_OBJECT(webrtcBin, "Signaling state set to %s", desc.get()); + auto desc = GMallocString::unsafeAdoptFromUTF8(g_enum_to_string(GST_TYPE_WEBRTC_SIGNALING_STATE, state)); + GST_DEBUG_OBJECT(webrtcBin, "Signaling state set to %s", desc.utf8()); #endif return state; } @@ -485,15 +485,16 @@ Vector getMediaStreamIdsFromSDPMedia(const GstSDPMedia& media) HashSet mediaStreamIdsSet; for (guint i = 0; i < gst_sdp_media_attributes_len(&media); ++i) { const auto attribute = gst_sdp_media_get_attribute(&media, i); - if (!g_strcmp0(attribute->key, "msid")) { - auto components = String::fromUTF8(attribute->value).split(' '); + auto key = CStringView::unsafeFromUTF8(attribute->key); + if (key == "msid"_s) { + auto components = String(byteCast(unsafeSpan(attribute->value))).split(' '); if (components.size() < 2) continue; mediaStreamIdsSet.add(components[0]); } // MSID may also come in ssrc attributes, specially if they're in an SDP answer. They look like: // a=ssrc:3612593434 msid:e1019f4a-0983-4863-b923-b75903cced2c webrtctransceiver1 - if (!g_strcmp0(attribute->key, "ssrc")) { + if (key == "ssrc"_s) { auto outerComponents = String::fromUTF8(attribute->value).split(' '); for (auto& outer : outerComponents) { auto innerComponents = outer.split(':'); @@ -519,17 +520,18 @@ inline bool isRecvDirection(GstWebRTCRTPTransceiverDirection direction) static std::optional toGStreamerMediaEndpointTransceiverState(GstElement* webrtcBin, GstWebRTCRTPTransceiver* transceiver, const GstWebRTCSessionDescription* remoteDescription) { GRefPtr receiver; - GUniqueOutPtr mid; + GUniqueOutPtr midChars; GstWebRTCRTPTransceiverDirection direction, currentDirection, firedDirection; guint mLineIndex; // GstWebRTCRTPTransceiver doesn't have a fired-direction property, so use direction. Until // GStreamer 1.26 direction and current-direction always had the same value. This was fixed by: // https://gitlab.freedesktop.org/gstreamer/gstreamer/-/commit/cafb999fb0cdf32803fcc3f85f2652212f05c2d0 - g_object_get(transceiver, "receiver", &receiver.outPtr(), "direction", &direction, "current-direction", ¤tDirection, "mlineindex", &mLineIndex, "mid", &mid.outPtr(), nullptr); + g_object_get(transceiver, "receiver", &receiver.outPtr(), "direction", &direction, "current-direction", ¤tDirection, "mlineindex", &mLineIndex, "mid", &midChars.outPtr(), nullptr); + auto mid = GMallocString::unsafeAdoptFromUTF8(WTFMove(midChars)); #ifndef GST_DISABLE_GST_DEBUG - GUniquePtr desc(g_enum_to_string(GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION, direction)); - GUniquePtr currentDesc(g_enum_to_string(GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION, currentDirection)); - GST_TRACE_OBJECT(webrtcBin, "Receiver = %" GST_PTR_FORMAT ", direction = %s, current-direction = %s, mlineindex = %u, mid = %s", receiver.get(), desc.get(), currentDesc.get(), mLineIndex, GST_STR_NULL(mid.get())); + auto desc = GMallocString::unsafeAdoptFromUTF8(g_enum_to_string(GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION, direction)); + auto currentDesc = GMallocString::unsafeAdoptFromUTF8(g_enum_to_string(GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION, currentDirection)); + GST_TRACE_OBJECT(webrtcBin, "Receiver = %" GST_PTR_FORMAT ", direction = %s, current-direction = %s, mlineindex = %u, mid = %s", receiver.get(), desc.utf8(), currentDesc.utf8(), mLineIndex, GST_STR_NULL(mid.utf8())); #endif firedDirection = currentDirection != GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE ? currentDirection : direction; @@ -558,7 +560,7 @@ static std::optional toGStreamerMediaEnd if (!streamIds.isEmpty()) firedDirectionResult = toRTCRtpTransceiverDirection(firedDirection); - return { { String::fromUTF8(mid.get()), WTFMove(streamIds), WTFMove(firedDirectionResult) } }; + return { { String(mid.span()), WTFMove(streamIds), WTFMove(firedDirectionResult) } }; } static Vector transceiverStatesFromWebRTCBin(GstElement* webrtcBin) @@ -577,12 +579,12 @@ static Vector transceiverStatesFromWebRT GUniqueOutPtr localDescription; g_object_get(webrtcBin, "local-description", &localDescription.outPtr(), nullptr); if (localDescription) { - GUniquePtr sdp(gst_sdp_message_as_text(localDescription->sdp)); - GST_TRACE_OBJECT(webrtcBin, "Local-description:\n%s", sdp.get()); + auto sdp = GMallocString::unsafeAdoptFromUTF8(gst_sdp_message_as_text(localDescription->sdp)); + GST_TRACE_OBJECT(webrtcBin.get(), "Local-description:\n%s", sdp.utf8()); } if (remoteDescription) { - GUniquePtr sdp(gst_sdp_message_as_text(remoteDescription->sdp)); - GST_TRACE_OBJECT(webrtcBin, "Remote-description:\n%s", sdp.get()); + auto sdp = GMallocString::unsafeAdoptFromUTF8(gst_sdp_message_as_text(remoteDescription->sdp)); + GST_TRACE_OBJECT(webrtcBin.get(), "Remote-description:\n%s", sdp.utf8()); } #endif @@ -604,8 +606,8 @@ void GStreamerMediaEndpoint::linkOutgoingSources(GstSDPMessage* sdpMessage) unsigned totalMedias = gst_sdp_message_medias_len(sdpMessage); #ifndef GST_DISABLE_GST_DEBUG GST_DEBUG_OBJECT(m_pipeline.get(), "Linking outgoing sources for %u m-lines", totalMedias); - GUniquePtr sdp(gst_sdp_message_as_text(sdpMessage)); - GST_TRACE_OBJECT(m_pipeline.get(), "in SDP:\n%s", sdp.get()); + auto sdp = GMallocString::unsafeAdoptFromUTF8(gst_sdp_message_as_text(sdpMessage)); + GST_TRACE_OBJECT(m_pipeline.get(), "in SDP:\n%s", sdp.utf8()); #endif for (unsigned i = 0; i < totalMedias; i++) { const auto media = gst_sdp_message_get_media(sdpMessage, i); @@ -620,10 +622,10 @@ void GStreamerMediaEndpoint::linkOutgoingSources(GstSDPMessage* sdpMessage) continue; } - auto msid = String::fromUTF8(gst_sdp_media_get_attribute_val(media, "msid")); + auto msid = CStringView::unsafeFromUTF8(gst_sdp_media_get_attribute_val(media, "msid")); - GST_DEBUG_OBJECT(m_pipeline.get(), "Looking-up outgoing source with msid %s in %zu unlinked sources", msid.utf8().data(), m_unlinkedOutgoingSources.size()); - m_unlinkedOutgoingSources.removeFirstMatching([&](auto& source) -> bool { + GST_DEBUG_OBJECT(m_pipeline.get(), "Looking-up outgoing source with msid %s in %zu unlinked sources", msid.utf8(), m_unlinkedOutgoingSources.size()); + m_unlinkedOutgoingSources.removeFirstMatching([&, msid = String(msid.span())](auto& source) -> bool { if (source->type() != sourceType) return false; @@ -837,12 +839,12 @@ void GStreamerMediaEndpoint::doSetRemoteDescription(const RTCSessionDescription& if (protectedThis->isStopped()) return; - processSDPMessage(&message, [this](unsigned, StringView mid, const auto* media) { - const char* mediaType = gst_sdp_media_get_media(media); - m_mediaForMid.set(mid.toString(), g_str_equal(mediaType, "audio") ? RealtimeMediaSource::Type::Audio : RealtimeMediaSource::Type::Video); + processSDPMessage(&message, [this](unsigned, CStringView mid, const auto* media) { + auto mediaType = CStringView::unsafeFromUTF8(gst_sdp_media_get_media(media)); + m_mediaForMid.set(mid.span(), mediaType == "audio"_s ? RealtimeMediaSource::Type::Audio : RealtimeMediaSource::Type::Video); // https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1907 - if (sdpMediaHasAttributeKey(media, "ice-lite")) { + if (sdpMediaHasAttributeKey(media, "ice-lite"_s)) { GRefPtr ice; g_object_get(m_webrtcBin.get(), "ice-agent", &ice.outPtr(), nullptr); g_object_set(ice.get(), "ice-lite", TRUE, nullptr); @@ -868,8 +870,8 @@ void GStreamerMediaEndpoint::doSetRemoteDescription(const RTCSessionDescription& } #ifndef GST_DISABLE_GST_DEBUG - auto dotFileName = makeString(span(GST_OBJECT_NAME(m_pipeline.get())), ".setRemoteDescription"_s); - GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.utf8().data()); + auto dotFileName = makeString(unsafeSpan(GST_OBJECT_NAME(m_pipeline.get())), ".setRemoteDescription"_s); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.ascii().data()); #endif auto rtcTransceiverStates = transceiverStatesFromWebRTCBin(m_webrtcBin.get()); @@ -934,8 +936,7 @@ void GStreamerMediaEndpoint::setDescription(const RTCSessionDescription* descrip sdpType = description->type(); if (descriptionType == DescriptionType::Local && sdpType == RTCSdpType::Answer && !gst_sdp_message_get_version(message.get())) { GError error; - GUniquePtr errorMessage(g_strdup("Expect line: v=")); - error.message = errorMessage.get(); + error.message = const_cast("Expect line: v="); failureCallback(&error); return; } @@ -957,8 +958,8 @@ void GStreamerMediaEndpoint::setDescription(const RTCSessionDescription* descrip gst_sdp_message_copy(message.get(), &data->message.outPtr()); #ifndef GST_DISABLE_GST_DEBUG - GUniquePtr sdp(gst_sdp_message_as_text(data->message.get())); - GST_DEBUG_OBJECT(m_pipeline.get(), "SDP: %s", sdp.get()); + auto sdp = GMallocString::unsafeAdoptFromUTF8(gst_sdp_message_as_text(data->message.get())); + GST_DEBUG_OBJECT(m_pipeline.get(), "SDP: %s", sdp.utf8()); #endif GUniquePtr sessionDescription(gst_webrtc_session_description_new(type, message.release())); @@ -990,7 +991,7 @@ void GStreamerMediaEndpoint::setDescription(const RTCSessionDescription* descrip }, data, reinterpret_cast(destroySetDescriptionCallData))); } -void GStreamerMediaEndpoint::processSDPMessage(const GstSDPMessage* message, Function mediaCallback) +void GStreamerMediaEndpoint::processSDPMessage(const GstSDPMessage* message, Function mediaCallback) { unsigned totalMedias = gst_sdp_message_medias_len(message); for (unsigned mediaIndex = 0; mediaIndex < totalMedias; mediaIndex++) { @@ -1000,10 +1001,10 @@ void GStreamerMediaEndpoint::processSDPMessage(const GstSDPMessage* message, Fun continue; #ifndef GST_DISABLE_GST_DEBUG - GUniquePtr mediaRepresentation(gst_sdp_media_as_text(media)); - GST_LOG_OBJECT(m_pipeline.get(), "Processing media:\n%s", mediaRepresentation.get()); + auto mediaRepresentation = GMallocString::unsafeAdoptFromUTF8(gst_sdp_media_as_text(media)); + GST_LOG_OBJECT(m_pipeline.get(), "Processing media:\n%s", mediaRepresentation.utf8()); #endif - const char* mid = gst_sdp_media_get_attribute_val(media, "mid"); + auto mid = CStringView::unsafeFromUTF8(gst_sdp_media_get_attribute_val(media, "mid")); if (!mid) continue; @@ -1011,7 +1012,7 @@ void GStreamerMediaEndpoint::processSDPMessage(const GstSDPMessage* message, Fun unsigned totalAttributes = gst_sdp_media_attributes_len(media); for (unsigned attributeIndex = 0; attributeIndex < totalAttributes; attributeIndex++) { const auto* attribute = gst_sdp_media_get_attribute(media, attributeIndex); - if (!g_strcmp0(attribute->key, "inactive")) { + if (CStringView::unsafeFromUTF8(attribute->key) == "inactive"_s) { isInactive = true; break; } @@ -1021,7 +1022,7 @@ void GStreamerMediaEndpoint::processSDPMessage(const GstSDPMessage* message, Fun continue; } - mediaCallback(mediaIndex, StringView::fromLatin1(mid), media); + mediaCallback(mediaIndex, mid, media); } } @@ -1053,7 +1054,7 @@ GRefPtr GStreamerMediaEndpoint::requestPad(const GRefPtr& allow } std::optional payloadType; if (auto encodingName = gstStructureGetString(structure, "encoding-name"_s)) - payloadType = payloadTypeForEncodingName(encodingName); + payloadType = payloadTypeForEncodingName(encodingName.span()); if (!payloadType) { if (availablePayloadType < 128) @@ -1106,7 +1107,7 @@ GRefPtr GStreamerMediaEndpoint::requestPad(const GRefPtr& allow if (!mediaStreamID.isEmpty()) { GST_DEBUG_OBJECT(m_pipeline.get(), "Setting msid to %s on sink pad %" GST_PTR_FORMAT, mediaStreamID.ascii().data(), sinkPad.get()); - if (gstObjectHasProperty(sinkPad.get(), "msid")) + if (gstObjectHasProperty(sinkPad.get(), "msid"_s)) g_object_set(sinkPad.get(), "msid", mediaStreamID.ascii().data(), nullptr); } @@ -1125,8 +1126,7 @@ std::optional GStreamerMediaEndpoint::isIceGatheringComplete(const String& unsigned numberOfMedias = gst_sdp_message_medias_len(message.get()); for (unsigned i = 0; i < numberOfMedias; i++) { const auto* media = gst_sdp_message_get_media(message.get(), i); - const char* value = gst_sdp_media_get_attribute_val_n(media, "end-of-candidates", 0); - if (!value) + if (!gst_sdp_media_get_attribute_val_n(media, "end-of-candidates", 0)) return false; } @@ -1262,8 +1262,7 @@ void GStreamerMediaEndpoint::initiate(bool isInitiator, GstStructure* rawOptions } GUniqueOutPtr sessionDescription; - const char* sdpTypeString = holder->sdpType == RTCSdpType::Offer ? "offer" : "answer"; - gst_structure_get(reply, sdpTypeString, GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &sessionDescription.outPtr(), nullptr); + gst_structure_get(reply, holder->sdpType == RTCSdpType::Offer ? "offer" : "answer", GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &sessionDescription.outPtr(), nullptr); #ifndef GST_DISABLE_GST_DEBUG GUniquePtr sdp(gst_sdp_message_as_text(sessionDescription->sdp)); @@ -1336,12 +1335,12 @@ MediaStream& GStreamerMediaEndpoint::mediaStreamFromRTCStream(String mediaStream String GStreamerMediaEndpoint::trackIdFromSDPMedia(const GstSDPMedia& media) { - const char* msidAttribute = gst_sdp_media_get_attribute_val(&media, "msid"); + auto msidAttribute = CStringView::unsafeFromUTF8(gst_sdp_media_get_attribute_val(&media, "msid")); if (!msidAttribute) return emptyString(); - GST_LOG_OBJECT(m_pipeline.get(), "SDP media msid attribute value: %s", msidAttribute); - auto components = String::fromUTF8(msidAttribute).split(' '); + GST_LOG_OBJECT(m_pipeline.get(), "SDP media msid attribute value: %s", msidAttribute.utf8()); + auto components = String(msidAttribute.span()).split(' '); if (components.size() < 2) return emptyString(); @@ -1448,8 +1447,8 @@ void GStreamerMediaEndpoint::connectPad(GstPad* pad) gst_element_set_state(bin, GST_STATE_PAUSED); #ifndef GST_DISABLE_GST_DEBUG - auto dotFileName = makeString(span(GST_OBJECT_NAME(m_pipeline.get())), ".pending-"_s, span(GST_OBJECT_NAME(pad))); - GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.utf8().data()); + auto dotFileName = makeString(unsafeSpan(GST_OBJECT_NAME(m_pipeline.get())), ".pending-"_s, unsafeSpan(GST_OBJECT_NAME(pad))); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.ascii().data()); #endif } @@ -1569,8 +1568,8 @@ ExceptionOr GStreamerMediaEndpoint::createTran }); #ifndef GST_DISABLE_GST_DEBUG - GUniquePtr desc(g_enum_to_string(GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION, direction)); - GST_DEBUG_OBJECT(m_pipeline.get(), "Adding %s transceiver for payload %" GST_PTR_FORMAT, desc.get(), caps.get()); + auto desc = GMallocString::unsafeAdoptFromUTF8(g_enum_to_string(GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION, direction)); + GST_DEBUG_OBJECT(m_pipeline.get(), "Adding %s transceiver for payload %" GST_PTR_FORMAT, desc.utf8(), caps.get()); #endif // FIXME: None of this (excepted direction) is passed to webrtcbin yet. @@ -2014,8 +2013,8 @@ void GStreamerMediaEndpoint::onIceGatheringChange() GstWebRTCICEGatheringState state; g_object_get(m_webrtcBin.get(), "ice-gathering-state", &state, nullptr); #ifndef GST_DISABLE_GST_DEBUG - GUniquePtr desc(g_enum_to_string(GST_TYPE_WEBRTC_ICE_GATHERING_STATE, state)); - GST_DEBUG_OBJECT(m_pipeline.get(), "ICE gathering state changed to %s", desc.get()); + auto desc = GMallocString::unsafeAdoptFromUTF8(g_enum_to_string(GST_TYPE_WEBRTC_ICE_GATHERING_STATE, state)); + GST_DEBUG_OBJECT(m_pipeline.get(), "ICE gathering state changed to %s", desc.utf8()); #endif callOnMainThread([protectedThis = Ref(*this), this, state] { if (isStopped()) @@ -2114,9 +2113,10 @@ void GStreamerMediaEndpoint::collectTransceivers() if (existingTransceiver) continue; - GUniqueOutPtr mid; + GUniqueOutPtr midChars; unsigned mLineIndex; - g_object_get(current.get(), "mid", &mid.outPtr(), "mlineindex", &mLineIndex, nullptr); + g_object_get(transceiver.get(), "mid", &midChars.outPtr(), "mlineindex", &mLineIndex, nullptr); + auto mid = GMallocString::unsafeAdoptFromUTF8(WTFMove(midChars)); if (!mid) continue; @@ -2126,7 +2126,7 @@ void GStreamerMediaEndpoint::collectTransceivers() continue; } - m_peerConnectionBackend.newRemoteTransceiver(WTF::makeUnique(WTFMove(current)), m_mediaForMid.get(String::fromUTF8(mid.get())), trackIdFromSDPMedia(*media)); + m_peerConnectionBackend.newRemoteTransceiver(WTF::makeUnique(WTFMove(current)), m_mediaForMid.get(String(mid.span())), trackIdFromSDPMedia(*media)); } } @@ -2201,7 +2201,7 @@ GUniquePtr GStreamerMediaEndpoint::preprocessStats(const GRefPtr GStreamerMediaEndpoint::preprocessStats(const GRefPtr GStreamerMediaEndpoint::canTrickleIceCandidates() const for (unsigned i = 0; i < gst_sdp_message_attributes_len(description->sdp); i++) { const auto attribute = gst_sdp_message_get_attribute(description->sdp, i); - if (g_strcmp0(attribute->key, "ice-options")) + if (!equal(unsafeSpan(attribute->key), "ice-options"_s)) continue; auto values = makeString(span(attribute->value)).split(' '); diff --git a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerMediaEndpoint.h b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerMediaEndpoint.h index 54194eb04f7e0..57f96c29c21a3 100644 --- a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerMediaEndpoint.h +++ b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerMediaEndpoint.h @@ -162,7 +162,7 @@ class GStreamerMediaEndpoint : public ThreadSafeRefCountedAndCanMakeThreadSafeWe ExceptionOr createTransceiverBackends(const String& kind, const RTCRtpTransceiverInit&, GStreamerRtpSenderBackend::Source&&, PeerConnectionBackend::IgnoreNegotiationNeededFlag); - void processSDPMessage(const GstSDPMessage*, Function); + void processSDPMessage(const GstSDPMessage*, Function); WARN_UNUSED_RETURN GRefPtr requestPad(const GRefPtr&, const String& mediaStreamID); diff --git a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerPeerConnectionBackend.cpp b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerPeerConnectionBackend.cpp index 34e4a80e2b91a..c0910212cad77 100644 --- a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerPeerConnectionBackend.cpp +++ b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerPeerConnectionBackend.cpp @@ -76,7 +76,7 @@ static std::unique_ptr createGStreamerPeerConnectionBacke std::call_once(debugRegisteredFlag, [] { GST_DEBUG_CATEGORY_INIT(webkit_webrtc_pc_backend_debug, "webkitwebrtcpeerconnection", 0, "WebKit WebRTC PeerConnection"); }); - if (!isGStreamerPluginAvailable("webrtc")) { + if (!isGStreamerPluginAvailable("webrtc"_s)) { WTFLogAlways("GstWebRTC plugin not found. Make sure to install gst-plugins-bad >= 1.20 with the webrtc plugin enabled."); return nullptr; } diff --git a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpReceiverBackend.cpp b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpReceiverBackend.cpp index 2a8d20533e65b..7f5e9b108ae7b 100644 --- a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpReceiverBackend.cpp +++ b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpReceiverBackend.cpp @@ -67,8 +67,8 @@ RTCRtpParameters GStreamerRtpReceiverBackend::getParameters() auto media = gstStructureGetString(structure, "media"_s); auto encodingName = gstStructureGetString(structure, "encoding-name"_s); - if (media && encodingName) - codec.mimeType = makeString(media, '/', encodingName.convertToASCIILowercase()); + if (!media.isEmpty() && !encodingName.isEmpty()) + codec.mimeType = makeString(media.span(), '/', String(encodingName.span()).convertToASCIILowercase()); if (auto clockRate = gstStructureGet(structure, "clock-rate"_s)) codec.clockRate = *clockRate; @@ -77,7 +77,7 @@ RTCRtpParameters GStreamerRtpReceiverBackend::getParameters() codec.channels = *channels; if (auto fmtpLine = gstStructureGetString(structure, "fmtp-line"_s)) - codec.sdpFmtpLine = fmtpLine.toString(); + codec.sdpFmtpLine = fmtpLine.span(); parameters.codecs.append(WTFMove(codec)); @@ -86,7 +86,7 @@ RTCRtpParameters GStreamerRtpReceiverBackend::getParameters() if (!name.startsWith("extmap-"_s)) return true; - auto extensionId = parseInteger(name.toStringWithoutCopying().substring(7)); + auto extensionId = parseInteger(name.substring(7)); if (!extensionId) return true; diff --git a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpTransceiverBackend.cpp b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpTransceiverBackend.cpp index 4d01f0fad9316..de52b8a490bf8 100644 --- a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpTransceiverBackend.cpp +++ b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpTransceiverBackend.cpp @@ -26,6 +26,7 @@ #include "GStreamerRtpSenderBackend.h" #include "GStreamerWebRTCUtils.h" #include "RTCRtpCodecCapability.h" +#include #include GST_DEBUG_CATEGORY(webkit_webrtc_transceiver_debug); @@ -89,8 +90,8 @@ void GStreamerRtpTransceiverBackend::setDirection(RTCRtpTransceiverDirection dir { auto gstDirection = fromRTCRtpTransceiverDirection(direction); #ifndef GST_DISABLE_GST_DEBUG - GUniquePtr directionString(g_enum_to_string(GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION, gstDirection)); - GST_DEBUG_OBJECT(m_rtcTransceiver.get(), "Setting direction to %s", directionString.get()); + auto directionString = GMallocString::unsafeAdoptFromUTF8(g_enum_to_string(GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION, gstDirection)); + GST_DEBUG_OBJECT(m_rtcTransceiver.get(), "Setting direction to %s", directionString.utf8()); #endif g_object_set(m_rtcTransceiver.get(), "direction", gstDirection, nullptr); } @@ -156,14 +157,14 @@ ExceptionOr GStreamerRtpTransceiverBackend::setCodecPreferences(const Vect if (gst_caps_get_size(currentCaps.get()) > 0) { auto structure = gst_caps_get_structure(currentCaps.get(), 0); if (auto msIdValue = gstStructureGetString(structure, "a-msid"_s)) - msid = msIdValue.toString(); + msid = msIdValue.span(); gstStructureForeach(structure, [&](auto id, const auto& value) -> bool { auto key = gstIdToString(id); if (!key.startsWith("extmap-"_s)) return true; - extensions.add(key.toString(), String::fromLatin1(g_value_get_string(value))); + extensions.add(key, byteCast(unsafeSpan(g_value_get_string(value)))); return true; }); } diff --git a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerStatsCollector.cpp b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerStatsCollector.cpp index c12aa3374cd7c..7ee6567b45ac6 100644 --- a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerStatsCollector.cpp +++ b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerStatsCollector.cpp @@ -40,7 +40,7 @@ namespace WebCore { RTCStatsReport::Stats::Stats(Type type, const GstStructure* structure) : type(type) - , id(gstStructureGetString(structure, "id"_s).toString()) + , id(gstStructureGetString(structure, "id"_s).span()) { if (auto value = gstStructureGet(structure, "timestamp"_s)) timestamp = Seconds::fromMicroseconds(*value).milliseconds(); @@ -48,9 +48,9 @@ RTCStatsReport::Stats::Stats(Type type, const GstStructure* structure) RTCStatsReport::RtpStreamStats::RtpStreamStats(Type type, const GstStructure* structure) : Stats(type, structure) - , kind(gstStructureGetString(structure, "kind"_s).toString()) - , transportId(gstStructureGetString(structure, "transport-id"_s).toString()) - , codecId(gstStructureGetString(structure, "codec-id"_s).toString()) + , kind(gstStructureGetString(structure, "kind"_s).span()) + , transportId(gstStructureGetString(structure, "transport-id"_s).span()) + , codecId(gstStructureGetString(structure, "codec-id"_s).span()) { if (auto value = gstStructureGet(structure, "ssrc"_s)) ssrc = *value; @@ -65,8 +65,8 @@ RTCStatsReport::SentRtpStreamStats::SentRtpStreamStats(Type type, const GstStruc RTCStatsReport::CodecStats::CodecStats(const GstStructure* structure) : Stats(Type::Codec, structure) - , mimeType(gstStructureGetString(structure, "mime-type"_s).toString()) - , sdpFmtpLine(gstStructureGetString(structure, "sdp-fmtp-line"_s).toString()) + , mimeType(gstStructureGetString(structure, "mime-type"_s).span()) + , sdpFmtpLine(gstStructureGetString(structure, "sdp-fmtp-line"_s).span()) { clockRate = gstStructureGet(structure, "clock-rate"_s); channels = gstStructureGet(structure, "channels"_s); @@ -98,7 +98,7 @@ RTCStatsReport::ReceivedRtpStreamStats::ReceivedRtpStreamStats(Type type, const RTCStatsReport::RemoteInboundRtpStreamStats::RemoteInboundRtpStreamStats(const GstStructure* structure) : ReceivedRtpStreamStats(Type::RemoteInboundRtp, structure) - , localId(gstStructureGetString(structure, "local-id"_s).toString()) + , localId(gstStructureGetString(structure, "local-id"_s).span()) { roundTripTime = gstStructureGet(structure, "round-trip-time"_s); fractionLost = gstStructureGet(structure, "fraction-lost"_s); @@ -110,7 +110,7 @@ RTCStatsReport::RemoteInboundRtpStreamStats::RemoteInboundRtpStreamStats(const G RTCStatsReport::RemoteOutboundRtpStreamStats::RemoteOutboundRtpStreamStats(const GstStructure* structure) : SentRtpStreamStats(Type::RemoteOutboundRtp, structure) - , localId(gstStructureGetString(structure, "local-id"_s).toString()) + , localId(gstStructureGetString(structure, "local-id"_s).span()) { remoteTimestamp = gstStructureGet(structure, "remote-timestamp"_s); @@ -139,7 +139,7 @@ RTCStatsReport::InboundRtpStreamStats::InboundRtpStreamStats(const GstStructure* frameHeight = gstStructureGet(structure, "frame-height"_s); if (auto identifier = gstStructureGetString(structure, "track-identifier"_s)) - trackIdentifier = identifier.toString(); + trackIdentifier = identifier.span(); // FIXME: // stats.fractionLost = @@ -155,7 +155,7 @@ RTCStatsReport::InboundRtpStreamStats::InboundRtpStreamStats(const GstStructure* RTCStatsReport::OutboundRtpStreamStats::OutboundRtpStreamStats(const GstStructure* structure) : SentRtpStreamStats(Type::OutboundRtp, structure) - , remoteId(gstStructureGetString(structure, "remote-id"_s).toString()) + , remoteId(gstStructureGetString(structure, "remote-id"_s).span()) { firCount = gstStructureGet(structure, "fir-count"_s); pliCount = gstStructureGet(structure, "pli-count"_s); @@ -169,9 +169,9 @@ RTCStatsReport::OutboundRtpStreamStats::OutboundRtpStreamStats(const GstStructur framesPerSecond = gstStructureGet(structure, "frames-per-second"_s); if (auto midValue = gstStructureGetString(structure, "mid"_s)) - mid = midValue.toString(); + mid = midValue.span(); if (auto ridValue = gstStructureGetString(structure, "rid"_s)) - rid = ridValue.toString(); + rid = ridValue.span(); } RTCStatsReport::PeerConnectionStats::PeerConnectionStats(const GstStructure* structure) @@ -183,7 +183,7 @@ RTCStatsReport::PeerConnectionStats::PeerConnectionStats(const GstStructure* str RTCStatsReport::TransportStats::TransportStats(const GstStructure* structure) : Stats(Type::Transport, structure) - , selectedCandidatePairId(gstStructureGetString(structure, "selected-candidate-pair-id"_s).toString()) + , selectedCandidatePairId(gstStructureGetString(structure, "selected-candidate-pair-id"_s).span()) { // FIXME: This field is required, GstWebRTC doesn't provide it, so hard-code a value here. dtlsState = RTCDtlsTransportState::Connected; @@ -199,7 +199,7 @@ RTCStatsReport::TransportStats::TransportStats(const GstStructure* structure) // stats.srtpCipher = } -static inline RTCIceCandidateType iceCandidateType(StringView type) +static inline RTCIceCandidateType iceCandidateType(CStringView type) { if (type == "host"_s) return RTCIceCandidateType::Host; @@ -215,10 +215,10 @@ static inline RTCIceCandidateType iceCandidateType(StringView type) RTCStatsReport::IceCandidateStats::IceCandidateStats(GstWebRTCStatsType statsType, const GstStructure* structure) : Stats(statsType == GST_WEBRTC_STATS_REMOTE_CANDIDATE ? Type::RemoteCandidate : Type::LocalCandidate, structure) - , transportId(gstStructureGetString(structure, "transport-id"_s).toString()) - , address(gstStructureGetString(structure, "address"_s).toString()) - , protocol(gstStructureGetString(structure, "protocol"_s).toString()) - , url(gstStructureGetString(structure, "url"_s).toString()) + , transportId(gstStructureGetString(structure, "transport-id"_s).span()) + , address(gstStructureGetString(structure, "address"_s).span()) + , protocol(gstStructureGetString(structure, "protocol"_s).span()) + , url(gstStructureGetString(structure, "url"_s).span()) { port = gstStructureGet(structure, "port"_s); priority = gstStructureGet(structure, "priority"_s); @@ -229,8 +229,8 @@ RTCStatsReport::IceCandidateStats::IceCandidateStats(GstWebRTCStatsType statsTyp RTCStatsReport::IceCandidatePairStats::IceCandidatePairStats(const GstStructure* structure) : Stats(Type::CandidatePair, structure) - , localCandidateId(gstStructureGetString(structure, "local-candidate-id"_s).toString()) - , remoteCandidateId(gstStructureGetString(structure, "remote-candidate-id"_s).toString()) + , localCandidateId(gstStructureGetString(structure, "local-candidate-id"_s).span()) + , remoteCandidateId(gstStructureGetString(structure, "remote-candidate-id"_s).span()) { // FIXME // stats.transportId = diff --git a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerWebRTCUtils.cpp b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerWebRTCUtils.cpp index 198762cf6261d..ae55ffcae0823 100644 --- a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerWebRTCUtils.cpp +++ b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerWebRTCUtils.cpp @@ -164,7 +164,7 @@ static inline RTCRtpEncodingParameters toRTCEncodingParameters(const GstStructur parameters.maxFramerate = *maxFramerate; if (auto rid = gstStructureGetString(rtcParameters, "rid"_s)) - parameters.rid = makeString(rid); + parameters.rid = rid.span(); if (auto scaleResolutionDownBy = gstStructureGet(rtcParameters, "scale-resolution-down-by"_s)) parameters.scaleResolutionDownBy = *scaleResolutionDownBy; @@ -186,7 +186,7 @@ static inline RTCRtpCodecParameters toRTCCodecParameters(const GstStructure* rtc parameters.payloadType = *pt; if (auto mimeType = gstStructureGetString(rtcParameters, "mime-type"_s)) - parameters.mimeType = mimeType.toString(); + parameters.mimeType = mimeType.span(); if (auto clockRate = gstStructureGet(rtcParameters, "clock-rate"_s)) parameters.clockRate = *clockRate; @@ -195,7 +195,7 @@ static inline RTCRtpCodecParameters toRTCCodecParameters(const GstStructure* rtc parameters.channels = *channels; if (auto fmtpLine = gstStructureGetString(rtcParameters, "fmtp-line"_s)) - parameters.sdpFmtpLine = fmtpLine.toString(); + parameters.sdpFmtpLine = fmtpLine.span(); return parameters; } @@ -207,7 +207,7 @@ RTCRtpSendParameters toRTCRtpSendParameters(const GstStructure* rtcParameters) RTCRtpSendParameters parameters; if (auto transactionId = gstStructureGetString(rtcParameters, "transaction-id"_s)) - parameters.transactionId = makeString(transactionId); + parameters.transactionId = transactionId.span(); if (auto encodings = gst_structure_get_value(rtcParameters, "encodings")) { unsigned size = gst_value_list_get_size(encodings); @@ -405,7 +405,7 @@ static String x509Serialize(X509* x509) if (length <= 0) return { }; - return String::fromUTF8({ data, static_cast(length) }); + return String(byteCast(unsafeMakeSpan(data, length))); } static String privateKeySerialize(EVP_PKEY* privateKey) @@ -422,7 +422,7 @@ static String privateKeySerialize(EVP_PKEY* privateKey) if (length <= 0) return { }; - return String::fromUTF8({ data, static_cast(length) }); + return String(byteCast(unsafeMakeSpan(data, length))); } std::optional> generateCertificate(Ref&& origin, const PeerConnectionBackend::CertificateInformation& info) @@ -528,12 +528,12 @@ std::optional> generateCertificate(Ref&& ori return RTCCertificate::create(WTFMove(origin), expirationTime.milliseconds(), WTFMove(fingerprints), WTFMove(pem), WTFMove(serializedPrivateKey)); } -bool sdpMediaHasAttributeKey(const GstSDPMedia* media, const char* key) +bool sdpMediaHasAttributeKey(const GstSDPMedia* media, ASCIILiteral key) { unsigned len = gst_sdp_media_attributes_len(media); for (unsigned i = 0; i < len; i++) { const auto* attribute = gst_sdp_media_get_attribute(media, i); - if (!g_strcmp0(attribute->key, key)) + if (equal(unsafeSpan(attribute->key), key)) return true; } @@ -555,7 +555,7 @@ uint32_t UniqueSSRCGenerator::generateSSRC() return std::numeric_limits::max(); } -std::optional payloadTypeForEncodingName(StringView encodingName) +std::optional payloadTypeForEncodingName(const String& encodingName) { static HashMap staticPayloadTypes = { { "PCMU"_s, 0 }, @@ -563,9 +563,8 @@ std::optional payloadTypeForEncodingName(StringView encodingName) { "G722"_s, 9 }, }; - const auto key = encodingName.toStringWithoutCopying(); - if (staticPayloadTypes.contains(key)) - return staticPayloadTypes.get(key); + if (staticPayloadTypes.contains(encodingName)) + return staticPayloadTypes.get(encodingName); return { }; } @@ -588,7 +587,7 @@ GRefPtr capsFromRtpCapabilities(const RTCRtpCapabilities& capabilities, gst_structure_set(codecStructure, "encoding-params", G_TYPE_STRING, makeString(*codec.channels).ascii().data(), nullptr); if (auto encodingName = gstStructureGetString(codecStructure, "encoding-name"_s)) { - if (auto payloadType = payloadTypeForEncodingName(encodingName)) + if (auto payloadType = payloadTypeForEncodingName(encodingName.span())) gst_structure_set(codecStructure, "payload", G_TYPE_INT, *payloadType, nullptr); } @@ -610,13 +609,14 @@ GstWebRTCRTPTransceiverDirection getDirectionFromSDPMedia(const GstSDPMedia* med for (unsigned i = 0; i < gst_sdp_media_attributes_len(media); i++) { const auto* attribute = gst_sdp_media_get_attribute(media, i); - if (!g_strcmp0(attribute->key, "sendonly")) + auto key = CStringView::unsafeFromUTF8(attribute->key); + if (key == "sendonly"_s) return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY; - if (!g_strcmp0(attribute->key, "sendrecv")) + if (key == "sendrecv"_s) return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV; - if (!g_strcmp0(attribute->key, "recvonly")) + if (key == "recvonly"_s) return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY; - if (!g_strcmp0(attribute->key, "inactive")) + if (key == "inactive"_s) return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE; } @@ -629,16 +629,15 @@ GRefPtr capsFromSDPMedia(const GstSDPMedia* media) unsigned numberOfFormats = gst_sdp_media_formats_len(media); auto caps = adoptGRef(gst_caps_new_empty()); for (unsigned i = 0; i < numberOfFormats; i++) { - const char* rtpMapValue = gst_sdp_media_get_attribute_val_n(media, "rtpmap", i); - if (!rtpMapValue) { + auto rtpMap = CStringView::unsafeFromUTF8(gst_sdp_media_get_attribute_val_n(media, "rtpmap", i)); + if (!rtpMap) { GST_DEBUG("Skipping media format without rtpmap"); continue; } - auto rtpMap = StringView::fromLatin1(rtpMapValue); - auto components = rtpMap.split(' '); + auto components = String(rtpMap.span()).split(' '); auto payloadType = parseInteger(*components.begin()); if (!payloadType) { - GST_WARNING("Invalid payload type in rtpmap %s", rtpMap.utf8().data()); + GST_WARNING("Invalid payload type in rtpmap %s", rtpMap.utf8()); continue; } @@ -661,8 +660,8 @@ GRefPtr capsFromSDPMedia(const GstSDPMedia* media) "a-sendonly", "a-recvonly", "a-end-of-candidates", nullptr); if (auto name = gstStructureGetString(structure, "encoding-name"_s)) { - auto encodingName = name.convertToASCIIUppercase(); - gst_structure_set(structure, "encoding-name", G_TYPE_STRING, encodingName.ascii().data(), nullptr); + auto encodingName = convertToASCIIUppercase(name.span()); + gst_structure_set(structure, "encoding-name", G_TYPE_STRING, encodingName.data(), nullptr); } // Remove ssrc- attributes that end up being accumulated in fmtp SDP media parameters. @@ -683,11 +682,11 @@ void setSsrcAudioLevelVadOn(GstStructure* structure) { unsigned totalFields = gst_structure_n_fields(structure); for (unsigned i = 0; i < totalFields; i++) { - String fieldName = WTF::span(gst_structure_nth_field_name(structure, i)); - if (!fieldName.startsWith("extmap-"_s)) + auto fieldName = CStringView::unsafeFromUTF8(gst_structure_nth_field_name(structure, i)); + if (!startsWith(fieldName.span(), "extmap-"_s)) continue; - const auto value = gst_structure_get_value(structure, fieldName.ascii().data()); + const auto value = gst_structure_get_value(structure, fieldName.utf8()); if (!G_VALUE_HOLDS_STRING(value)) continue; @@ -710,8 +709,9 @@ void setSsrcAudioLevelVadOn(GstStructure* structure) g_value_set_static_string(&stringValue, "vad=on"); gst_value_array_append_and_take_value(&arrayValue, &stringValue); - gst_structure_remove_field(structure, fieldName.ascii().data()); - gst_structure_take_value(structure, fieldName.ascii().data(), &arrayValue); + GMallocString fieldNameCopy(fieldName); + gst_structure_remove_field(structure, fieldNameCopy.utf8()); + gst_structure_take_value(structure, fieldNameCopy.utf8(), &arrayValue); } } diff --git a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerWebRTCUtils.h b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerWebRTCUtils.h index e6f38a89d7136..460a5d37f7227 100644 --- a/Source/WebCore/Modules/mediastream/gstreamer/GStreamerWebRTCUtils.h +++ b/Source/WebCore/Modules/mediastream/gstreamer/GStreamerWebRTCUtils.h @@ -269,7 +269,7 @@ ExceptionOr>fromRTCSendParameters(const RTCRtpSendParam std::optional> generateCertificate(Ref&&, const PeerConnectionBackend::CertificateInformation&); -bool sdpMediaHasAttributeKey(const GstSDPMedia*, const char* key); +bool sdpMediaHasAttributeKey(const GstSDPMedia*, ASCIILiteral key); class UniqueSSRCGenerator : public ThreadSafeRefCounted { WTF_MAKE_FAST_ALLOCATED; @@ -283,7 +283,7 @@ class UniqueSSRCGenerator : public ThreadSafeRefCounted { Vector m_knownIds WTF_GUARDED_BY_LOCK(m_lock); }; -std::optional payloadTypeForEncodingName(StringView encodingName); +std::optional payloadTypeForEncodingName(const String& encodingName); WARN_UNUSED_RETURN GRefPtr capsFromRtpCapabilities(const RTCRtpCapabilities&, Function supplementCapsCallback); diff --git a/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp index 75cc35a9a72ae..9865cc0a1407d 100644 --- a/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp +++ b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp @@ -848,6 +848,8 @@ void LibWebRTCMediaEndpoint::OnStatsDelivered(const rtc::scoped_refptr> decryptAES128GCMPayload(const ClientKeys& clientK * CEK = HMAC-SHA-256(PRK, cek_info || 0x01)[0..15] */ static const uint8_t cekInfo[] = "Content-Encoding: aes128gcm\x00\x01"; - auto cek = hmacSHA256(prk, std::span(cekInfo, sizeof(cekInfo) - 1)); + auto cek = hmacSHA256(prk, byteCast(std::span(cekInfo, sizeof(cekInfo) - 1))); cek.shrink(16); /* @@ -160,7 +160,7 @@ std::optional> decryptAES128GCMPayload(const ClientKeys& clientK * NONCE = HMAC-SHA-256(PRK, nonce_info || 0x01)[0..11] */ static const uint8_t nonceInfo[] = "Content-Encoding: nonce\x00\x01"; - auto nonce = hmacSHA256(prk, std::span(nonceInfo, sizeof(nonceInfo) - 1)); + auto nonce = hmacSHA256(prk, byteCast(std::span(nonceInfo, sizeof(nonceInfo) - 1))); nonce.shrink(12); // Finally, decrypt with AES128GCM and return the unpadded plaintext. @@ -238,7 +238,7 @@ std::optional> decryptAESGCMPayload(const ClientKeys& clientKeys */ static const uint8_t authInfo[] = "Content-Encoding: auth\x00\x01"; auto prkCombine = hmacSHA256(clientKeys.sharedAuthSecret, *ecdhSecretResult); - auto ikm = hmacSHA256(prkCombine, std::span(authInfo, sizeof(authInfo) - 1)); + auto ikm = hmacSHA256(prkCombine, byteCast(std::span(authInfo, sizeof(authInfo) - 1))); auto prk = hmacSHA256(salt, ikm); /* diff --git a/Source/WebCore/Modules/webdatabase/Database.cpp b/Source/WebCore/Modules/webdatabase/Database.cpp index e194d3543e8f3..d2560b61dc457 100644 --- a/Source/WebCore/Modules/webdatabase/Database.cpp +++ b/Source/WebCore/Modules/webdatabase/Database.cpp @@ -107,7 +107,7 @@ static const String& fullyQualifiedInfoTableName() static String formatErrorMessage(ASCIILiteral message, int sqliteErrorCode, const char* sqliteErrorMessage) { - return makeString(message, " ("_s, sqliteErrorCode, ' ', span(sqliteErrorMessage), ')'); + return makeString(message, " ("_s, sqliteErrorCode, ' ', unsafeSpan(sqliteErrorMessage), ')'); } static bool setTextValueInDatabase(SQLiteDatabase& db, StringView query, const String& value) diff --git a/Source/WebCore/Modules/webdatabase/SQLError.h b/Source/WebCore/Modules/webdatabase/SQLError.h index 72f5053a0c842..13078763c0ded 100644 --- a/Source/WebCore/Modules/webdatabase/SQLError.h +++ b/Source/WebCore/Modules/webdatabase/SQLError.h @@ -42,7 +42,7 @@ class SQLError : public ThreadSafeRefCounted { } static Ref create(unsigned code, ASCIILiteral message, int sqliteCode, const char* sqliteMessage) { - return create(code, makeString(message, " ("_s, sqliteCode, ' ', span(sqliteMessage), ')')); + return create(code, makeString(message, " ("_s, sqliteCode, ' ', unsafeSpan(sqliteMessage), ')')); } unsigned code() const { return m_code; } diff --git a/Source/WebCore/Modules/websockets/WebSocketHandshake.cpp b/Source/WebCore/Modules/websockets/WebSocketHandshake.cpp index 60657b749d1b6..b259df8a9edf7 100644 --- a/Source/WebCore/Modules/websockets/WebSocketHandshake.cpp +++ b/Source/WebCore/Modules/websockets/WebSocketHandshake.cpp @@ -86,9 +86,10 @@ static String hostName(const URL& url, bool secure) static constexpr size_t maxInputSampleSize = 128; static String trimInputSample(std::span input) { + // FIXME: Unclear why this is Latin-1 and not UTF-8. if (input.size() <= maxInputSampleSize) - return input; - return makeString(input.first(maxInputSampleSize), horizontalEllipsis); + return byteCast(input); + return makeString(byteCast(input.first(maxInputSampleSize)), horizontalEllipsis); } static String generateSecWebSocketKey() @@ -409,24 +410,24 @@ int WebSocketHandshake::readStatusLine(std::span header, int& sta return lineLength; } - StringView httpStatusLine(header.first(*firstSpaceIndex)); + StringView httpStatusLine(byteCast(header.first(*firstSpaceIndex))); if (!headerHasValidHTTPVersion(httpStatusLine)) { m_failureReason = makeString("Invalid HTTP version string: "_s, httpStatusLine); return lineLength; } - StringView statusCodeString(header.subspan(*firstSpaceIndex + 1, *secondSpaceIndex - *firstSpaceIndex - 1)); - if (statusCodeString.length() != 3) // Status code must consist of three digits. + auto statusCodeString = byteCast(header.subspan(*firstSpaceIndex + 1, *secondSpaceIndex - *firstSpaceIndex - 1)); + if (statusCodeString.size() != 3) // Status code must consist of three digits. return lineLength; - for (int i = 0; i < 3; ++i) { - if (!isASCIIDigit(statusCodeString[i])) { + for (auto digit : statusCodeString) { + if (!isASCIIDigit(digit)) { m_failureReason = makeString("Invalid status code: "_s, statusCodeString); return lineLength; } } statusCode = parseInteger(statusCodeString).value(); - statusText = String(header.subspan(*secondSpaceIndex + 1, index - *secondSpaceIndex - 3)); // Exclude "\r\n". + statusText = String(byteCast(header.subspan(*secondSpaceIndex + 1, index - *secondSpaceIndex - 3))); // Exclude "\r\n". return lineLength; } diff --git a/Source/WebCore/PAL/pal/Gunzip.h b/Source/WebCore/PAL/pal/Gunzip.h index 842ee3d75645e..47d980924ce81 100644 --- a/Source/WebCore/PAL/pal/Gunzip.h +++ b/Source/WebCore/PAL/pal/Gunzip.h @@ -26,13 +26,13 @@ #pragma once #include -#include +#include namespace PAL { // This function is only suitable for zip files which are guaranteed to not have any flags set in their headers. // See https://tools.ietf.org/html/rfc1952 for more information. -PAL_EXPORT Vector gunzip(const unsigned char* data, size_t length); +PAL_EXPORT Vector gunzip(const unsigned char* data, size_t length); } diff --git a/Source/WebCore/PAL/pal/cocoa/Gunzip.cpp b/Source/WebCore/PAL/pal/cocoa/Gunzip.cpp index 18cbb9949bd90..524597b101115 100644 --- a/Source/WebCore/PAL/pal/cocoa/Gunzip.cpp +++ b/Source/WebCore/PAL/pal/cocoa/Gunzip.cpp @@ -30,9 +30,9 @@ namespace PAL { -Vector gunzip(const unsigned char* data, size_t length) +Vector gunzip(const unsigned char* data, size_t length) { - Vector result; + Vector result; // Parse the gzip header. auto checks = [&]() { diff --git a/Source/WebCore/PAL/pal/text/TextCodecASCIIFastPath.h b/Source/WebCore/PAL/pal/text/TextCodecASCIIFastPath.h index 06c75137d7136..47d2ac3babcc8 100644 --- a/Source/WebCore/PAL/pal/text/TextCodecASCIIFastPath.h +++ b/Source/WebCore/PAL/pal/text/TextCodecASCIIFastPath.h @@ -32,7 +32,7 @@ namespace PAL { template struct UCharByteFiller; template<> struct UCharByteFiller<4> { - static void copy(LChar* destination, const uint8_t* source) + static void copy(Latin1Character* destination, const uint8_t* source) { memcpy(destination, source, 4); } @@ -46,7 +46,7 @@ template<> struct UCharByteFiller<4> { } }; template<> struct UCharByteFiller<8> { - static void copy(LChar* destination, const uint8_t* source) + static void copy(Latin1Character* destination, const uint8_t* source) { memcpy(destination, source, 8); } @@ -64,7 +64,7 @@ template<> struct UCharByteFiller<8> { } }; -inline void copyASCIIMachineWord(LChar* destination, const uint8_t* source) +inline void copyASCIIMachineWord(Latin1Character* destination, const uint8_t* source) { UCharByteFiller::copy(destination, source); } diff --git a/Source/WebCore/PAL/pal/text/TextCodecLatin1.cpp b/Source/WebCore/PAL/pal/text/TextCodecLatin1.cpp index 17bff34214530..686ea1a5e183f 100644 --- a/Source/WebCore/PAL/pal/text/TextCodecLatin1.cpp +++ b/Source/WebCore/PAL/pal/text/TextCodecLatin1.cpp @@ -33,7 +33,7 @@ namespace PAL { -static const UChar latin1ConversionTable[256] = { +static const char16_t latin1ConversionTable[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, // 00-07 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, // 08-0F 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, // 10-17 @@ -99,7 +99,7 @@ void TextCodecLatin1::registerCodecs(TextCodecRegistrar registrar) String TextCodecLatin1::decode(std::span bytes, bool, bool, bool& sawException) { - LChar* characters; + Latin1Character* characters; if (bytes.empty()) return emptyString(); if (UNLIKELY(bytes.size() > std::numeric_limits::max())) { @@ -112,7 +112,7 @@ String TextCodecLatin1::decode(std::span bytes, bool, bool, bool& const uint8_t* source = bytes.data(); const uint8_t* end = bytes.data() + bytes.size(); const uint8_t* alignedEnd = WTF::alignToMachineWord(end); - LChar* destination = characters; + Latin1Character* destination = characters; while (source < end) { if (isASCII(*source)) { @@ -121,7 +121,7 @@ String TextCodecLatin1::decode(std::span bytes, bool, bool, bool& while (source < alignedEnd) { auto chunk = *reinterpret_cast_ptr(source); - if (!WTF::containsOnlyASCII(chunk)) + if (!WTF::containsOnlyASCII(chunk)) goto useLookupTable; copyASCIIMachineWord(destination, source); @@ -152,14 +152,14 @@ String TextCodecLatin1::decode(std::span bytes, bool, bool, bool& return result; upConvertTo16Bit: - UChar* characters16; + char16_t* characters16; String result16 = String::createUninitialized(bytes.size(), characters16); - UChar* destination16 = characters16; + char16_t* destination16 = characters16; // Zero extend and copy already processed 8 bit data - LChar* ptr8 = characters; - LChar* endPtr8 = destination; + Latin1Character* ptr8 = characters; + Latin1Character* endPtr8 = destination; while (ptr8 < endPtr8) *destination16++ = *ptr8++; @@ -176,7 +176,7 @@ String TextCodecLatin1::decode(std::span bytes, bool, bool, bool& while (source < alignedEnd) { auto chunk = *reinterpret_cast_ptr(source); - if (!WTF::containsOnlyASCII(chunk)) + if (!WTF::containsOnlyASCII(chunk)) goto useLookupTable16; copyASCIIMachineWord(destination16, source); @@ -237,7 +237,7 @@ Vector TextCodecLatin1::encode(StringView string, UnencodableHandling h auto* bytes = result.data(); // Convert and simultaneously do a check to see if it's all ASCII. - UChar ored = 0; + char16_t ored = 0; for (auto character : string.codeUnits()) { *bytes++ = character; ored |= character; diff --git a/Source/WebCore/PAL/pal/text/TextCodecUTF8.cpp b/Source/WebCore/PAL/pal/text/TextCodecUTF8.cpp index e3702858f31c9..1d4a44ea114aa 100644 --- a/Source/WebCore/PAL/pal/text/TextCodecUTF8.cpp +++ b/Source/WebCore/PAL/pal/text/TextCodecUTF8.cpp @@ -162,7 +162,7 @@ static inline int decodeNonASCIISequence(const uint8_t* sequence, uint8_t& lengt return ((sequence[0] << 18) + (sequence[1] << 12) + (sequence[2] << 6) + sequence[3]) - 0x03C82080; } -static inline UChar* appendCharacter(UChar* destination, int character) +static inline char16_t* appendCharacter(char16_t* destination, int character) { ASSERT(character != nonCharacter); ASSERT(!U_IS_SURROGATE(character)); @@ -181,7 +181,7 @@ void TextCodecUTF8::consumePartialSequenceByte() memmove(m_partialSequence, m_partialSequence + 1, m_partialSequenceSize); } -bool TextCodecUTF8::handlePartialSequence(LChar*& destination, std::span& source, bool flush) +bool TextCodecUTF8::handlePartialSequence(Latin1Character*& destination, std::span& source, bool flush) { ASSERT(m_partialSequenceSize); do { @@ -232,7 +232,7 @@ bool TextCodecUTF8::handlePartialSequence(LChar*& destination, std::span& source, bool flush, bool stopOnError, bool& sawError) +void TextCodecUTF8::handlePartialSequence(char16_t*& destination, std::span& source, bool flush, bool stopOnError, bool& sawError) { ASSERT(m_partialSequenceSize); do { @@ -306,18 +306,18 @@ String TextCodecUTF8::decode(std::span bytes, bool flush, bool st sawError = true; return { }; } - StringBuffer buffer(bufferSize); + StringBuffer buffer(bufferSize); auto source = bytes; auto* alignedEnd = WTF::alignToMachineWord(bytes.data() + bytes.size()); - LChar* destination = buffer.characters(); + Latin1Character* destination = buffer.characters(); do { if (m_partialSequenceSize) { // Explicitly copy destination and source pointers to avoid taking pointers to the // local variables, which may harm code generation by disabling some optimizations // in some compilers. - LChar* destinationForHandlePartialSequence = destination; + Latin1Character* destinationForHandlePartialSequence = destination; if (handlePartialSequence(destinationForHandlePartialSequence, source, flush)) { goto upConvertTo16Bit; } @@ -332,7 +332,7 @@ String TextCodecUTF8::decode(std::span bytes, bool flush, bool st if (WTF::isAlignedToMachineWord(source.data())) { while (source.data() < alignedEnd) { auto chunk = *reinterpret_cast_ptr(source.data()); - if (!WTF::containsOnlyASCII(chunk)) + if (!WTF::containsOnlyASCII(chunk)) break; copyASCIIMachineWord(destination, source.data()); source = source.subspan(sizeof(WTF::MachineWord)); @@ -385,12 +385,12 @@ String TextCodecUTF8::decode(std::span bytes, bool flush, bool st return String::adopt(WTFMove(buffer)); upConvertTo16Bit: - StringBuffer buffer16(bufferSize); + StringBuffer buffer16(bufferSize); - UChar* destination16 = buffer16.characters(); + char16_t* destination16 = buffer16.characters(); // Copy the already converted characters - for (LChar* converted8 = buffer.characters(); converted8 < destination;) + for (Latin1Character* converted8 = buffer.characters(); converted8 < destination;) *destination16++ = *converted8++; do { @@ -398,7 +398,7 @@ String TextCodecUTF8::decode(std::span bytes, bool flush, bool st // Explicitly copy destination and source pointers to avoid taking pointers to the // local variables, which may harm code generation by disabling some optimizations // in some compilers. - UChar* destinationForHandlePartialSequence = destination16; + char16_t* destinationForHandlePartialSequence = destination16; handlePartialSequence(destinationForHandlePartialSequence, source, flush, stopOnError, sawError); destination16 = destinationForHandlePartialSequence; if (m_partialSequenceSize) @@ -411,7 +411,7 @@ String TextCodecUTF8::decode(std::span bytes, bool flush, bool st if (WTF::isAlignedToMachineWord(source.data())) { while (source.data() < alignedEnd) { auto chunk = *reinterpret_cast_ptr(source.data()); - if (!WTF::containsOnlyASCII(chunk)) + if (!WTF::containsOnlyASCII(chunk)) break; copyASCIIMachineWord(destination16, source.data()); source = source.subspan(sizeof(WTF::MachineWord)); diff --git a/Source/WebCore/PAL/pal/text/TextCodecUTF8.h b/Source/WebCore/PAL/pal/text/TextCodecUTF8.h index 873bc6b1ffad4..8277f740f9ee3 100644 --- a/Source/WebCore/PAL/pal/text/TextCodecUTF8.h +++ b/Source/WebCore/PAL/pal/text/TextCodecUTF8.h @@ -27,7 +27,7 @@ #include "TextCodec.h" #include -#include +#include namespace PAL { @@ -44,8 +44,8 @@ class TextCodecUTF8 final : public TextCodec { String decode(std::span, bool flush, bool stopOnError, bool& sawError) final; Vector encode(StringView, UnencodableHandling) const final; - bool handlePartialSequence(LChar*& destination, std::span& source, bool flush); - void handlePartialSequence(UChar*& destination, std::span& source, bool flush, bool stopOnError, bool& sawError); + bool handlePartialSequence(Latin1Character*& destination, std::span& source, bool flush); + void handlePartialSequence(char16_t*& destination, std::span& source, bool flush, bool stopOnError, bool& sawError); void consumePartialSequenceByte(); int m_partialSequenceSize { 0 }; diff --git a/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp b/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp index 06abf198aa081..f1ad7dbe7ed27 100644 --- a/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp +++ b/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp @@ -295,8 +295,8 @@ JSC::EncodedJSValue rejectPromiseWithGetterTypeError(JSC::JSGlobalObject& lexica String makeThisTypeErrorMessage(const char* interfaceName, const char* functionName) { - auto interfaceNameSpan = span(interfaceName); - return makeString("Can only call "_s, interfaceNameSpan, '.', span(functionName), " on instances of "_s, interfaceNameSpan); + auto interfaceNameSpan = unsafeSpan(interfaceName); + return makeString("Can only call "_s, interfaceNameSpan, '.', unsafeSpan(functionName), " on instances of "_s, interfaceNameSpan); } String makeUnsupportedIndexedSetterErrorMessage(ASCIILiteral interfaceName) diff --git a/Source/WebCore/bindings/js/ScriptBufferSourceProvider.h b/Source/WebCore/bindings/js/ScriptBufferSourceProvider.h index adb20d913303e..83f23dbf94fee 100644 --- a/Source/WebCore/bindings/js/ScriptBufferSourceProvider.h +++ b/Source/WebCore/bindings/js/ScriptBufferSourceProvider.h @@ -76,7 +76,7 @@ class ScriptBufferSourceProvider final : public JSC::SourceProvider, public Abst m_scriptHash = StringHasher::computeHashAndMaskTop8Bits(m_contiguousBuffer->span()); } if (*m_containsOnlyASCII) - return m_contiguousBuffer->span(); + return byteCast(m_contiguousBuffer->span()); if (!m_cachedScriptString) { m_cachedScriptString = m_scriptBuffer.toString(); diff --git a/Source/WebCore/bridge/IdentifierRep.cpp b/Source/WebCore/bridge/IdentifierRep.cpp index 626f7f780787b..32bad5261b07b 100644 --- a/Source/WebCore/bridge/IdentifierRep.cpp +++ b/Source/WebCore/bridge/IdentifierRep.cpp @@ -91,7 +91,7 @@ IdentifierRep* IdentifierRep::get(const char* name) if (!name) return nullptr; - String string = String::fromUTF8WithLatin1Fallback(span(name)); + String string = String::fromUTF8WithLatin1Fallback(unsafeSpan(name)); StringIdentifierMap::AddResult result = stringIdentifierMap().add(string.impl(), nullptr); if (result.isNewEntry) { ASSERT(!result.iterator->value); diff --git a/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp b/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp index 26c6464aa0653..cee426e7c4c0f 100644 --- a/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp +++ b/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp @@ -203,11 +203,11 @@ void DFABytecodeInterpreter::interpretTestFlagsAndAppendAction(uint32_t& program } template -inline void DFABytecodeInterpreter::interpretJumpTable(std::span url, uint32_t& urlIndex, uint32_t& programCounter) +inline void DFABytecodeInterpreter::interpretJumpTable(std::span url, uint32_t& urlIndex, uint32_t& programCounter) { DFABytecodeJumpSize jumpSize = getJumpSize(m_bytecode, programCounter); - char c = urlIndex < url.size() ? url[urlIndex] : 0; + char c = urlIndex < url.size() ? byteCast(url[urlIndex]) : 0; char character = caseSensitive ? c : toASCIILower(c); uint8_t firstCharacter = getBits(m_bytecode, programCounter + sizeof(DFABytecodeInstruction)); uint8_t lastCharacter = getBits(m_bytecode, programCounter + sizeof(DFABytecodeInstruction) + sizeof(uint8_t)); @@ -245,8 +245,8 @@ auto DFABytecodeInterpreter::actionsMatchingEverything() -> Actions auto DFABytecodeInterpreter::interpret(const String& urlString, ResourceFlags flags) -> Actions { CString urlCString; - std::span url; - if (LIKELY(urlString.is8Bit())) + std::span url; + if (urlString.is8Bit()) [[likely]] url = urlString.span8(); else { urlCString = urlString.utf8(); @@ -299,7 +299,7 @@ auto DFABytecodeInterpreter::interpret(const String& urlString, ResourceFlags fl goto nextDFA; // Check to see if the next character in the url is the value stored with the bytecode. - char character = urlIndex < url.size() ? url[urlIndex] : 0; + char character = urlIndex < url.size() ? byteCast(url[urlIndex]) : 0; DFABytecodeJumpSize jumpSize = getJumpSize(m_bytecode, programCounter); if (character == getBits(m_bytecode, programCounter + sizeof(DFABytecodeInstruction))) { uint32_t jumpLocation = programCounter + sizeof(DFABytecodeInstruction) + sizeof(uint8_t); @@ -315,7 +315,7 @@ auto DFABytecodeInterpreter::interpret(const String& urlString, ResourceFlags fl goto nextDFA; // Check to see if the next character in the url is the value stored with the bytecode. - char character = urlIndex < url.size() ? toASCIILower(url[urlIndex]) : 0; + char character = urlIndex < url.size() ? byteCast(toASCIILower(url[urlIndex])) : 0; DFABytecodeJumpSize jumpSize = getJumpSize(m_bytecode, programCounter); if (character == getBits(m_bytecode, programCounter + sizeof(DFABytecodeInstruction))) { uint32_t jumpLocation = programCounter + sizeof(DFABytecodeInstruction) + sizeof(uint8_t); @@ -343,7 +343,7 @@ auto DFABytecodeInterpreter::interpret(const String& urlString, ResourceFlags fl if (urlIndex > url.size()) goto nextDFA; - char character = urlIndex < url.size() ? url[urlIndex] : 0; + char character = urlIndex < url.size() ? byteCast(url[urlIndex]) : 0; DFABytecodeJumpSize jumpSize = getJumpSize(m_bytecode, programCounter); if (character >= getBits(m_bytecode, programCounter + sizeof(DFABytecodeInstruction)) && character <= getBits(m_bytecode, programCounter + sizeof(DFABytecodeInstruction) + sizeof(uint8_t))) { @@ -359,7 +359,7 @@ auto DFABytecodeInterpreter::interpret(const String& urlString, ResourceFlags fl if (urlIndex > url.size()) goto nextDFA; - char character = urlIndex < url.size() ? toASCIILower(url[urlIndex]) : 0; + char character = urlIndex < url.size() ? byteCast(toASCIILower(url[urlIndex])) : 0; DFABytecodeJumpSize jumpSize = getJumpSize(m_bytecode, programCounter); if (character >= getBits(m_bytecode, programCounter + sizeof(DFABytecodeInstruction)) && character <= getBits(m_bytecode, programCounter + sizeof(DFABytecodeInstruction) + sizeof(uint8_t))) { diff --git a/Source/WebCore/contentextensions/DFABytecodeInterpreter.h b/Source/WebCore/contentextensions/DFABytecodeInterpreter.h index 681ff8c0680e2..e12861c908d5d 100644 --- a/Source/WebCore/contentextensions/DFABytecodeInterpreter.h +++ b/Source/WebCore/contentextensions/DFABytecodeInterpreter.h @@ -50,7 +50,7 @@ class DFABytecodeInterpreter { void interpretTestFlagsAndAppendAction(unsigned& programCounter, ResourceFlags, Actions&); template - void interpretJumpTable(std::span url, uint32_t& urlIndex, uint32_t& programCounter); + void interpretJumpTable(std::span url, uint32_t& urlIndex, uint32_t& programCounter); const std::span m_bytecode; }; diff --git a/Source/WebCore/crypto/SubtleCrypto.cpp b/Source/WebCore/crypto/SubtleCrypto.cpp index 0a38e9e289328..599dedd7ae0aa 100644 --- a/Source/WebCore/crypto/SubtleCrypto.cpp +++ b/Source/WebCore/crypto/SubtleCrypto.cpp @@ -1269,9 +1269,8 @@ void SubtleCrypto::unwrapKey(JSC::JSGlobalObject& state, KeyFormat format, Buffe auto& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); - String jwkString(bytes.span()); JSLockHolder locker(vm); - auto jwkObject = JSONParse(&state, jwkString); + auto jwkObject = JSONParse(&state, byteCast(bytes.span())); if (!jwkObject) { promise->reject(ExceptionCode::DataError, "WrappedKey cannot be converted to a JSON object"_s); return; diff --git a/Source/WebCore/css/CSSVariableData.cpp b/Source/WebCore/css/CSSVariableData.cpp index a54dc6c4d8f55..250f4ee5e6cfb 100644 --- a/Source/WebCore/css/CSSVariableData.cpp +++ b/Source/WebCore/css/CSSVariableData.cpp @@ -75,7 +75,7 @@ CSSVariableData::CSSVariableData(const CSSParserTokenRange& range, const CSSPars if (!stringBuilder.isEmpty()) { m_backingString = stringBuilder.toString(); if (m_backingString.is8Bit()) - updateBackingStringsInTokens(); + updateBackingStringsInTokens(); else updateBackingStringsInTokens(); } diff --git a/Source/WebCore/css/parser/CSSParserToken.h b/Source/WebCore/css/parser/CSSParserToken.h index c11e707445a2e..1ef21802825b0 100644 --- a/Source/WebCore/css/parser/CSSParserToken.h +++ b/Source/WebCore/css/parser/CSSParserToken.h @@ -174,7 +174,7 @@ class CSSParserToken { bool m_valueIs8Bit : 1 { false }; bool m_isBackedByStringLiteral : 1 { false }; unsigned m_valueLength { 0 }; - const void* m_valueDataCharRaw { nullptr }; // Either LChar* or UChar*. + const void* m_valueDataCharRaw { nullptr }; // Either Latin1Character* or char16_t*. union { UChar m_delimiter; diff --git a/Source/WebCore/css/parser/CSSPropertyParser.cpp b/Source/WebCore/css/parser/CSSPropertyParser.cpp index 26b576b4565a5..5e73417725340 100644 --- a/Source/WebCore/css/parser/CSSPropertyParser.cpp +++ b/Source/WebCore/css/parser/CSSPropertyParser.cpp @@ -88,7 +88,7 @@ bool isCustomPropertyName(StringView propertyName) return propertyName.length() > 2 && propertyName.characterAt(0) == '-' && propertyName.characterAt(1) == '-'; } -static bool hasPrefix(std::span string, std::span prefix) +static bool hasPrefix(std::span string, std::span prefix) { if (string.size() < prefix.size()) return false; diff --git a/Source/WebCore/css/parser/CSSTokenizerInputStream.h b/Source/WebCore/css/parser/CSSTokenizerInputStream.h index 9f404d30ace73..0bf6081eb0681 100644 --- a/Source/WebCore/css/parser/CSSTokenizerInputStream.h +++ b/Source/WebCore/css/parser/CSSTokenizerInputStream.h @@ -33,7 +33,7 @@ namespace WebCore { -constexpr LChar kEndOfFileMarker = 0; +constexpr Latin1Character kEndOfFileMarker = 0; DECLARE_ALLOCATOR_WITH_HEAP_IDENTIFIER(CSSTokenizerInputStream); class CSSTokenizerInputStream { diff --git a/Source/WebCore/css/process-css-properties.py b/Source/WebCore/css/process-css-properties.py index 1f510631524dd..94c2a93860ffd 100755 --- a/Source/WebCore/css/process-css-properties.py +++ b/Source/WebCore/css/process-css-properties.py @@ -2560,7 +2560,7 @@ def _generate_lookup_functions(self, *, to): String nameForIDL(CSSPropertyID id) { - LChar characters[maxCSSPropertyNameLength]; + Latin1Character characters[maxCSSPropertyNameLength]; const char* nameForCSS = nameLiteral(id); if (!nameForCSS) return emptyString(); @@ -2576,7 +2576,7 @@ def _generate_lookup_functions(self, *, to): } *nextCharacter++ = character; } - return std::span { characters, nextCharacter }; + return std::span { characters, nextCharacter }; } """) diff --git a/Source/WebCore/css/process-css-pseudo-selectors.py b/Source/WebCore/css/process-css-pseudo-selectors.py index 49ed1cc65651a..de83a7f07a446 100644 --- a/Source/WebCore/css/process-css-pseudo-selectors.py +++ b/Source/WebCore/css/process-css-pseudo-selectors.py @@ -435,7 +435,7 @@ def prefix_value(prefix, value): def write_parsing_function_definitions_for_pseudo_class(self, writer): longest_keyword_length = len(max(self.mapping, key=len)) writer.write_block(""" - static inline const SelectorPseudoClassOrCompatibilityPseudoElementEntry* findPseudoClassAndCompatibilityElementName(std::span characters) + static inline const SelectorPseudoClassOrCompatibilityPseudoElementEntry* findPseudoClassAndCompatibilityElementName(std::span characters) { return SelectorPseudoClassAndCompatibilityElementMapHash::in_word_set(byteCast(characters.data()), characters.size()); }""") @@ -444,7 +444,7 @@ def write_parsing_function_definitions_for_pseudo_class(self, writer): static inline const SelectorPseudoClassOrCompatibilityPseudoElementEntry* findPseudoClassAndCompatibilityElementName(std::span characters) {{ constexpr unsigned maxKeywordLength = {longest_keyword_length}; - std::array buffer; + std::array buffer; if (characters.size() > maxKeywordLength) return nullptr; @@ -453,7 +453,7 @@ def write_parsing_function_definitions_for_pseudo_class(self, writer): if (!isLatin1(character)) return nullptr; - buffer[i] = static_cast(character); + buffer[i] = static_cast(character); }} return findPseudoClassAndCompatibilityElementName(std::span {{ buffer }}.first(characters.size())); }}""") @@ -475,7 +475,7 @@ def write_parsing_function_definitions_for_pseudo_class(self, writer): def write_parsing_function_definitions_for_pseudo_element(self, writer): longest_keyword_length = len(max(self.mapping, key=len)) writer.write_block(""" - static inline std::optional findPseudoElementName(std::span characters) + static inline std::optional findPseudoElementName(std::span characters) { if (auto entry = SelectorPseudoElementMapHash::in_word_set(byteCast(characters.data()), characters.size())) return entry->type; @@ -486,7 +486,7 @@ def write_parsing_function_definitions_for_pseudo_element(self, writer): static inline std::optional findPseudoElementName(std::span characters) {{ constexpr unsigned maxKeywordLength = {longest_keyword_length}; - std::array buffer; + std::array buffer; if (characters.size() > maxKeywordLength) return std::nullopt; @@ -495,7 +495,7 @@ def write_parsing_function_definitions_for_pseudo_element(self, writer): if (!isLatin1(character)) return std::nullopt; - buffer[i] = static_cast(character); + buffer[i] = static_cast(character); }} return findPseudoElementName(std::span {{ buffer }}.first(characters.size())); }}""") diff --git a/Source/WebCore/css/scripts/test/TestCSSPropertiesResults/CSSPropertyNames.gperf b/Source/WebCore/css/scripts/test/TestCSSPropertiesResults/CSSPropertyNames.gperf new file mode 100644 index 0000000000000..73943bf53762e --- /dev/null +++ b/Source/WebCore/css/scripts/test/TestCSSPropertiesResults/CSSPropertyNames.gperf @@ -0,0 +1,935 @@ +%{ +// This file is automatically generated from CSSProperties.json by the process-css-properties.py script. Do not edit it. + +#include "config.h" +#include "CSSPropertyNames.h" + +#include "BoxSides.h" +#include "CSSProperty.h" +#include "Settings.h" +#include +#include +#include +#include +#include + + +IGNORE_WARNINGS_BEGIN("implicit-fallthrough") +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN + +// Older versions of gperf like to use the `register` keyword. +#define register + +namespace WebCore { + +static_assert(cssPropertyIDEnumValueCount <= (std::numeric_limits::max() + 1), "CSSPropertyID should fit into uint16_t."); + +const std::array computedPropertyIDs { + CSSPropertyID::CSSPropertyBackgroundFillLayerTestPrimary, + CSSPropertyID::CSSPropertyBackgroundFillLayerTestSecondary, + CSSPropertyID::CSSPropertyBackgroundFillLayerTestSecondaryWithConverter, + CSSPropertyID::CSSPropertyTestAnimationWrapper, + CSSPropertyID::CSSPropertyTestAnimationWrapperAccelerationAlways, + CSSPropertyID::CSSPropertyTestAnimationWrapperAccelerationThreadedOnly, + CSSPropertyID::CSSPropertyTestAutoFunctions, + CSSPropertyID::CSSPropertyTestBoundedRepetitionWithCommas, + CSSPropertyID::CSSPropertyTestBoundedRepetitionWithCommasFixed, + CSSPropertyID::CSSPropertyTestBoundedRepetitionWithCommasNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestBoundedRepetitionWithCommasSingleItemOpt, + CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpaces, + CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesFixed, + CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesSingleItemOpt, + CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesWithType, + CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesWithTypeNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesWithTypeWithDefaultPrevious, + CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesWithTypeWithDefaultPreviousTwo, + CSSPropertyID::CSSPropertyTestColor, + CSSPropertyID::CSSPropertyTestColorAllowsTypesAbsolute, + CSSPropertyID::CSSPropertyTestColorPropertyWithNoVisitedLinkSupport, + CSSPropertyID::CSSPropertyTestColorPropertyWithVisitedLinkSupport, + CSSPropertyID::CSSPropertyTestCustomExtractor, + CSSPropertyID::CSSPropertyTestExtractorConverter, + CSSPropertyID::CSSPropertyTestFunctionBoundedParameters, + CSSPropertyID::CSSPropertyTestFunctionFixedParameters, + CSSPropertyID::CSSPropertyTestFunctionNoParameters, + CSSPropertyID::CSSPropertyTestFunctionParametersMatchAllAnyOrder, + CSSPropertyID::CSSPropertyTestFunctionParametersMatchAllAnyOrderWithOptional, + CSSPropertyID::CSSPropertyTestFunctionParametersMatchAllOrdered, + CSSPropertyID::CSSPropertyTestFunctionParametersMatchAllOrderedWithOptional, + CSSPropertyID::CSSPropertyTestFunctionParametersMatchOneOrMoreAnyOrder, + CSSPropertyID::CSSPropertyTestFunctionSingleParameter, + CSSPropertyID::CSSPropertyTestFunctionSingleParameterMatchOne, + CSSPropertyID::CSSPropertyTestFunctionSingleParameterOptional, + CSSPropertyID::CSSPropertyTestFunctionUnboundedParametersNoMin, + CSSPropertyID::CSSPropertyTestFunctionUnboundedParametersWithMinimum, + CSSPropertyID::CSSPropertyTestHighPriority, + CSSPropertyID::CSSPropertyTestImage, + CSSPropertyID::CSSPropertyTestImageNoImageSet, + CSSPropertyID::CSSPropertyTestKeyword, + CSSPropertyID::CSSPropertyTestKeywordWithAliasedTo, + CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalBlock, + CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalInline, + CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalHorizontal, + CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalVertical, + CSSPropertyID::CSSPropertyTestMatchAllAnyOrder, + CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithCustomType, + CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptional, + CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndCustomType, + CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndMultipleRequiredAndCustomType, + CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndMultipleRequiredAndCustomTypeNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndMultipleRequiredAndPreserveOrderAndCustomType, + CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndMultipleRequiredAndPreserveOrderAndCustomTypeNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndPreserveOrderAndCustomType, + CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalSingleItemOpt, + CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalWithPreserveOrder, + CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalWithPreserveOrderNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithPreserveOrder, + CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithPreserveOrderAndCustomType, + CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithPreserveOrderNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestMatchAllOrdered, + CSSPropertyID::CSSPropertyTestMatchAllOrderedWithCustomType, + CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptional, + CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalAndCustomType, + CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalAndCustomTypeAndNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalAndMultipleRequired, + CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalAndMultipleRequiredAndCustomType, + CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalSingleItemOpt, + CSSPropertyID::CSSPropertyTestMatchOne, + CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrder, + CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithCustomType, + CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithCustomTypeNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithPreserveOrder, + CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithPreserveOrderAndCustomType, + CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithPreserveOrderAndCustomTypeNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithPreserveOrderNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestMatchOneWithGroupWithSettingsFlag, + CSSPropertyID::CSSPropertyTestMatchOneWithKeywordWithSettingsFlag, + CSSPropertyID::CSSPropertyTestMatchOneWithMultipleKeywords, + CSSPropertyID::CSSPropertyTestMatchOneWithReferenceWithSettingsFlag, + CSSPropertyID::CSSPropertyTestMatchOneWithSettingsFlag, + CSSPropertyID::CSSPropertyTestMediumPriority, + CSSPropertyID::CSSPropertyTestNumericValueRange, + CSSPropertyID::CSSPropertyTestProperty, + CSSPropertyID::CSSPropertyTestSettingsOne, + CSSPropertyID::CSSPropertyTestSharedBuilderExtractorConverter, + CSSPropertyID::CSSPropertyTestSinkPriority, + CSSPropertyID::CSSPropertyTestTopPriority, + CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithCommasWithMin, + CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithCommasWithMinNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithCommasWithMinSingleItemOpt, + CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesNoMin, + CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesNoMinNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesWithMin, + CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesWithMinNoSingleItemOpt, + CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesWithMinSingleItemOpt, + CSSPropertyID::CSSPropertyTestUrlWithModifiers, + CSSPropertyID::CSSPropertyTestUrlWithNoModifiers, + CSSPropertyID::CSSPropertyTestUsingSharedRule, + CSSPropertyID::CSSPropertyTestUsingSharedRuleExported, + CSSPropertyID::CSSPropertyTestUsingSharedRuleWithOverrideFunction, +}; + +constexpr ASCIILiteral propertyNameStrings[numCSSProperties] = { + "test-top-priority"_s, + "test-high-priority"_s, + "background-fill-layer-test-primary"_s, + "test-medium-priority"_s, + "background-fill-layer-test-secondary"_s, + "background-fill-layer-test-secondary-with-converter"_s, + "first-test-descriptor-for-first-descriptor"_s, + "first-test-descriptor-for-second-descriptor"_s, + "test-animation-wrapper"_s, + "test-animation-wrapper-acceleration-always"_s, + "test-animation-wrapper-acceleration-threaded-only"_s, + "test-auto-functions"_s, + "test-bounded-repetition-with-commas"_s, + "test-bounded-repetition-with-commas-fixed"_s, + "test-bounded-repetition-with-commas-no-single-item-opt"_s, + "test-bounded-repetition-with-commas-single-item-opt"_s, + "test-bounded-repetition-with-spaces"_s, + "test-bounded-repetition-with-spaces-fixed"_s, + "test-bounded-repetition-with-spaces-no-single-item-opt"_s, + "test-bounded-repetition-with-spaces-single-item-opt"_s, + "test-bounded-repetition-with-spaces-with-type"_s, + "test-bounded-repetition-with-spaces-with-type-no-single-item-opt"_s, + "test-bounded-repetition-with-spaces-with-type-with-default-previous"_s, + "test-bounded-repetition-with-spaces-with-type-with-default-previous-two"_s, + "test-color"_s, + "test-color-allows-types-absolute"_s, + "test-color-property-with-no-visited-link-support"_s, + "test-color-property-with-visited-link-support"_s, + "test-custom-extractor"_s, + "test-extractor-converter"_s, + "test-function-bounded-parameters"_s, + "test-function-fixed-parameters"_s, + "test-function-no-parameters"_s, + "test-function-parameters-match-all-any-order"_s, + "test-function-parameters-match-all-any-order-with-optional"_s, + "test-function-parameters-match-all-ordered"_s, + "test-function-parameters-match-all-ordered-with-optional"_s, + "test-function-parameters-match-one-or-more-any-order"_s, + "test-function-single-parameter"_s, + "test-function-single-parameter-match-one"_s, + "test-function-single-parameter-optional"_s, + "test-function-unbounded-parameters-no-min"_s, + "test-function-unbounded-parameters-with-minimum"_s, + "test-image"_s, + "test-image-no-image-set"_s, + "test-keyword"_s, + "test-keyword-with-aliased-to"_s, + "test-match-all-any-order"_s, + "test-match-all-any-order-with-custom-type"_s, + "test-match-all-any-order-with-optional"_s, + "test-match-all-any-order-with-optional-and-custom-type"_s, + "test-match-all-any-order-with-optional-and-multiple-required-and-custom-type"_s, + "test-match-all-any-order-with-optional-and-multiple-required-and-custom-type-no-single-item-opt"_s, + "test-match-all-any-order-with-optional-and-multiple-required-and-preserve-order-and-custom-type"_s, + "test-match-all-any-order-with-optional-and-multiple-required-and-preserve-order-and-custom-type-no-single-item-opt"_s, + "test-match-all-any-order-with-optional-and-preserve-order-and-custom-type"_s, + "test-match-all-any-order-with-optional-no-single-item-opt"_s, + "test-match-all-any-order-with-optional-single-item-opt"_s, + "test-match-all-any-order-with-optional-with-preserve-order"_s, + "test-match-all-any-order-with-optional-with-preserve-order-no-single-item-opt"_s, + "test-match-all-any-order-with-preserve-order"_s, + "test-match-all-any-order-with-preserve-order-and-custom-type"_s, + "test-match-all-any-order-with-preserve-order-no-single-item-opt"_s, + "test-match-all-ordered"_s, + "test-match-all-ordered-with-custom-type"_s, + "test-match-all-ordered-with-optional"_s, + "test-match-all-ordered-with-optional-and-custom-type"_s, + "test-match-all-ordered-with-optional-and-custom-type-and-no-single-item-opt"_s, + "test-match-all-ordered-with-optional-and-multiple-required"_s, + "test-match-all-ordered-with-optional-and-multiple-required-and-custom-type"_s, + "test-match-all-ordered-with-optional-no-single-item-opt"_s, + "test-match-all-ordered-with-optional-single-item-opt"_s, + "test-match-one"_s, + "test-match-one-or-more-any-order"_s, + "test-match-one-or-more-any-order-no-single-item-opt"_s, + "test-match-one-or-more-any-order-with-custom-type"_s, + "test-match-one-or-more-any-order-with-custom-type-no-single-item-opt"_s, + "test-match-one-or-more-any-order-with-preserve-order"_s, + "test-match-one-or-more-any-order-with-preserve-order-and-custom-type"_s, + "test-match-one-or-more-any-order-with-preserve-order-and-custom-type-no-single-item-opt"_s, + "test-match-one-or-more-any-order-with-preserve-order-no-single-item-opt"_s, + "test-match-one-with-group-with-settings-flag"_s, + "test-match-one-with-keyword-with-settings-flag"_s, + "test-match-one-with-multiple-keywords"_s, + "test-match-one-with-reference-with-settings-flag"_s, + "test-match-one-with-settings-flag"_s, + "test-numeric-value-range"_s, + "test-property"_s, + "test-settings-one"_s, + "test-shared-builder-extractor-converter"_s, + "test-unbounded-repetition-with-commas-with-min"_s, + "test-unbounded-repetition-with-commas-with-min-no-single-item-opt"_s, + "test-unbounded-repetition-with-commas-with-min-single-item-opt"_s, + "test-unbounded-repetition-with-spaces-no-min"_s, + "test-unbounded-repetition-with-spaces-no-min-no-single-item-opt"_s, + "test-unbounded-repetition-with-spaces-with-min"_s, + "test-unbounded-repetition-with-spaces-with-min-no-single-item-opt"_s, + "test-unbounded-repetition-with-spaces-with-min-single-item-opt"_s, + "test-url-with-modifiers"_s, + "test-url-with-no-modifiers"_s, + "test-using-shared-rule"_s, + "test-using-shared-rule-exported"_s, + "test-using-shared-rule-with-override-function"_s, + "test-sink-priority"_s, + "test-logical-property-group-physical-horizontal"_s, + "test-logical-property-group-physical-vertical"_s, + "test-logical-property-group-logical-block"_s, + "test-logical-property-group-logical-inline"_s, + "all"_s, + "font"_s, + "test-shorthand-one"_s, + "test-shorthand-two"_s, +}; + +%} +%struct-type +struct CSSPropertyHashTableEntry { + const char* name; + uint16_t id; +}; +%language=C++ +%readonly-tables +%global-table +%7bit +%compare-strncmp +%define class-name CSSPropertyNamesHash +%enum + +%% +all, CSSPropertyID::CSSPropertyAll +background-fill-layer-test-primary, CSSPropertyID::CSSPropertyBackgroundFillLayerTestPrimary +background-fill-layer-test-secondary, CSSPropertyID::CSSPropertyBackgroundFillLayerTestSecondary +background-fill-layer-test-secondary-with-converter, CSSPropertyID::CSSPropertyBackgroundFillLayerTestSecondaryWithConverter +first-test-descriptor-for-first-descriptor, CSSPropertyID::CSSPropertyFirstTestDescriptorForFirstDescriptor +first-test-descriptor-for-second-descriptor, CSSPropertyID::CSSPropertyFirstTestDescriptorForSecondDescriptor +font, CSSPropertyID::CSSPropertyFont +test-animation-wrapper, CSSPropertyID::CSSPropertyTestAnimationWrapper +test-animation-wrapper-acceleration-always, CSSPropertyID::CSSPropertyTestAnimationWrapperAccelerationAlways +test-animation-wrapper-acceleration-threaded-only, CSSPropertyID::CSSPropertyTestAnimationWrapperAccelerationThreadedOnly +test-auto-functions, CSSPropertyID::CSSPropertyTestAutoFunctions +test-bounded-repetition-with-commas, CSSPropertyID::CSSPropertyTestBoundedRepetitionWithCommas +test-bounded-repetition-with-commas-fixed, CSSPropertyID::CSSPropertyTestBoundedRepetitionWithCommasFixed +test-bounded-repetition-with-commas-no-single-item-opt, CSSPropertyID::CSSPropertyTestBoundedRepetitionWithCommasNoSingleItemOpt +test-bounded-repetition-with-commas-single-item-opt, CSSPropertyID::CSSPropertyTestBoundedRepetitionWithCommasSingleItemOpt +test-bounded-repetition-with-spaces, CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpaces +test-bounded-repetition-with-spaces-fixed, CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesFixed +test-bounded-repetition-with-spaces-no-single-item-opt, CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesNoSingleItemOpt +test-bounded-repetition-with-spaces-single-item-opt, CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesSingleItemOpt +test-bounded-repetition-with-spaces-with-type, CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesWithType +test-bounded-repetition-with-spaces-with-type-no-single-item-opt, CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesWithTypeNoSingleItemOpt +test-bounded-repetition-with-spaces-with-type-with-default-previous, CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesWithTypeWithDefaultPrevious +test-bounded-repetition-with-spaces-with-type-with-default-previous-two, CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesWithTypeWithDefaultPreviousTwo +test-color, CSSPropertyID::CSSPropertyTestColor +test-color-allows-types-absolute, CSSPropertyID::CSSPropertyTestColorAllowsTypesAbsolute +test-color-property-with-no-visited-link-support, CSSPropertyID::CSSPropertyTestColorPropertyWithNoVisitedLinkSupport +test-color-property-with-visited-link-support, CSSPropertyID::CSSPropertyTestColorPropertyWithVisitedLinkSupport +test-custom-extractor, CSSPropertyID::CSSPropertyTestCustomExtractor +test-extractor-converter, CSSPropertyID::CSSPropertyTestExtractorConverter +test-function-bounded-parameters, CSSPropertyID::CSSPropertyTestFunctionBoundedParameters +test-function-fixed-parameters, CSSPropertyID::CSSPropertyTestFunctionFixedParameters +test-function-no-parameters, CSSPropertyID::CSSPropertyTestFunctionNoParameters +test-function-parameters-match-all-any-order, CSSPropertyID::CSSPropertyTestFunctionParametersMatchAllAnyOrder +test-function-parameters-match-all-any-order-with-optional, CSSPropertyID::CSSPropertyTestFunctionParametersMatchAllAnyOrderWithOptional +test-function-parameters-match-all-ordered, CSSPropertyID::CSSPropertyTestFunctionParametersMatchAllOrdered +test-function-parameters-match-all-ordered-with-optional, CSSPropertyID::CSSPropertyTestFunctionParametersMatchAllOrderedWithOptional +test-function-parameters-match-one-or-more-any-order, CSSPropertyID::CSSPropertyTestFunctionParametersMatchOneOrMoreAnyOrder +test-function-single-parameter, CSSPropertyID::CSSPropertyTestFunctionSingleParameter +test-function-single-parameter-match-one, CSSPropertyID::CSSPropertyTestFunctionSingleParameterMatchOne +test-function-single-parameter-optional, CSSPropertyID::CSSPropertyTestFunctionSingleParameterOptional +test-function-unbounded-parameters-no-min, CSSPropertyID::CSSPropertyTestFunctionUnboundedParametersNoMin +test-function-unbounded-parameters-with-minimum, CSSPropertyID::CSSPropertyTestFunctionUnboundedParametersWithMinimum +test-high-priority, CSSPropertyID::CSSPropertyTestHighPriority +test-image, CSSPropertyID::CSSPropertyTestImage +test-image-no-image-set, CSSPropertyID::CSSPropertyTestImageNoImageSet +test-keyword, CSSPropertyID::CSSPropertyTestKeyword +test-keyword-with-aliased-to, CSSPropertyID::CSSPropertyTestKeywordWithAliasedTo +test-logical-property-group-logical-block, CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalBlock +test-logical-property-group-logical-inline, CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalInline +test-logical-property-group-physical-horizontal, CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalHorizontal +test-logical-property-group-physical-vertical, CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalVertical +test-match-all-any-order, CSSPropertyID::CSSPropertyTestMatchAllAnyOrder +test-match-all-any-order-with-custom-type, CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithCustomType +test-match-all-any-order-with-optional, CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptional +test-match-all-any-order-with-optional-and-custom-type, CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndCustomType +test-match-all-any-order-with-optional-and-multiple-required-and-custom-type, CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndMultipleRequiredAndCustomType +test-match-all-any-order-with-optional-and-multiple-required-and-custom-type-no-single-item-opt, CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndMultipleRequiredAndCustomTypeNoSingleItemOpt +test-match-all-any-order-with-optional-and-multiple-required-and-preserve-order-and-custom-type, CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndMultipleRequiredAndPreserveOrderAndCustomType +test-match-all-any-order-with-optional-and-multiple-required-and-preserve-order-and-custom-type-no-single-item-opt, CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndMultipleRequiredAndPreserveOrderAndCustomTypeNoSingleItemOpt +test-match-all-any-order-with-optional-and-preserve-order-and-custom-type, CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndPreserveOrderAndCustomType +test-match-all-any-order-with-optional-no-single-item-opt, CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalNoSingleItemOpt +test-match-all-any-order-with-optional-single-item-opt, CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalSingleItemOpt +test-match-all-any-order-with-optional-with-preserve-order, CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalWithPreserveOrder +test-match-all-any-order-with-optional-with-preserve-order-no-single-item-opt, CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalWithPreserveOrderNoSingleItemOpt +test-match-all-any-order-with-preserve-order, CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithPreserveOrder +test-match-all-any-order-with-preserve-order-and-custom-type, CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithPreserveOrderAndCustomType +test-match-all-any-order-with-preserve-order-no-single-item-opt, CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithPreserveOrderNoSingleItemOpt +test-match-all-ordered, CSSPropertyID::CSSPropertyTestMatchAllOrdered +test-match-all-ordered-with-custom-type, CSSPropertyID::CSSPropertyTestMatchAllOrderedWithCustomType +test-match-all-ordered-with-optional, CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptional +test-match-all-ordered-with-optional-and-custom-type, CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalAndCustomType +test-match-all-ordered-with-optional-and-custom-type-and-no-single-item-opt, CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalAndCustomTypeAndNoSingleItemOpt +test-match-all-ordered-with-optional-and-multiple-required, CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalAndMultipleRequired +test-match-all-ordered-with-optional-and-multiple-required-and-custom-type, CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalAndMultipleRequiredAndCustomType +test-match-all-ordered-with-optional-no-single-item-opt, CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalNoSingleItemOpt +test-match-all-ordered-with-optional-single-item-opt, CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalSingleItemOpt +test-match-one, CSSPropertyID::CSSPropertyTestMatchOne +test-match-one-or-more-any-order, CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrder +test-match-one-or-more-any-order-no-single-item-opt, CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderNoSingleItemOpt +test-match-one-or-more-any-order-with-custom-type, CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithCustomType +test-match-one-or-more-any-order-with-custom-type-no-single-item-opt, CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithCustomTypeNoSingleItemOpt +test-match-one-or-more-any-order-with-preserve-order, CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithPreserveOrder +test-match-one-or-more-any-order-with-preserve-order-and-custom-type, CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithPreserveOrderAndCustomType +test-match-one-or-more-any-order-with-preserve-order-and-custom-type-no-single-item-opt, CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithPreserveOrderAndCustomTypeNoSingleItemOpt +test-match-one-or-more-any-order-with-preserve-order-no-single-item-opt, CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithPreserveOrderNoSingleItemOpt +test-match-one-with-group-with-settings-flag, CSSPropertyID::CSSPropertyTestMatchOneWithGroupWithSettingsFlag +test-match-one-with-keyword-with-settings-flag, CSSPropertyID::CSSPropertyTestMatchOneWithKeywordWithSettingsFlag +test-match-one-with-multiple-keywords, CSSPropertyID::CSSPropertyTestMatchOneWithMultipleKeywords +test-match-one-with-reference-with-settings-flag, CSSPropertyID::CSSPropertyTestMatchOneWithReferenceWithSettingsFlag +test-match-one-with-settings-flag, CSSPropertyID::CSSPropertyTestMatchOneWithSettingsFlag +test-medium-priority, CSSPropertyID::CSSPropertyTestMediumPriority +test-numeric-value-range, CSSPropertyID::CSSPropertyTestNumericValueRange +test-property, CSSPropertyID::CSSPropertyTestProperty +test-settings-one, CSSPropertyID::CSSPropertyTestSettingsOne +test-shared-builder-extractor-converter, CSSPropertyID::CSSPropertyTestSharedBuilderExtractorConverter +test-shorthand-one, CSSPropertyID::CSSPropertyTestShorthandOne +test-shorthand-two, CSSPropertyID::CSSPropertyTestShorthandTwo +test-sink-priority, CSSPropertyID::CSSPropertyTestSinkPriority +test-top-priority, CSSPropertyID::CSSPropertyTestTopPriority +test-unbounded-repetition-with-commas-with-min, CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithCommasWithMin +test-unbounded-repetition-with-commas-with-min-no-single-item-opt, CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithCommasWithMinNoSingleItemOpt +test-unbounded-repetition-with-commas-with-min-single-item-opt, CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithCommasWithMinSingleItemOpt +test-unbounded-repetition-with-spaces-no-min, CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesNoMin +test-unbounded-repetition-with-spaces-no-min-no-single-item-opt, CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesNoMinNoSingleItemOpt +test-unbounded-repetition-with-spaces-with-min, CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesWithMin +test-unbounded-repetition-with-spaces-with-min-no-single-item-opt, CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesWithMinNoSingleItemOpt +test-unbounded-repetition-with-spaces-with-min-single-item-opt, CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesWithMinSingleItemOpt +test-url-with-modifiers, CSSPropertyID::CSSPropertyTestUrlWithModifiers +test-url-with-no-modifiers, CSSPropertyID::CSSPropertyTestUrlWithNoModifiers +test-using-shared-rule, CSSPropertyID::CSSPropertyTestUsingSharedRule +test-using-shared-rule-exported, CSSPropertyID::CSSPropertyTestUsingSharedRuleExported +test-using-shared-rule-with-override-function, CSSPropertyID::CSSPropertyTestUsingSharedRuleWithOverrideFunction +%% + +CSSPropertyID findCSSProperty(const char* characters, unsigned length) +{ + auto* value = CSSPropertyNamesHash::in_word_set(characters, length); + return value ? static_cast(value->id) : CSSPropertyID::CSSPropertyInvalid; +} + +ASCIILiteral nameLiteral(CSSPropertyID id) +{ + if (id < firstCSSProperty) + return { }; + unsigned index = id - firstCSSProperty; + if (index >= numCSSProperties) + return { }; + return propertyNameStrings[index]; +} + +const AtomString& nameString(CSSPropertyID id) +{ + if (id < firstCSSProperty) + return nullAtom(); + unsigned index = id - firstCSSProperty; + if (index >= numCSSProperties) + return nullAtom(); + + static NeverDestroyed> atomStrings; + auto& string = atomStrings.get()[index]; + if (string.isNull()) + string = propertyNameStrings[index]; + return string; +} + +String nameForIDL(CSSPropertyID id) +{ + Latin1Character characters[maxCSSPropertyNameLength]; + const char* nameForCSS = nameLiteral(id); + if (!nameForCSS) + return emptyString(); + + auto* propertyNamePointer = nameForCSS; + auto* nextCharacter = characters; + while (char character = *propertyNamePointer++) { + if (character == '-') { + char nextCharacter = *propertyNamePointer++; + if (!nextCharacter) + break; + character = (propertyNamePointer - 2 != nameForCSS) ? toASCIIUpper(nextCharacter) : nextCharacter; + } + *nextCharacter++ = character; + } + return std::span { characters, nextCharacter }; +} + + +bool isInternal(CSSPropertyID id) +{ + switch (id) { + return true; + default: + return false; + } +} + +static bool isExposedNotInvalidAndNotInternal(CSSPropertyID id, const CSSPropertySettings& settings) +{ + switch (id) { + case CSSPropertyID::CSSPropertyFirstTestDescriptorForFirstDescriptor: + return settings.cssDescriptorEnabled; + case CSSPropertyID::CSSPropertyTestSettingsOne: + return settings.cssSettingsOneEnabled; + case CSSPropertyID::CSSPropertyTestShorthandTwo: + return settings.cssSettingsShorthandEnabled; + default: + return true; + } +} + +static bool isExposedNotInvalidAndNotInternal(CSSPropertyID id, const Settings& settings) +{ + switch (id) { + case CSSPropertyID::CSSPropertyFirstTestDescriptorForFirstDescriptor: + return settings.cssDescriptorEnabled(); + case CSSPropertyID::CSSPropertyTestSettingsOne: + return settings.cssSettingsOneEnabled(); + case CSSPropertyID::CSSPropertyTestShorthandTwo: + return settings.cssSettingsShorthandEnabled(); + default: + return true; + } +} + +bool isExposed(CSSPropertyID id, const CSSPropertySettings* settings) +{ + if (id == CSSPropertyID::CSSPropertyInvalid || isInternal(id)) + return false; + if (!settings) + return true; + return isExposedNotInvalidAndNotInternal(id, *settings); +} + +bool isExposed(CSSPropertyID id, const CSSPropertySettings& settings) +{ + if (id == CSSPropertyID::CSSPropertyInvalid || isInternal(id)) + return false; + return isExposedNotInvalidAndNotInternal(id, settings); +} + +bool isExposed(CSSPropertyID id, const Settings* settings) +{ + if (id == CSSPropertyID::CSSPropertyInvalid || isInternal(id)) + return false; + if (!settings) + return true; + return isExposedNotInvalidAndNotInternal(id, *settings); +} + +bool isExposed(CSSPropertyID id, const Settings& settings) +{ + if (id == CSSPropertyID::CSSPropertyInvalid || isInternal(id)) + return false; + return isExposedNotInvalidAndNotInternal(id, settings); +} + +constexpr bool isInheritedPropertyTable[cssPropertyIDEnumValueCount] = { + false, // CSSPropertyID::CSSPropertyInvalid + true , // CSSPropertyID::CSSPropertyCustom + false, // CSSPropertyID::CSSPropertyTestTopPriority + false, // CSSPropertyID::CSSPropertyTestHighPriority + false, // CSSPropertyID::CSSPropertyBackgroundFillLayerTestPrimary + false, // CSSPropertyID::CSSPropertyTestMediumPriority + false, // CSSPropertyID::CSSPropertyBackgroundFillLayerTestSecondary + false, // CSSPropertyID::CSSPropertyBackgroundFillLayerTestSecondaryWithConverter + false, // CSSPropertyID::CSSPropertyFirstTestDescriptorForFirstDescriptor + false, // CSSPropertyID::CSSPropertyFirstTestDescriptorForSecondDescriptor + false, // CSSPropertyID::CSSPropertyTestAnimationWrapper + false, // CSSPropertyID::CSSPropertyTestAnimationWrapperAccelerationAlways + false, // CSSPropertyID::CSSPropertyTestAnimationWrapperAccelerationThreadedOnly + false, // CSSPropertyID::CSSPropertyTestAutoFunctions + false, // CSSPropertyID::CSSPropertyTestBoundedRepetitionWithCommas + false, // CSSPropertyID::CSSPropertyTestBoundedRepetitionWithCommasFixed + false, // CSSPropertyID::CSSPropertyTestBoundedRepetitionWithCommasNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestBoundedRepetitionWithCommasSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpaces + false, // CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesFixed + false, // CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesWithType + false, // CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesWithTypeNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesWithTypeWithDefaultPrevious + false, // CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesWithTypeWithDefaultPreviousTwo + false, // CSSPropertyID::CSSPropertyTestColor + false, // CSSPropertyID::CSSPropertyTestColorAllowsTypesAbsolute + false, // CSSPropertyID::CSSPropertyTestColorPropertyWithNoVisitedLinkSupport + false, // CSSPropertyID::CSSPropertyTestColorPropertyWithVisitedLinkSupport + false, // CSSPropertyID::CSSPropertyTestCustomExtractor + false, // CSSPropertyID::CSSPropertyTestExtractorConverter + false, // CSSPropertyID::CSSPropertyTestFunctionBoundedParameters + false, // CSSPropertyID::CSSPropertyTestFunctionFixedParameters + false, // CSSPropertyID::CSSPropertyTestFunctionNoParameters + false, // CSSPropertyID::CSSPropertyTestFunctionParametersMatchAllAnyOrder + false, // CSSPropertyID::CSSPropertyTestFunctionParametersMatchAllAnyOrderWithOptional + false, // CSSPropertyID::CSSPropertyTestFunctionParametersMatchAllOrdered + false, // CSSPropertyID::CSSPropertyTestFunctionParametersMatchAllOrderedWithOptional + false, // CSSPropertyID::CSSPropertyTestFunctionParametersMatchOneOrMoreAnyOrder + false, // CSSPropertyID::CSSPropertyTestFunctionSingleParameter + false, // CSSPropertyID::CSSPropertyTestFunctionSingleParameterMatchOne + false, // CSSPropertyID::CSSPropertyTestFunctionSingleParameterOptional + false, // CSSPropertyID::CSSPropertyTestFunctionUnboundedParametersNoMin + false, // CSSPropertyID::CSSPropertyTestFunctionUnboundedParametersWithMinimum + false, // CSSPropertyID::CSSPropertyTestImage + false, // CSSPropertyID::CSSPropertyTestImageNoImageSet + false, // CSSPropertyID::CSSPropertyTestKeyword + false, // CSSPropertyID::CSSPropertyTestKeywordWithAliasedTo + false, // CSSPropertyID::CSSPropertyTestMatchAllAnyOrder + false, // CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithCustomType + false, // CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptional + false, // CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndCustomType + false, // CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndMultipleRequiredAndCustomType + false, // CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndMultipleRequiredAndCustomTypeNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndMultipleRequiredAndPreserveOrderAndCustomType + false, // CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndMultipleRequiredAndPreserveOrderAndCustomTypeNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndPreserveOrderAndCustomType + false, // CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalWithPreserveOrder + false, // CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalWithPreserveOrderNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithPreserveOrder + false, // CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithPreserveOrderAndCustomType + false, // CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithPreserveOrderNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestMatchAllOrdered + false, // CSSPropertyID::CSSPropertyTestMatchAllOrderedWithCustomType + false, // CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptional + false, // CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalAndCustomType + false, // CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalAndCustomTypeAndNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalAndMultipleRequired + false, // CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalAndMultipleRequiredAndCustomType + false, // CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestMatchOne + false, // CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrder + false, // CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithCustomType + false, // CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithCustomTypeNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithPreserveOrder + false, // CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithPreserveOrderAndCustomType + false, // CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithPreserveOrderAndCustomTypeNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithPreserveOrderNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestMatchOneWithGroupWithSettingsFlag + false, // CSSPropertyID::CSSPropertyTestMatchOneWithKeywordWithSettingsFlag + false, // CSSPropertyID::CSSPropertyTestMatchOneWithMultipleKeywords + false, // CSSPropertyID::CSSPropertyTestMatchOneWithReferenceWithSettingsFlag + false, // CSSPropertyID::CSSPropertyTestMatchOneWithSettingsFlag + false, // CSSPropertyID::CSSPropertyTestNumericValueRange + false, // CSSPropertyID::CSSPropertyTestProperty + false, // CSSPropertyID::CSSPropertyTestSettingsOne + false, // CSSPropertyID::CSSPropertyTestSharedBuilderExtractorConverter + false, // CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithCommasWithMin + false, // CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithCommasWithMinNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithCommasWithMinSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesNoMin + false, // CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesNoMinNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesWithMin + false, // CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesWithMinNoSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesWithMinSingleItemOpt + false, // CSSPropertyID::CSSPropertyTestUrlWithModifiers + false, // CSSPropertyID::CSSPropertyTestUrlWithNoModifiers + false, // CSSPropertyID::CSSPropertyTestUsingSharedRule + false, // CSSPropertyID::CSSPropertyTestUsingSharedRuleExported + false, // CSSPropertyID::CSSPropertyTestUsingSharedRuleWithOverrideFunction + false, // CSSPropertyID::CSSPropertyTestSinkPriority + false, // CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalHorizontal + false, // CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalVertical + false, // CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalBlock + false, // CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalInline + false, // CSSPropertyID::CSSPropertyAll + false, // CSSPropertyID::CSSPropertyFont + false, // CSSPropertyID::CSSPropertyTestShorthandOne + false, // CSSPropertyID::CSSPropertyTestShorthandTwo +}; + +bool CSSProperty::isInheritedProperty(CSSPropertyID id) +{ + ASSERT(id < cssPropertyIDEnumValueCount); + ASSERT(id != CSSPropertyID::CSSPropertyInvalid); + return isInheritedPropertyTable[id]; +} + +CSSPropertyID cascadeAliasProperty(CSSPropertyID id) +{ + switch (id) { + default: + return id; + } +} + +Vector CSSProperty::aliasesForProperty(CSSPropertyID id) +{ + switch (id) { + default: + return { }; + } +} + +const WTF::BitSet CSSProperty::colorProperties = ([]() -> WTF::BitSet { + WTF::BitSet result; + result.set(CSSPropertyID::CSSPropertyTestColor); + result.set(CSSPropertyID::CSSPropertyTestColorAllowsTypesAbsolute); + result.set(CSSPropertyID::CSSPropertyTestColorPropertyWithNoVisitedLinkSupport); + result.set(CSSPropertyID::CSSPropertyTestColorPropertyWithVisitedLinkSupport); + return result; +})(); + +const WTF::BitSet CSSProperty::physicalProperties = ([]() -> WTF::BitSet { + WTF::BitSet result; + result.set(CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalHorizontal); + result.set(CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalVertical); + return result; +})(); + +char16_t CSSProperty::listValuedPropertySeparator(CSSPropertyID id) +{ + switch (id) { + default: + break; + } + return '\0'; +} + +bool CSSProperty::allowsNumberOrIntegerInput(CSSPropertyID id) +{ + switch (id) { + case CSSPropertyID::CSSPropertyTestTopPriority: + case CSSPropertyID::CSSPropertyTestHighPriority: + case CSSPropertyID::CSSPropertyBackgroundFillLayerTestPrimary: + case CSSPropertyID::CSSPropertyTestMediumPriority: + case CSSPropertyID::CSSPropertyBackgroundFillLayerTestSecondary: + case CSSPropertyID::CSSPropertyBackgroundFillLayerTestSecondaryWithConverter: + case CSSPropertyID::CSSPropertyTestAnimationWrapper: + case CSSPropertyID::CSSPropertyTestAnimationWrapperAccelerationAlways: + case CSSPropertyID::CSSPropertyTestAnimationWrapperAccelerationThreadedOnly: + case CSSPropertyID::CSSPropertyTestAutoFunctions: + case CSSPropertyID::CSSPropertyTestBoundedRepetitionWithCommasNoSingleItemOpt: + case CSSPropertyID::CSSPropertyTestBoundedRepetitionWithCommasSingleItemOpt: + case CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesNoSingleItemOpt: + case CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesSingleItemOpt: + case CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesWithType: + case CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesWithTypeNoSingleItemOpt: + case CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesWithTypeWithDefaultPrevious: + case CSSPropertyID::CSSPropertyTestBoundedRepetitionWithSpacesWithTypeWithDefaultPreviousTwo: + case CSSPropertyID::CSSPropertyTestCustomExtractor: + case CSSPropertyID::CSSPropertyTestExtractorConverter: + case CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndCustomType: + case CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalAndPreserveOrderAndCustomType: + case CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalNoSingleItemOpt: + case CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalSingleItemOpt: + case CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalWithPreserveOrder: + case CSSPropertyID::CSSPropertyTestMatchAllAnyOrderWithOptionalWithPreserveOrderNoSingleItemOpt: + case CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalAndCustomType: + case CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalAndCustomTypeAndNoSingleItemOpt: + case CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalNoSingleItemOpt: + case CSSPropertyID::CSSPropertyTestMatchAllOrderedWithOptionalSingleItemOpt: + case CSSPropertyID::CSSPropertyTestMatchOne: + case CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrder: + case CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderNoSingleItemOpt: + case CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithCustomType: + case CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithCustomTypeNoSingleItemOpt: + case CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithPreserveOrder: + case CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithPreserveOrderAndCustomType: + case CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithPreserveOrderAndCustomTypeNoSingleItemOpt: + case CSSPropertyID::CSSPropertyTestMatchOneOrMoreAnyOrderWithPreserveOrderNoSingleItemOpt: + case CSSPropertyID::CSSPropertyTestMatchOneWithGroupWithSettingsFlag: + case CSSPropertyID::CSSPropertyTestMatchOneWithKeywordWithSettingsFlag: + case CSSPropertyID::CSSPropertyTestMatchOneWithMultipleKeywords: + case CSSPropertyID::CSSPropertyTestMatchOneWithReferenceWithSettingsFlag: + case CSSPropertyID::CSSPropertyTestNumericValueRange: + case CSSPropertyID::CSSPropertyTestProperty: + case CSSPropertyID::CSSPropertyTestSettingsOne: + case CSSPropertyID::CSSPropertyTestSharedBuilderExtractorConverter: + case CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithCommasWithMinNoSingleItemOpt: + case CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithCommasWithMinSingleItemOpt: + case CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesNoMin: + case CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesNoMinNoSingleItemOpt: + case CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesWithMinNoSingleItemOpt: + case CSSPropertyID::CSSPropertyTestUnboundedRepetitionWithSpacesWithMinSingleItemOpt: + case CSSPropertyID::CSSPropertyTestUsingSharedRule: + case CSSPropertyID::CSSPropertyTestSinkPriority: + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalHorizontal: + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalVertical: + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalBlock: + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalInline: + return true; + default: + return false; + } +} + +bool CSSProperty::disablesNativeAppearance(CSSPropertyID id) +{ + switch (id) { + return true; + default: + return false; + } +} + +bool CSSProperty::isTestGroupProperty(CSSPropertyID id) +{ + switch (id) { + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalBlock: + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalInline: + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalHorizontal: + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalVertical: + case CSSPropertyID::CSSPropertyTestShorthandOne: + case CSSPropertyID::CSSPropertyTestShorthandTwo: + return true; + default: + return false; + } +} + +bool CSSProperty::isInLogicalPropertyGroup(CSSPropertyID id) +{ + switch (id) { + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalBlock: + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalInline: + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalHorizontal: + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalVertical: + return true; + default: + return false; + } +} + +bool CSSProperty::areInSameLogicalPropertyGroupWithDifferentMappingLogic(CSSPropertyID id1, CSSPropertyID id2) +{ + switch (id1) { + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalBlock: + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalInline: + switch (id2) { + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalHorizontal: + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalVertical: + return true; + default: + return false; + } + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalHorizontal: + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalVertical: + switch (id2) { + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalBlock: + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalInline: + return true; + default: + return false; + } + default: + return false; + } +} + +CSSPropertyID CSSProperty::resolveDirectionAwareProperty(CSSPropertyID id, WritingMode writingMode) +{ + switch (id) { + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalBlock: { + static constexpr CSSPropertyID properties[2] = { CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalHorizontal, CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalVertical }; + return properties[static_cast(mapAxisLogicalToPhysical(writingMode, LogicalBoxAxis::Block))]; + } + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalInline: { + static constexpr CSSPropertyID properties[2] = { CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalHorizontal, CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalVertical }; + return properties[static_cast(mapAxisLogicalToPhysical(writingMode, LogicalBoxAxis::Inline))]; + } + default: + return id; + } +} + +CSSPropertyID CSSProperty::unresolvePhysicalProperty(CSSPropertyID id, WritingMode writingMode) +{ + switch (id) { + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalHorizontal: { + static constexpr CSSPropertyID properties[2] = { CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalInline, CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalBlock }; + return properties[static_cast(mapAxisPhysicalToLogical(writingMode, BoxAxis::Horizontal))]; + } + case CSSPropertyID::CSSPropertyTestLogicalPropertyGroupPhysicalVertical: { + static constexpr CSSPropertyID properties[2] = { CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalInline, CSSPropertyID::CSSPropertyTestLogicalPropertyGroupLogicalBlock }; + return properties[static_cast(mapAxisPhysicalToLogical(writingMode, BoxAxis::Vertical))]; + } + default: + return id; + } +} + +bool CSSProperty::isDescriptorOnly(CSSPropertyID id) +{ + switch (id) { + case CSSPropertyID::CSSPropertyFirstTestDescriptorForFirstDescriptor: + case CSSPropertyID::CSSPropertyFirstTestDescriptorForSecondDescriptor: + return true; + default: + return false; + } +} + +bool CSSProperty::acceptsQuirkyColor(CSSPropertyID id) +{ + switch (id) { + return true; + default: + return false; + } +} + +bool CSSProperty::acceptsQuirkyLength(CSSPropertyID id) +{ + switch (id) { + return true; + default: + return false; + } +} + +bool CSSProperty::acceptsQuirkyAngle(CSSPropertyID id) +{ + switch (id) { + return true; + default: + return false; + } +} + +bool CSSProperty::animationUsesNonAdditiveOrCumulativeInterpolation(CSSPropertyID id) +{ + switch (id) { + return true; + default: + return false; + } +} + +bool CSSProperty::animationUsesNonNormalizedDiscreteInterpolation(CSSPropertyID id) +{ + switch (id) { + return true; + default: + return false; + } +} + +bool CSSProperty::animationIsAccelerated(CSSPropertyID id, [[maybe_unused]] const Settings& settings) +{ + switch (id) { + case CSSPropertyID::CSSPropertyTestAnimationWrapperAccelerationAlways: + return true; + default: + return false; + } +} + +std::span CSSProperty::allAcceleratedAnimationProperties([[maybe_unused]] const Settings& settings) +{ + static constexpr std::array propertiesExcludingThreadedOnly { + CSSPropertyID::CSSPropertyTestAnimationWrapperAccelerationAlways, + }; + return std::span { propertiesExcludingThreadedOnly }; +} + +CSSPropertySettings::CSSPropertySettings(const Settings& settings) + : cssDescriptorEnabled { settings.cssDescriptorEnabled() } + , cssSettingsOneEnabled { settings.cssSettingsOneEnabled() } + , cssSettingsShorthandEnabled { settings.cssSettingsShorthandEnabled() } +{ +} + +bool operator==(const CSSPropertySettings& a, const CSSPropertySettings& b) +{ + return a.cssDescriptorEnabled == b.cssDescriptorEnabled + && a.cssSettingsOneEnabled == b.cssSettingsOneEnabled + && a.cssSettingsShorthandEnabled == b.cssSettingsShorthandEnabled; +} + +void add(Hasher& hasher, const CSSPropertySettings& settings) +{ + uint64_t bits = settings.cssDescriptorEnabled << 0 + | settings.cssSettingsOneEnabled << 1 + | settings.cssSettingsShorthandEnabled << 2; + add(hasher, bits); +} + + +TextStream& operator<<(TextStream& stream, CSSPropertyID property) +{ + return stream << nameLiteral(property); +} + +} // namespace WebCore + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_END +IGNORE_WARNINGS_END diff --git a/Source/WebCore/dom/DatasetDOMStringMap.cpp b/Source/WebCore/dom/DatasetDOMStringMap.cpp index a0daa09eef8a3..4daf6ae38a2b3 100644 --- a/Source/WebCore/dom/DatasetDOMStringMap.cpp +++ b/Source/WebCore/dom/DatasetDOMStringMap.cpp @@ -111,8 +111,8 @@ static AtomString convertPropertyNameToAttributeName(const String& name) StringImpl* nameImpl = name.impl(); if (nameImpl->is8Bit()) - return convertPropertyNameToAttributeName(*nameImpl); - return convertPropertyNameToAttributeName(*nameImpl); + return convertPropertyNameToAttributeName(*nameImpl); + return convertPropertyNameToAttributeName(*nameImpl); } void DatasetDOMStringMap::ref() diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp index e222e35c1941f..e6755fa9a2ae5 100644 --- a/Source/WebCore/dom/Document.cpp +++ b/Source/WebCore/dom/Document.cpp @@ -1669,7 +1669,7 @@ enum class CustomElementNameCharacterKind : uint8_t { Upper, }; -static ALWAYS_INLINE CustomElementNameCharacterKind customElementNameCharacterKind(LChar character) +static ALWAYS_INLINE CustomElementNameCharacterKind customElementNameCharacterKind(Latin1Character character) { using Kind = CustomElementNameCharacterKind; static const Kind table[] = { @@ -6574,7 +6574,7 @@ void Document::updateCachedCookiesEnabled() }); } -static bool isValidNameNonASCII(std::span characters) +static bool isValidNameNonASCII(std::span characters) { if (!isValidNameStart(characters[0])) return false; @@ -6616,7 +6616,7 @@ static inline bool isValidNameASCII(std::span characters) return true; } -static bool isValidNameASCIIWithoutColon(std::span characters) +static bool isValidNameASCIIWithoutColon(std::span characters) { auto c = characters.front(); if (!(isASCIIAlpha(c) || c == '_')) @@ -10153,7 +10153,7 @@ RefPtr Document::attachmentForIdentifier(const String& id static MessageSource messageSourceForWTFLogChannel(const WTFLogChannel& channel) { - auto channelName = span(channel.name); + auto channelName = unsafeSpan(channel.name); if (equalLettersIgnoringASCIICase(channelName, "media"_s)) return MessageSource::Media; diff --git a/Source/WebCore/dom/SpaceSplitString.cpp b/Source/WebCore/dom/SpaceSplitString.cpp index 8e5ef6a4df56e..7499a72ac794d 100644 --- a/Source/WebCore/dom/SpaceSplitString.cpp +++ b/Source/WebCore/dom/SpaceSplitString.cpp @@ -140,8 +140,8 @@ bool SpaceSplitString::spaceSplitStringContainsValue(StringView spaceSplitString return false; if (value.is8Bit()) - return spaceSplitStringContainsValueInternal(shouldFoldCase == ShouldFoldCase::Yes ? StringView { spaceSplitString.convertToASCIILowercase() } : spaceSplitString, value); - return spaceSplitStringContainsValueInternal(shouldFoldCase == ShouldFoldCase::Yes ? StringView { spaceSplitString.convertToASCIILowercase() } : spaceSplitString, value); + return spaceSplitStringContainsValueInternal(shouldFoldCase == ShouldFoldCase::Yes ? StringView { spaceSplitString.convertToASCIILowercase() } : spaceSplitString, value); + return spaceSplitStringContainsValueInternal(shouldFoldCase == ShouldFoldCase::Yes ? StringView { spaceSplitString.convertToASCIILowercase() } : spaceSplitString, value); } class TokenCounter { diff --git a/Source/WebCore/dom/make_names.pl b/Source/WebCore/dom/make_names.pl index 043e9cd6539f0..b914e5b3038b3 100755 --- a/Source/WebCore/dom/make_names.pl +++ b/Source/WebCore/dom/make_names.pl @@ -1114,8 +1114,8 @@ sub printNodeNameHeaderFile print F "} // namespace AttributeNames\n"; print F "\n"; print F "NodeName findNodeName(Namespace, const String&);\n"; - print F "ElementName findHTMLElementName(std::span);\n"; - print F "ElementName findHTMLElementName(std::span);\n"; + print F "ElementName findHTMLElementName(std::span);\n"; + print F "ElementName findHTMLElementName(std::span);\n"; print F "ElementName findHTMLElementName(const String&);\n"; print F "ElementName findSVGElementName(const String&);\n"; print F "ElementName findMathMLElementName(const String&);\n"; @@ -1252,7 +1252,7 @@ sub printNodeNameCppFile print F " return findNodeNameFromBuffer(ns, name.span16());\n"; print F "}\n"; print F "\n"; - print F "ElementName findHTMLElementName(std::span buffer)\n"; + print F "ElementName findHTMLElementName(std::span buffer)\n"; print F "{\n"; print F " return findHTMLNodeName(buffer);\n"; print F "}\n"; diff --git a/Source/WebCore/editing/Editing.cpp b/Source/WebCore/editing/Editing.cpp index 96acec93aefb3..4ef5d294d9426 100644 --- a/Source/WebCore/editing/Editing.cpp +++ b/Source/WebCore/editing/Editing.cpp @@ -377,7 +377,7 @@ String stringWithRebalancedWhitespace(const String& string, bool startIsStartOfP previousCharacterWasSpace = false; continue; } - LChar selectedWhitespaceCharacter; + Latin1Character selectedWhitespaceCharacter; // We need to ensure there is no next sibling text node. See https://bugs.webkit.org/show_bug.cgi?id=123163 if (previousCharacterWasSpace || (!i && startIsStartOfParagraph) || (i == length - 1 && shouldEmitNBSPbeforeEnd)) { selectedWhitespaceCharacter = noBreakSpace; diff --git a/Source/WebCore/editing/MarkupAccumulator.cpp b/Source/WebCore/editing/MarkupAccumulator.cpp index 35f4d22ee8258..e639caa6dc39f 100644 --- a/Source/WebCore/editing/MarkupAccumulator.cpp +++ b/Source/WebCore/editing/MarkupAccumulator.cpp @@ -189,7 +189,7 @@ void MarkupAccumulator::appendCharactersReplacingEntities(StringBuilder& result, return; if (source.is8Bit()) - appendCharactersReplacingEntitiesInternal(result, source, offset, length, entityMask); + appendCharactersReplacingEntitiesInternal(result, source, offset, length, entityMask); else appendCharactersReplacingEntitiesInternal(result, source, offset, length, entityMask); } diff --git a/Source/WebCore/editing/TextIterator.cpp b/Source/WebCore/editing/TextIterator.cpp index 45838976b1d9b..19b597f049955 100644 --- a/Source/WebCore/editing/TextIterator.cpp +++ b/Source/WebCore/editing/TextIterator.cpp @@ -1763,7 +1763,7 @@ static UStringSearch* createSearcher() // but it doesn't matter exactly what it is, since we don't perform any searches // without setting both the pattern and the text. UErrorCode status = U_ZERO_ERROR; - auto searchCollatorName = makeString(span(currentSearchLocaleID()), "@collation=search"_s); + auto searchCollatorName = makeString(unsafeSpan(currentSearchLocaleID()), "@collation=search"_s); UStringSearch* searcher = usearch_open(&newlineCharacter, 1, &newlineCharacter, 1, searchCollatorName.utf8().data(), 0, &status); ASSERT(U_SUCCESS(status) || status == U_USING_FALLBACK_WARNING || status == U_USING_DEFAULT_WARNING); return searcher; diff --git a/Source/WebCore/editing/cocoa/NodeHTMLConverter.mm b/Source/WebCore/editing/cocoa/NodeHTMLConverter.mm new file mode 100644 index 0000000000000..575d52022b532 --- /dev/null +++ b/Source/WebCore/editing/cocoa/NodeHTMLConverter.mm @@ -0,0 +1,2325 @@ +/* + * Copyright (C) 2011-2025 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "NodeHTMLConverter.h" + +#import "ArchiveResource.h" +#import "BoundaryPointInlines.h" +#import "CSSColorValue.h" +#import "CSSComputedStyleDeclaration.h" +#import "CSSPrimitiveValue.h" +#import "CSSSerializationContext.h" +#import "CachedImage.h" +#import "CharacterData.h" +#import "ColorCocoa.h" +#import "ColorMac.h" +#import "CommonAtomStrings.h" +#import "ComposedTreeIterator.h" +#import "ContainerNodeInlines.h" +#import "Document.h" +#import "DocumentLoader.h" +#import "Editing.h" +#import "ElementChildIteratorInlines.h" +#import "ElementInlines.h" +#import "ElementRareData.h" +#import "ElementTraversal.h" +#import "File.h" +#import "FontAttributes.h" +#import "FontCascade.h" +#import "FrameLoader.h" +#import "HTMLAttachmentElement.h" +#import "HTMLConverter.h" +#import "HTMLElement.h" +#import "HTMLFrameElement.h" +#import "HTMLIFrameElement.h" +#import "HTMLImageElement.h" +#import "HTMLInputElement.h" +#import "HTMLMetaElement.h" +#import "HTMLNames.h" +#import "HTMLOListElement.h" +#import "HTMLTableCellElement.h" +#import "HTMLTextAreaElement.h" +#import "ImageAdapter.h" +#import "LoaderNSURLExtras.h" +#import "LocalFrame.h" +#import "LocalizedStrings.h" +#import "NodeName.h" +#import "Quirks.h" +#import "RenderImage.h" +#import "RenderText.h" +#import "StyleExtractor.h" +#import "StyleProperties.h" +#import "StyledElement.h" +#import "TextIterator.h" +#import "VisibleSelection.h" +#import "WebContentReader.h" +#import "WebCoreTextAttachment.h" +#import "markup.h" +#import +#import +#import +#import +#import +#import +#import +#import + +#if ENABLE(DATA_DETECTION) +#import "DataDetection.h" +#endif + +#if ENABLE(MULTI_REPRESENTATION_HEIC) +#import "PlatformNSAdaptiveImageGlyph.h" +#endif + +#if PLATFORM(IOS_FAMILY) +#import "UIFoundationSoftLink.h" +#import "WAKAppKitStubs.h" +#import +#import +#endif + +using namespace WebCore; +using namespace HTMLNames; + +#if PLATFORM(IOS_FAMILY) + +enum { + NSEnterCharacter = 0x0003, + NSBackspaceCharacter = 0x0008, + NSTabCharacter = 0x0009, + NSNewlineCharacter = 0x000a, + NSFormFeedCharacter = 0x000c, + NSCarriageReturnCharacter = 0x000d, + NSBackTabCharacter = 0x0019, + NSDeleteCharacter = 0x007f, + NSLineSeparatorCharacter = 0x2028, + NSParagraphSeparatorCharacter = 0x2029, +}; + +@interface NSTextBlock () +- (void)setWidth:(CGFloat)val type:(NSTextBlockValueType)type forLayer:(NSTextBlockLayer)layer edge:(NSRectEdge)edge; +- (void)setBorderColor:(UIColor *)color forEdge:(NSRectEdge)edge; +@end + +#endif + +// Additional control Unicode characters +const unichar WebNextLineCharacter = 0x0085; + +static const CGFloat defaultFontSize = 12; +static const CGFloat minimumFontSize = 1; + +using NodeSet = HashSet>; + +class HTMLConverterCaches { + WTF_MAKE_TZONE_ALLOCATED(HTMLConverterCaches); +public: + String propertyValueForNode(Node&, CSSPropertyID ); + bool floatPropertyValueForNode(Node&, CSSPropertyID, float&); + Color colorPropertyValueForNode(Node&, CSSPropertyID); + + bool isBlockElement(Element&); + bool elementHasOwnBackgroundColor(Element&); + + RefPtr computedStylePropertyForElement(Element&, CSSPropertyID); + RefPtr inlineStylePropertyForElement(Element&, CSSPropertyID); + + Node* cacheAncestorsOfStartToBeConverted(const Position&, const Position&); + bool isAncestorsOfStartToBeConverted(Node& node) const { return m_ancestorsUnderCommonAncestor.contains(&node); } + +private: + HashMap> m_computedStyles; + NodeSet m_ancestorsUnderCommonAncestor; +}; + +WTF_MAKE_TZONE_ALLOCATED_IMPL(HTMLConverterCaches); + +@interface NSTextList (WebCoreNSTextListDetails) ++ (NSDictionary *)_standardMarkerAttributesForAttributes:(NSDictionary *)attrs; +@end + +@interface NSObject(WebMessageDocumentSimulation) ++ (void)document:(NSObject **)outDocument attachment:(NSTextAttachment **)outAttachment forURL:(NSURL *)url; +@end + +class HTMLConverter { +public: + explicit HTMLConverter(const SimpleRange&, IgnoreUserSelectNone); + ~HTMLConverter(); + + AttributedString convert(); + +private: + Position m_start; + Position m_end; + DocumentLoader* m_dataSource { nullptr }; + + HashMap, RetainPtr> m_attributesForElements; + HashMap, RefPtr> m_textTableFooters; + HashMap, RetainPtr> m_aggregatedAttributesForElements; + + UserSelectNoneStateCache m_userSelectNoneStateCache; + bool m_ignoreUserSelectNoneContent { false }; + + RetainPtr _attrStr; + RetainPtr _documentAttrs; + RetainPtr _topPresentationIntent; + NSInteger _topPresentationIntentIdentity; + RetainPtr _textLists; + RetainPtr _textBlocks; + RetainPtr _textTables; + RetainPtr _textTableSpacings; + RetainPtr _textTablePaddings; + RetainPtr _textTableRows; + RetainPtr _textTableRowArrays; + RetainPtr _textTableRowBackgroundColors; + RetainPtr _fontCache; + RetainPtr _writingDirectionArray; + + CGFloat _defaultTabInterval; + NSUInteger _domRangeStartIndex; + NSInteger _quoteLevel; + + std::unique_ptr _caches; + + struct { + unsigned int isSoft:1; + unsigned int reachedStart:1; + unsigned int reachedEnd:1; + unsigned int hasTrailingNewline:1; + unsigned int pad:26; + } _flags; + + RetainPtr _colorForElement(Element&, CSSPropertyID); + + void _traverseNode(Node&, unsigned depth, bool embedded); + void _traverseFooterNode(Element&, unsigned depth); + + NSDictionary *computedAttributesForElement(Element&); + NSDictionary *attributesForElement(Element&); + NSDictionary *aggregatedAttributesForAncestors(CharacterData&); + NSDictionary* aggregatedAttributesForElementAndItsAncestors(Element&); + + Element* _blockLevelElementForNode(Node*); + +#if ENABLE(MULTI_REPRESENTATION_HEIC) + BOOL _addMultiRepresentationHEICAttachmentForImageElement(HTMLImageElement&); +#endif + + void _newParagraphForElement(Element&, NSString *tag, BOOL flag, BOOL suppressTrailingSpace); + void _newLineForElement(Element&); + void _newTabForElement(Element&); + BOOL _addAttachmentForElement(Element&, NSURL *url, BOOL needsParagraph, BOOL usePlaceholder); + void _addQuoteForElement(Element&, BOOL opening, NSInteger level); + void _addValue(NSString *value, Element&); + void _fillInBlock(NSTextBlock *block, Element&, PlatformColor *backgroundColor, CGFloat extraMargin, CGFloat extraPadding, BOOL isTable); + void _enterBlockquote(); + void _exitBlockquote(); + + BOOL _enterElement(Element&, BOOL embedded); + BOOL _processElement(Element&, NSInteger depth); + void _exitElement(Element&, NSInteger depth, NSUInteger startIndex); + + void _processHeadElement(Element&); + void _processMetaElementWithName(NSString *name, NSString *content); + + void _addLinkForElement(Element&, NSRange); + void _addTableForElement(Element* tableElement); + void _addTableCellForElement(Element* tableCellElement); + void _addMarkersToList(NSTextList *list, NSRange range); + void _processText(Text&); + void _adjustTrailingNewline(); +}; + +HTMLConverter::HTMLConverter(const SimpleRange& range, IgnoreUserSelectNone treatment) + : m_start(makeContainerOffsetPosition(range.start)) + , m_end(makeContainerOffsetPosition(range.end)) + , m_userSelectNoneStateCache(ComposedTree) + , m_ignoreUserSelectNoneContent(treatment == IgnoreUserSelectNone::Yes && !range.start.document().quirks().needsToCopyUserSelectNoneQuirk()) +{ + _attrStr = adoptNS([[NSMutableAttributedString alloc] init]); + _documentAttrs = adoptNS([[NSMutableDictionary alloc] init]); + _topPresentationIntent = nil; + _topPresentationIntentIdentity = 0; + _textLists = adoptNS([[NSMutableArray alloc] init]); + _textBlocks = adoptNS([[NSMutableArray alloc] init]); + _textTables = adoptNS([[NSMutableArray alloc] init]); + _textTableSpacings = adoptNS([[NSMutableArray alloc] init]); + _textTablePaddings = adoptNS([[NSMutableArray alloc] init]); + _textTableRows = adoptNS([[NSMutableArray alloc] init]); + _textTableRowArrays = adoptNS([[NSMutableArray alloc] init]); + _textTableRowBackgroundColors = adoptNS([[NSMutableArray alloc] init]); + _fontCache = adoptNS([[NSMutableDictionary alloc] init]); + _writingDirectionArray = adoptNS([[NSMutableArray alloc] init]); + + _defaultTabInterval = 36; + _domRangeStartIndex = 0; + _quoteLevel = 0; + + _flags.isSoft = false; + _flags.reachedStart = false; + _flags.reachedEnd = false; + + _caches = makeUnique(); +} + +HTMLConverter::~HTMLConverter() = default; + +AttributedString HTMLConverter::convert() +{ + if (m_start > m_end) + return { }; + + Node* commonAncestorContainer = _caches->cacheAncestorsOfStartToBeConverted(m_start, m_end); + ASSERT(commonAncestorContainer); + + m_dataSource = commonAncestorContainer->document().frame()->loader().documentLoader(); + + Document& document = commonAncestorContainer->document(); + if (auto* body = document.bodyOrFrameset()) { + if (auto backgroundColor = _colorForElement(*body, CSSPropertyBackgroundColor)) + [_documentAttrs setObject:backgroundColor.get() forKey:NSBackgroundColorDocumentAttribute]; + } + + _domRangeStartIndex = 0; + _traverseNode(*commonAncestorContainer, 0, false /* embedded */); + if (_domRangeStartIndex > 0 && _domRangeStartIndex <= [_attrStr length]) + [_attrStr deleteCharactersInRange:NSMakeRange(0, _domRangeStartIndex)]; + + return AttributedString::fromNSAttributedStringAndDocumentAttributes(WTFMove(_attrStr), WTFMove(_documentAttrs)); +} + +#if !PLATFORM(IOS_FAMILY) +static RetainPtr fileWrapperForURL(DocumentLoader* dataSource, NSURL *URL) +{ + if ([URL isFileURL]) + return adoptNS([[NSFileWrapper alloc] initWithURL:[URL URLByResolvingSymlinksInPath] options:0 error:nullptr]); + + if (dataSource) { + if (RefPtr resource = dataSource->subresource(URL)) { + auto wrapper = adoptNS([[NSFileWrapper alloc] initRegularFileWithContents:resource->data().makeContiguous()->createNSData().get()]); + RetainPtr filename = resource->response().suggestedFilename().createNSString(); + if (!filename || ![filename length]) + filename = suggestedFilenameWithMIMEType(resource->url().createNSURL().get(), resource->mimeType()); + [wrapper setPreferredFilename:filename.get()]; + return wrapper; + } + } + + NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:adoptNS([[NSMutableURLRequest alloc] initWithURL:URL]).get()]; + if (cachedResponse) { + auto wrapper = adoptNS([[NSFileWrapper alloc] initRegularFileWithContents:[cachedResponse data]]); + [wrapper setPreferredFilename:[[cachedResponse response] suggestedFilename]]; + return wrapper; + } + + return nil; +} +#endif // !PLATFORM(IOS_FAMILY) + +static PlatformFont *_fontForNameAndSize(NSString *fontName, CGFloat size, NSMutableDictionary *cache) +{ + PlatformFont *font = [cache objectForKey:fontName]; +#if PLATFORM(IOS_FAMILY) + if (font) + return [font fontWithSize:size]; + + font = [PlatformFontClass fontWithName:fontName size:size]; +#else + NSFontManager *fontManager = [NSFontManager sharedFontManager]; + if (font) { + font = [fontManager convertFont:font toSize:size]; + return font; + } + font = [fontManager fontWithFamily:fontName traits:0 weight:0 size:size]; +#endif + if (!font) { +#if PLATFORM(IOS_FAMILY) + NSArray *availableFamilyNames = [PlatformFontClass familyNames]; +#else + NSArray *availableFamilyNames = [fontManager availableFontFamilies]; +#endif + NSRange dividingRange; + NSRange dividingSpaceRange = [fontName rangeOfString:@" " options:NSBackwardsSearch]; + NSRange dividingDashRange = [fontName rangeOfString:@"-" options:NSBackwardsSearch]; + dividingRange = (0 < dividingSpaceRange.length && 0 < dividingDashRange.length) ? (dividingSpaceRange.location > dividingDashRange.location ? dividingSpaceRange : dividingDashRange) : (0 < dividingSpaceRange.length ? dividingSpaceRange : dividingDashRange); + + while (dividingRange.length > 0) { + NSString *familyName = [fontName substringToIndex:dividingRange.location]; + if ([availableFamilyNames containsObject:familyName]) { +#if PLATFORM(IOS_FAMILY) + NSString *faceName = [fontName substringFromIndex:(dividingRange.location + dividingRange.length)]; + NSArray *familyMemberFaceNames = [PlatformFontClass fontNamesForFamilyName:familyName]; + for (NSString *familyMemberFaceName in familyMemberFaceNames) { + if ([familyMemberFaceName compare:faceName options:NSCaseInsensitiveSearch] == NSOrderedSame) { + font = [PlatformFontClass fontWithName:familyMemberFaceName size:size]; + break; + } + } + if (!font && [familyMemberFaceNames count]) + font = [PlatformFontClass fontWithName:familyName size:size]; +#else + NSArray *familyMemberArray; + NSString *faceName = [fontName substringFromIndex:(dividingRange.location + dividingRange.length)]; + NSArray *familyMemberArrays = [fontManager availableMembersOfFontFamily:familyName]; + NSEnumerator *familyMemberArraysEnum = [familyMemberArrays objectEnumerator]; + while ((familyMemberArray = [familyMemberArraysEnum nextObject])) { + NSString *familyMemberFaceName = [familyMemberArray objectAtIndex:1]; + if ([familyMemberFaceName compare:faceName options:NSCaseInsensitiveSearch] == NSOrderedSame) { + NSFontTraitMask traits = [[familyMemberArray objectAtIndex:3] integerValue]; + NSInteger weight = [[familyMemberArray objectAtIndex:2] integerValue]; + font = [fontManager fontWithFamily:familyName traits:traits weight:weight size:size]; + break; + } + } + if (!font) { + if (0 < [familyMemberArrays count]) { + NSArray *familyMemberArray = [familyMemberArrays objectAtIndex:0]; + NSFontTraitMask traits = [[familyMemberArray objectAtIndex:3] integerValue]; + NSInteger weight = [[familyMemberArray objectAtIndex:2] integerValue]; + font = [fontManager fontWithFamily:familyName traits:traits weight:weight size:size]; + } + } +#endif + break; + } else { + dividingSpaceRange = [familyName rangeOfString:@" " options:NSBackwardsSearch]; + dividingDashRange = [familyName rangeOfString:@"-" options:NSBackwardsSearch]; + dividingRange = (0 < dividingSpaceRange.length && 0 < dividingDashRange.length) ? (dividingSpaceRange.location > dividingDashRange.location ? dividingSpaceRange : dividingDashRange) : (0 < dividingSpaceRange.length ? dividingSpaceRange : dividingDashRange); + } + } + } +#if PLATFORM(IOS_FAMILY) + if (!font) + font = [PlatformFontClass systemFontOfSize:size]; +#else + if (!font) + font = [NSFont fontWithName:@"Times" size:size]; + if (!font) + font = [NSFont userFontOfSize:size]; + if (!font) + font = [fontManager convertFont:WebDefaultFont() toSize:size]; + if (!font) + font = WebDefaultFont(); +#endif + [cache setObject:font forKey:fontName]; + + return font; +} + +static NSParagraphStyle *defaultParagraphStyle() +{ + static NeverDestroyed style = [] { + auto style = adoptNS([[PlatformNSParagraphStyle defaultParagraphStyle] mutableCopy]); + [style setDefaultTabInterval:36]; + [style setTabStops:@[]]; + return style; + }(); + return style.get().get(); +} + +RefPtr HTMLConverterCaches::computedStylePropertyForElement(Element& element, CSSPropertyID propertyId) +{ + if (propertyId == CSSPropertyInvalid) + return nullptr; + + auto result = m_computedStyles.add(&element, nullptr); + if (result.isNewEntry) + result.iterator->value = makeUnique(&element, true); + auto& computedStyle = *result.iterator->value; + return computedStyle.propertyValue(propertyId); +} + +RefPtr HTMLConverterCaches::inlineStylePropertyForElement(Element& element, CSSPropertyID propertyId) +{ + if (propertyId == CSSPropertyInvalid) + return nullptr; + + RefPtr styledElement = dynamicDowncast(element); + if (!styledElement) + return nullptr; + + const auto* properties = styledElement->inlineStyle(); + if (!properties) + return nullptr; + return properties->getPropertyCSSValue(propertyId); +} + +static bool stringFromCSSValue(CSSValue& value, String& result) +{ + if (auto* primitiveValue = dynamicDowncast(value)) { + // FIXME: Use isStringType(CSSUnitType)? + auto primitiveType = primitiveValue->primitiveType(); + if (primitiveType == CSSUnitType::CSS_STRING || primitiveType == CSSUnitType::CSS_IDENT || primitiveType == CSSUnitType::CSS_ATTR) { + auto stringValue = value.cssText(CSS::defaultSerializationContext()); + if (stringValue.length()) { + result = stringValue; + return true; + } + } + } else if (value.isValueList() || value.isAppleColorFilterValue() || value.isFilterValue() || value.isTextShadowPropertyValue() || value.isBoxShadowPropertyValue() || value.isURL()) { + result = value.cssText(CSS::defaultSerializationContext()); + return true; + } + return false; +} + +String HTMLConverterCaches::propertyValueForNode(Node& node, CSSPropertyID propertyId) +{ + using namespace ElementNames; + + RefPtr element = dynamicDowncast(node); + if (!element) { + if (RefPtr parent = node.parentInComposedTree()) + return propertyValueForNode(*parent, propertyId); + return String(); + } + + bool inherit = false; + if (RefPtr value = computedStylePropertyForElement(*element, propertyId)) { + String result; + if (stringFromCSSValue(*value, result)) + return result; + } + + if (RefPtr value = inlineStylePropertyForElement(*element, propertyId)) { + String result; + if (isValueID(*value, CSSValueInherit)) + inherit = true; + else if (stringFromCSSValue(*value, result)) + return result; + } + + switch (propertyId) { + case CSSPropertyDisplay: + switch (element->elementName()) { + case HTML::head: + case HTML::script: + case HTML::applet: + case HTML::noframes: + return noneAtom(); + case HTML::address: + case HTML::blockquote: + case HTML::body: + case HTML::center: + case HTML::dd: + case HTML::dir: + case HTML::div: + case HTML::dl: + case HTML::dt: + case HTML::fieldset: + case HTML::form: + case HTML::frame: + case HTML::frameset: + case HTML::hr: + case HTML::html: + case HTML::h1: + case HTML::h2: + case HTML::h3: + case HTML::h4: + case HTML::h5: + case HTML::h6: + case HTML::iframe: + case HTML::menu: + case HTML::noscript: + case HTML::ol: + case HTML::p: + case HTML::pre: + case HTML::ul: + return "block"_s; + case HTML::li: + return "list-item"_s; + case HTML::table: + return "table"_s; + case HTML::tr: + return "table-row"_s; + case HTML::th: + case HTML::td: + return "table-cell"_s; + case HTML::thead: + return "table-header-group"_s; + case HTML::tbody: + return "table-row-group"_s; + case HTML::tfoot: + return "table-footer-group"_s; + case HTML::col: + return "table-column"_s; + case HTML::colgroup: + return "table-column-group"_s; + case HTML::caption: + return "table-caption"_s; + default: + break; + } + break; + case CSSPropertyWhiteSpace: + if (element->hasTagName(preTag)) + return "pre"_s; + inherit = true; + break; + case CSSPropertyFontStyle: + if (element->hasTagName(iTag) || element->hasTagName(citeTag) || element->hasTagName(emTag) || element->hasTagName(varTag) || element->hasTagName(addressTag)) + return "italic"_s; + inherit = true; + break; + case CSSPropertyFontWeight: + if (element->hasTagName(bTag) || element->hasTagName(strongTag) || element->hasTagName(thTag)) + return "bolder"_s; + inherit = true; + break; + case CSSPropertyTextDecorationLine: + switch (element->elementName()) { + case HTML::u: + case HTML::ins: + return "underline"_s; + case HTML::s: + case HTML::strike: + case HTML::del: + return "line-through"_s; + default: + break; + } + inherit = true; // FIXME: This is not strictly correct + break; + case CSSPropertyTextAlign: + if (element->hasTagName(centerTag) || element->hasTagName(captionTag) || element->hasTagName(thTag)) + return "center"_s; + inherit = true; + break; + case CSSPropertyVerticalAlign: + switch (element->elementName()) { + case HTML::sup: + return "super"_s; + case HTML::sub: + return "sub"_s; + case HTML::thead: + case HTML::tbody: + case HTML::tfoot: + return "middle"_s; + case HTML::tr: + case HTML::th: + case HTML::td: + inherit = true; + break; + default: + break; + } + break; + case CSSPropertyFontFamily: + case CSSPropertyFontVariantCaps: + case CSSPropertyTextTransform: + case CSSPropertyTextShadow: + case CSSPropertyVisibility: + case CSSPropertyBorderCollapse: + case CSSPropertyEmptyCells: + case CSSPropertyWordSpacing: + case CSSPropertyListStyleType: + case CSSPropertyDirection: + inherit = true; // FIXME: Let classes in the css component figure this out. + break; + default: + break; + } + + if (inherit) { + if (RefPtr parent = node.parentInComposedTree()) + return propertyValueForNode(*parent, propertyId); + } + + return String(); +} + +static inline bool floatValueFromPrimitiveValue(CSSPrimitiveValue& primitiveValue, float& result) +{ + switch (primitiveValue.primitiveType()) { + case CSSUnitType::CSS_PX: + case CSSUnitType::CSS_PT: + case CSSUnitType::CSS_PC: + case CSSUnitType::CSS_CM: + case CSSUnitType::CSS_MM: + case CSSUnitType::CSS_Q: + case CSSUnitType::CSS_IN: + result = primitiveValue.resolveAsLengthDeprecated(); + return true; + default: + return false; + } +} + +bool HTMLConverterCaches::floatPropertyValueForNode(Node& node, CSSPropertyID propertyId, float& result) +{ + RefPtr element = dynamicDowncast(node); + if (!element) { + if (RefPtr parent = node.parentInComposedTree()) + return floatPropertyValueForNode(*parent, propertyId, result); + return false; + } + + if (RefPtr value = computedStylePropertyForElement(*element, propertyId)) { + if (RefPtr primitiveValue = dynamicDowncast(*value); primitiveValue && floatValueFromPrimitiveValue(*primitiveValue, result)) + return true; + } + + bool inherit = false; + if (RefPtr value = inlineStylePropertyForElement(*element, propertyId)) { + if (RefPtr primitiveValue = dynamicDowncast(*value); primitiveValue && floatValueFromPrimitiveValue(*primitiveValue, result)) + return true; + if (isValueID(*value, CSSValueInherit)) + inherit = true; + } + + switch (propertyId) { + case CSSPropertyTextIndent: + case CSSPropertyLetterSpacing: + case CSSPropertyWordSpacing: + case CSSPropertyLineHeight: + case CSSPropertyWidows: + case CSSPropertyOrphans: + inherit = true; + break; + default: + break; + } + + if (inherit) { + if (RefPtr parent = node.parentInComposedTree()) + return floatPropertyValueForNode(*parent, propertyId, result); + } + + return false; +} + +static inline NSShadow *_shadowForShadowStyle(NSString *shadowStyle) +{ + RetainPtr shadow; + NSUInteger shadowStyleLength = [shadowStyle length]; + NSRange openParenRange = [shadowStyle rangeOfString:@"("]; + NSRange closeParenRange = [shadowStyle rangeOfString:@")"]; + NSRange firstRange = NSMakeRange(NSNotFound, 0); + NSRange secondRange = NSMakeRange(NSNotFound, 0); + NSRange thirdRange = NSMakeRange(NSNotFound, 0); + NSRange spaceRange; + if (openParenRange.length > 0 && closeParenRange.length > 0 && NSMaxRange(openParenRange) < closeParenRange.location) { + NSArray *components = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(openParenRange), closeParenRange.location - NSMaxRange(openParenRange))] componentsSeparatedByString:@","]; + if ([components count] >= 3) { + CGFloat red = [[components objectAtIndex:0] floatValue] / 255; + CGFloat green = [[components objectAtIndex:1] floatValue] / 255; + CGFloat blue = [[components objectAtIndex:2] floatValue] / 255; + CGFloat alpha = ([components count] >= 4) ? [[components objectAtIndex:3] floatValue] / 255 : 1; + NSColor *shadowColor = [PlatformNSColorClass colorWithCalibratedRed:red green:green blue:blue alpha:alpha]; + NSSize shadowOffset; + CGFloat shadowBlurRadius; + firstRange = [shadowStyle rangeOfString:@"px"]; + if (firstRange.length > 0 && NSMaxRange(firstRange) < shadowStyleLength) + secondRange = [shadowStyle rangeOfString:@"px" options:0 range:NSMakeRange(NSMaxRange(firstRange), shadowStyleLength - NSMaxRange(firstRange))]; + if (secondRange.length > 0 && NSMaxRange(secondRange) < shadowStyleLength) + thirdRange = [shadowStyle rangeOfString:@"px" options:0 range:NSMakeRange(NSMaxRange(secondRange), shadowStyleLength - NSMaxRange(secondRange))]; + if (firstRange.location > 0 && firstRange.length > 0 && secondRange.length > 0 && thirdRange.length > 0) { + spaceRange = [shadowStyle rangeOfString:@" " options:NSBackwardsSearch range:NSMakeRange(0, firstRange.location)]; + if (spaceRange.length == 0) + spaceRange = NSMakeRange(0, 0); + shadowOffset.width = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(spaceRange), firstRange.location - NSMaxRange(spaceRange))] floatValue]; + spaceRange = [shadowStyle rangeOfString:@" " options:NSBackwardsSearch range:NSMakeRange(0, secondRange.location)]; + if (!spaceRange.length) + spaceRange = NSMakeRange(0, 0); + CGFloat shadowHeight = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(spaceRange), secondRange.location - NSMaxRange(spaceRange))] floatValue]; + // I don't know why we have this difference between the two platforms. +#if PLATFORM(IOS_FAMILY) + shadowOffset.height = shadowHeight; +#else + shadowOffset.height = -shadowHeight; +#endif + spaceRange = [shadowStyle rangeOfString:@" " options:NSBackwardsSearch range:NSMakeRange(0, thirdRange.location)]; + if (!spaceRange.length) + spaceRange = NSMakeRange(0, 0); + shadowBlurRadius = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(spaceRange), thirdRange.location - NSMaxRange(spaceRange))] floatValue]; + shadow = adoptNS([(NSShadow *)[PlatformNSShadow alloc] init]); + [shadow setShadowColor:shadowColor]; + [shadow setShadowOffset:shadowOffset]; + [shadow setShadowBlurRadius:shadowBlurRadius]; + } + } + } + return shadow.autorelease(); +} + +bool HTMLConverterCaches::isBlockElement(Element& element) +{ + String displayValue = propertyValueForNode(element, CSSPropertyDisplay); + if (displayValue == "block"_s || displayValue == "list-item"_s || displayValue.startsWith("table"_s)) + return true; + String floatValue = propertyValueForNode(element, CSSPropertyFloat); + if (floatValue == "left"_s || floatValue == "right"_s) + return true; + return false; +} + +bool HTMLConverterCaches::elementHasOwnBackgroundColor(Element& element) +{ + if (!isBlockElement(element)) + return false; + // In the text system, text blocks (table elements) and documents (body elements) + // have their own background colors, which should not be inherited. + return element.hasTagName(htmlTag) || element.hasTagName(bodyTag) || propertyValueForNode(element, CSSPropertyDisplay).startsWith("table"_s); +} + +Element* HTMLConverter::_blockLevelElementForNode(Node* node) +{ + RefPtr element = dynamicDowncast(node); + if (!element) + element = node->parentElement(); + if (element && !_caches->isBlockElement(*element)) + element = _blockLevelElementForNode(element->parentInComposedTree()); + return element.get(); +} + +static Color normalizedColor(Color color, bool ignoreDefaultColor, Element& element) +{ + if (!ignoreDefaultColor) + return color; + + bool useDarkAppearance = element.document().useDarkAppearance(element.existingComputedStyle()); + if (useDarkAppearance && Color::isWhiteColor(color)) + return Color(); + + if (!useDarkAppearance && Color::isBlackColor(color)) + return Color(); + + return color; +} + +Color HTMLConverterCaches::colorPropertyValueForNode(Node& node, CSSPropertyID propertyId) +{ + RefPtr element = dynamicDowncast(node); + if (!element) { + if (RefPtr parent = node.parentInComposedTree()) + return colorPropertyValueForNode(*parent, propertyId); + return Color(); + } + + bool ignoreDefaultColor = propertyId == CSSPropertyColor; + + if (auto value = computedStylePropertyForElement(*element, propertyId); value && value->isColor()) + return normalizedColor(CSSColorValue::absoluteColor(*value), ignoreDefaultColor, *element); + + bool inherit = false; + if (auto value = inlineStylePropertyForElement(*element, propertyId)) { + if (value->isColor()) + return normalizedColor(CSSColorValue::absoluteColor(*value), ignoreDefaultColor, *element); + if (isValueID(*value, CSSValueInherit)) + inherit = true; + } + + switch (propertyId) { + case CSSPropertyColor: + inherit = true; + break; + case CSSPropertyBackgroundColor: + if (!elementHasOwnBackgroundColor(*element)) { + if (auto* parentElement = node.parentElement()) { + if (!elementHasOwnBackgroundColor(*parentElement)) + inherit = true; + } + } + break; + default: + break; + } + + if (inherit) { + if (RefPtr parent = node.parentInComposedTree()) + return colorPropertyValueForNode(*parent, propertyId); + } + + return Color(); +} + +RetainPtr HTMLConverter::_colorForElement(Element& element, CSSPropertyID propertyId) +{ + Color result = _caches->colorPropertyValueForNode(element, propertyId); + if (!result.isValid()) + return nil; + auto platformResult = cocoaColor(result); + if ([[PlatformColorClass clearColor] isEqual:platformResult.get()] || ([platformResult alphaComponent] == 0.0)) + return nil; + return platformResult; +} + +static PlatformFont *_font(Element& element) +{ + auto* renderer = element.renderer(); + if (!renderer) + return nil; + Ref primaryFont = renderer->style().fontCascade().primaryFont(); + if (primaryFont->attributes().origin == FontOrigin::Remote) + return [PlatformFontClass systemFontOfSize:defaultFontSize]; + return (__bridge PlatformFont *)primaryFont->ctFont(); +} + +NSDictionary *HTMLConverter::computedAttributesForElement(Element& element) +{ + NSMutableDictionary *attrs = [NSMutableDictionary dictionary]; +#if !PLATFORM(IOS_FAMILY) + NSFontManager *fontManager = [NSFontManager sharedFontManager]; +#endif + + PlatformFont *font = nil; + PlatformFont *actualFont = _font(element); + auto foregroundColor = _colorForElement(element, CSSPropertyColor); + auto backgroundColor = _colorForElement(element, CSSPropertyBackgroundColor); + auto strokeColor = _colorForElement(element, CSSPropertyWebkitTextStrokeColor); + + float fontSize = 0; + if (!_caches->floatPropertyValueForNode(element, CSSPropertyFontSize, fontSize) || fontSize <= 0.0) + fontSize = defaultFontSize; + if (fontSize < minimumFontSize) + fontSize = minimumFontSize; + if (std::abs(floor(2.0 * fontSize + 0.5) / 2.0 - fontSize) < 0.05) + fontSize = floor(2.0 * fontSize + 0.5) / 2; + else if (std::abs(floor(10.0 * fontSize + 0.5) / 10.0 - fontSize) < 0.005) + fontSize = floor(10.0 * fontSize + 0.5) / 10; + + if (fontSize <= 0.0) + fontSize = defaultFontSize; + +#if PLATFORM(IOS_FAMILY) + if (actualFont) + font = [actualFont fontWithSize:fontSize]; +#else + if (actualFont) + font = [fontManager convertFont:actualFont toSize:fontSize]; +#endif + if (!font) { + String fontName = _caches->propertyValueForNode(element, CSSPropertyFontFamily); + if (fontName.length()) + font = _fontForNameAndSize(fontName.convertToASCIILowercase().createNSString().get(), fontSize, _fontCache.get()); + if (!font) + font = [PlatformFontClass fontWithName:@"Times" size:fontSize]; + + String fontStyle = _caches->propertyValueForNode(element, CSSPropertyFontStyle); + if (fontStyle == "italic"_s || fontStyle == "oblique"_s) { + PlatformFont *originalFont = font; +#if PLATFORM(IOS_FAMILY) + font = [PlatformFontClass fontWithFamilyName:[font familyName] traits:UIFontTraitItalic size:[font pointSize]]; +#else + font = [fontManager convertFont:font toHaveTrait:NSItalicFontMask]; +#endif + if (!font) + font = originalFont; + } + + String fontWeight = _caches->propertyValueForNode(element, CSSPropertyFontStyle); + if (fontWeight.startsWith("bold"_s) || parseIntegerAllowingTrailingJunk(fontWeight).value_or(0) >= 700) { + // ??? handle weight properly using NSFontManager + PlatformFont *originalFont = font; +#if PLATFORM(IOS_FAMILY) + font = [PlatformFontClass fontWithFamilyName:[font familyName] traits:UIFontTraitBold size:[font pointSize]]; +#else + font = [fontManager convertFont:font toHaveTrait:NSBoldFontMask]; +#endif + if (!font) + font = originalFont; + } +#if !PLATFORM(IOS_FAMILY) // IJB: No small caps support on iOS + if (_caches->propertyValueForNode(element, CSSPropertyFontVariantCaps) == "small-caps"_s) { + // ??? synthesize small-caps if [font isEqual:originalFont] + NSFont *originalFont = font; + font = [fontManager convertFont:font toHaveTrait:NSSmallCapsFontMask]; + if (!font) + font = originalFont; + } +#endif + } + if (font) + [attrs setObject:font forKey:NSFontAttributeName]; + if (foregroundColor) + [attrs setObject:foregroundColor.get() forKey:NSForegroundColorAttributeName]; + if (backgroundColor && !_caches->elementHasOwnBackgroundColor(element)) + [attrs setObject:backgroundColor.get() forKey:NSBackgroundColorAttributeName]; + + float strokeWidth = 0.0; + if (_caches->floatPropertyValueForNode(element, CSSPropertyWebkitTextStrokeWidth, strokeWidth)) { + float textStrokeWidth = strokeWidth / ([font pointSize] * 0.01); + [attrs setObject:@(textStrokeWidth) forKey:NSStrokeWidthAttributeName]; + } + if (strokeColor) + [attrs setObject:strokeColor.get() forKey:NSStrokeColorAttributeName]; + + String fontKerning = _caches->propertyValueForNode(element, CSSPropertyFontKerning); + String letterSpacing = _caches->propertyValueForNode(element, CSSPropertyLetterSpacing); + if (fontKerning.length() || letterSpacing.length()) { + if (fontKerning == noneAtom()) + [attrs setObject:@0.0 forKey:NSKernAttributeName]; + else { + double kernVal = letterSpacing.length() ? letterSpacing.toDouble() : 0.0; + if (std::abs(kernVal - 0) < FLT_EPSILON) + [attrs setObject:@0.0 forKey:NSKernAttributeName]; // auto and normal, the other possible values, are both "kerning enabled" + else + [attrs setObject:@(kernVal) forKey:NSKernAttributeName]; + } + } + + String fontLigatures = _caches->propertyValueForNode(element, CSSPropertyFontVariantLigatures); + if (fontLigatures.length()) { + if (fontLigatures.contains("normal"_s)) + ; // default: whatever the system decides to do + else if (fontLigatures.contains("common-ligatures"_s)) + [attrs setObject:@1 forKey:NSLigatureAttributeName]; // explicitly enabled + else if (fontLigatures.contains("no-common-ligatures"_s)) + [attrs setObject:@0 forKey:NSLigatureAttributeName]; // explicitly disabled + } + + String textDecoration = _caches->propertyValueForNode(element, CSSPropertyTextDecorationLine); + if (textDecoration.length()) { + if (textDecoration.contains("underline"_s)) + [attrs setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName]; + if (textDecoration.contains("line-through"_s)) + [attrs setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName]; + } + + String verticalAlign = _caches->propertyValueForNode(element, CSSPropertyVerticalAlign); + if (verticalAlign.length()) { + if (verticalAlign == "super"_s) + [attrs setObject:[NSNumber numberWithInteger:1] forKey:NSSuperscriptAttributeName]; + else if (verticalAlign == "sub"_s) + [attrs setObject:[NSNumber numberWithInteger:-1] forKey:NSSuperscriptAttributeName]; + } + + float baselineOffset = 0.0; + if (_caches->floatPropertyValueForNode(element, CSSPropertyVerticalAlign, baselineOffset)) + [attrs setObject:@(baselineOffset) forKey:NSBaselineOffsetAttributeName]; + + String textShadow = _caches->propertyValueForNode(element, CSSPropertyTextShadow); + if (textShadow.length() > 4) { + NSShadow *shadow = _shadowForShadowStyle(textShadow.createNSString().get()); + if (shadow) + [attrs setObject:shadow forKey:NSShadowAttributeName]; + } + + Element* blockElement = _blockLevelElementForNode(&element); + if (&element != blockElement && [_writingDirectionArray count] > 0) + [attrs setObject:[NSArray arrayWithArray:_writingDirectionArray.get()] forKey:NSWritingDirectionAttributeName]; + + if (blockElement) { + Element& coreBlockElement = *blockElement; + RetainPtr paragraphStyle = adoptNS([defaultParagraphStyle() mutableCopy]); + unsigned heading = 0; + if (coreBlockElement.hasTagName(h1Tag)) + heading = 1; + else if (coreBlockElement.hasTagName(h2Tag)) + heading = 2; + else if (coreBlockElement.hasTagName(h3Tag)) + heading = 3; + else if (coreBlockElement.hasTagName(h4Tag)) + heading = 4; + else if (coreBlockElement.hasTagName(h5Tag)) + heading = 5; + else if (coreBlockElement.hasTagName(h6Tag)) + heading = 6; + else if (coreBlockElement.hasTagName(blockquoteTag) && _topPresentationIntent) + [attrs setObject:_topPresentationIntent.get() forKey:NSPresentationIntentAttributeName]; + bool isParagraph = coreBlockElement.hasTagName(pTag) || coreBlockElement.hasTagName(liTag) || heading || coreBlockElement.hasTagName(blockquoteTag); + + String textAlign = _caches->propertyValueForNode(coreBlockElement, CSSPropertyTextAlign); + if (textAlign.length()) { + // WebKit can return -khtml-left, -khtml-right, -khtml-center + if (textAlign.endsWith("left"_s)) + [paragraphStyle setAlignment:NSTextAlignmentLeft]; + else if (textAlign.endsWith("right"_s)) + [paragraphStyle setAlignment:NSTextAlignmentRight]; + else if (textAlign.endsWith("center"_s)) + [paragraphStyle setAlignment:NSTextAlignmentCenter]; + else if (textAlign.endsWith("justify"_s)) + [paragraphStyle setAlignment:NSTextAlignmentJustified]; + } + + String direction = _caches->propertyValueForNode(coreBlockElement, CSSPropertyDirection); + if (direction.length()) { + if (direction == "ltr"_s) + [paragraphStyle setBaseWritingDirection:NSWritingDirectionLeftToRight]; + else if (direction == "rtl"_s) + [paragraphStyle setBaseWritingDirection:NSWritingDirectionRightToLeft]; + } + + String hyphenation = _caches->propertyValueForNode(coreBlockElement, CSSPropertyHyphens); + if (hyphenation.length()) { + if (hyphenation == autoAtom()) + [paragraphStyle setHyphenationFactor:1.0]; + else + [paragraphStyle setHyphenationFactor:0.0]; + } + if (heading) + [paragraphStyle setHeaderLevel:heading]; + if (isParagraph) { + // FIXME: Why are we ignoring margin-top? + float marginLeft = 0.0; + if (_caches->floatPropertyValueForNode(coreBlockElement, CSSPropertyMarginLeft, marginLeft) && marginLeft > 0.0) + [paragraphStyle setHeadIndent:marginLeft]; + float textIndent = 0.0; + if (_caches->floatPropertyValueForNode(coreBlockElement, CSSPropertyTextIndent, textIndent) && textIndent > 0.0) + [paragraphStyle setFirstLineHeadIndent:[paragraphStyle headIndent] + textIndent]; + float marginRight = 0.0; + if (_caches->floatPropertyValueForNode(coreBlockElement, CSSPropertyMarginRight, marginRight) && marginRight > 0.0) + [paragraphStyle setTailIndent:-marginRight]; + float marginBottom = 0.0; + if (_caches->floatPropertyValueForNode(coreBlockElement, CSSPropertyMarginBottom, marginBottom) && marginBottom > 0.0) + [paragraphStyle setParagraphSpacing:marginBottom]; + } + if ([_textLists count] > 0) + [paragraphStyle setTextLists:_textLists.get()]; + if ([_textBlocks count] > 0) + [paragraphStyle setTextBlocks:_textBlocks.get()]; + [attrs setObject:paragraphStyle.get() forKey:NSParagraphStyleAttributeName]; + } + return attrs; +} + + +NSDictionary* HTMLConverter::attributesForElement(Element& element) +{ + auto& attributes = m_attributesForElements.add(&element, nullptr).iterator->value; + if (!attributes) + attributes = computedAttributesForElement(element); + return attributes.get(); +} + +NSDictionary* HTMLConverter::aggregatedAttributesForAncestors(CharacterData& node) +{ + Node* ancestor = node.parentInComposedTree(); + while (ancestor && !is(*ancestor)) + ancestor = ancestor->parentInComposedTree(); + if (!ancestor) + return nullptr; + return aggregatedAttributesForElementAndItsAncestors(downcast(*ancestor)); +} + +NSDictionary* HTMLConverter::aggregatedAttributesForElementAndItsAncestors(Element& element) +{ + auto& cachedAttributes = m_aggregatedAttributesForElements.add(&element, nullptr).iterator->value; + if (cachedAttributes) + return cachedAttributes.get(); + + NSDictionary* attributesForCurrentElement = attributesForElement(element); + ASSERT(attributesForCurrentElement); + + Node* ancestor = element.parentInComposedTree(); + while (ancestor && !is(*ancestor)) + ancestor = ancestor->parentInComposedTree(); + + if (!ancestor) { + cachedAttributes = attributesForCurrentElement; + return attributesForCurrentElement; + } + + RetainPtr attributesForAncestors = adoptNS([aggregatedAttributesForElementAndItsAncestors(downcast(*ancestor)) mutableCopy]); + [attributesForAncestors addEntriesFromDictionary:attributesForCurrentElement]; + m_aggregatedAttributesForElements.set(&element, attributesForAncestors); + + return attributesForAncestors.get(); +} + +void HTMLConverter::_newParagraphForElement(Element& element, NSString *tag, BOOL flag, BOOL suppressTrailingSpace) +{ + NSUInteger textLength = [_attrStr length]; + unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n'; + NSRange rangeToReplace = (suppressTrailingSpace && _flags.isSoft && (lastChar == ' ' || lastChar == NSLineSeparatorCharacter)) ? NSMakeRange(textLength - 1, 1) : NSMakeRange(textLength, 0); + BOOL needBreak = (flag || lastChar != '\n'); + if (needBreak) { + NSString *string = (([@"BODY" isEqualToString:tag] || [@"HTML" isEqualToString:tag]) ? @"" : @"\n"); + [_writingDirectionArray removeAllObjects]; + [_attrStr replaceCharactersInRange:rangeToReplace withString:string]; + if (rangeToReplace.location < _domRangeStartIndex) + _domRangeStartIndex += [string length] - rangeToReplace.length; + rangeToReplace.length = [string length]; + NSDictionary *attrs = attributesForElement(element); + if (rangeToReplace.length > 0) + [_attrStr setAttributes:attrs range:rangeToReplace]; + _flags.isSoft = YES; + } +} + +void HTMLConverter::_newLineForElement(Element& element) +{ + unichar c = NSLineSeparatorCharacter; + RetainPtr string = adoptNS([[NSString alloc] initWithCharacters:&c length:1]); + NSUInteger textLength = [_attrStr length]; + NSRange rangeToReplace = NSMakeRange(textLength, 0); + [_attrStr replaceCharactersInRange:rangeToReplace withString:string.get()]; + rangeToReplace.length = [string length]; + if (rangeToReplace.location < _domRangeStartIndex) + _domRangeStartIndex += rangeToReplace.length; + NSDictionary *attrs = attributesForElement(element); + if (rangeToReplace.length > 0) + [_attrStr setAttributes:attrs range:rangeToReplace]; + _flags.isSoft = YES; +} + +void HTMLConverter::_newTabForElement(Element& element) +{ + NSString *string = @"\t"; + NSUInteger textLength = [_attrStr length]; + unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n'; + NSRange rangeToReplace = (_flags.isSoft && lastChar == ' ') ? NSMakeRange(textLength - 1, 1) : NSMakeRange(textLength, 0); + [_attrStr replaceCharactersInRange:rangeToReplace withString:string]; + rangeToReplace.length = [string length]; + if (rangeToReplace.location < _domRangeStartIndex) + _domRangeStartIndex += rangeToReplace.length; + NSDictionary *attrs = attributesForElement(element); + if (rangeToReplace.length > 0) + [_attrStr setAttributes:attrs range:rangeToReplace]; + _flags.isSoft = YES; +} + +static Class _WebMessageDocumentClassSingleton() +{ + static Class _WebMessageDocumentClass = Nil; + static BOOL lookedUpClass = NO; + if (!lookedUpClass) { + // If the class is not there, we don't want to try again +#if PLATFORM(MAC) + _WebMessageDocumentClass = objc_lookUpClass("EditableWebMessageDocument"); +#endif + if (!_WebMessageDocumentClass) + _WebMessageDocumentClass = objc_lookUpClass("WebMessageDocument"); + + if (_WebMessageDocumentClass && ![_WebMessageDocumentClass respondsToSelector:@selector(document:attachment:forURL:)]) + _WebMessageDocumentClass = Nil; + lookedUpClass = YES; + } + return _WebMessageDocumentClass; +} + +#if ENABLE(MULTI_REPRESENTATION_HEIC) +BOOL HTMLConverter::_addMultiRepresentationHEICAttachmentForImageElement(HTMLImageElement& element) +{ + RefPtr image = element.image(); + if (!image) + return NO; + + NSAdaptiveImageGlyph *attachment = image->adapter().multiRepresentationHEIC(); + if (!attachment) + return NO; + + NSUInteger textLength = [_attrStr length]; + + RetainPtr string = adoptNS([[NSString alloc] initWithFormat:@"%C", static_cast(NSAttachmentCharacter)]); + NSRange rangeToReplace = NSMakeRange(textLength, 0); + + [_attrStr replaceCharactersInRange:rangeToReplace withString:string.get()]; + rangeToReplace.length = [string length]; + if (rangeToReplace.location < _domRangeStartIndex) + _domRangeStartIndex += rangeToReplace.length; + + [_attrStr addAttribute:NSAdaptiveImageGlyphAttributeName value:attachment range:rangeToReplace]; + + _flags.isSoft = NO; + return YES; +} +#endif // ENABLE(MULTI_REPRESENTATION_HEIC) + +BOOL HTMLConverter::_addAttachmentForElement(Element& element, NSURL *url, BOOL needsParagraph, BOOL usePlaceholder) +{ + BOOL retval = NO; + BOOL notFound = NO; + RetainPtr fileWrapper; + auto* frame = element.document().frame(); + DocumentLoader *dataSource = frame->loader().frameHasLoaded() ? frame->loader().documentLoader() : 0; + BOOL ignoreOrientation = YES; + + if ([url isFileURL]) { + NSString *path = [[url path] stringByStandardizingPath]; + if (path) + fileWrapper = adoptNS([[NSFileWrapper alloc] initWithURL:url options:0 error:NULL]); + } + if (!fileWrapper && dataSource) { + if (auto resource = dataSource->subresource(url)) { + auto& mimeType = resource->mimeType(); + if (!usePlaceholder || mimeType != textHTMLContentTypeAtom()) { + fileWrapper = adoptNS([[NSFileWrapper alloc] initRegularFileWithContents:resource->data().makeContiguous()->createNSData().get()]); + [fileWrapper setPreferredFilename:suggestedFilenameWithMIMEType(url, mimeType)]; + } else + notFound = YES; + } + } +#if !PLATFORM(IOS_FAMILY) + if (!fileWrapper && !notFound) { + fileWrapper = fileWrapperForURL(dataSource, url); + if (usePlaceholder && fileWrapper && [[[[fileWrapper preferredFilename] pathExtension] lowercaseString] hasPrefix:@"htm"]) + notFound = YES; + if (notFound) + fileWrapper = nil; + } + if (!fileWrapper && !notFound) { + fileWrapper = fileWrapperForURL(m_dataSource, url); + if (usePlaceholder && fileWrapper && [[[[fileWrapper preferredFilename] pathExtension] lowercaseString] hasPrefix:@"htm"]) + notFound = YES; + if (notFound) + fileWrapper = nil; + } +#endif + if (!fileWrapper && !notFound && url) { + // Special handling for Mail attachments, until WebKit provides a standard way to get the data. + Class WebMessageDocumentClass = _WebMessageDocumentClassSingleton(); + if (WebMessageDocumentClass) { + NSTextAttachment *mimeTextAttachment = nil; + [WebMessageDocumentClass document:NULL attachment:&mimeTextAttachment forURL:url]; + if (mimeTextAttachment && [mimeTextAttachment respondsToSelector:@selector(fileWrapper)]) { + fileWrapper = [mimeTextAttachment fileWrapper]; + ignoreOrientation = NO; + } + } + } + if (fileWrapper || usePlaceholder) { + RetainPtr attachment; + NSAttributedStringKey attributeName = NSAttachmentAttributeName; + + NSUInteger textLength = [_attrStr length]; + RetainPtr string = adoptNS([[NSString alloc] initWithFormat:(needsParagraph ? @"%C\n" : @"%C"), static_cast(NSAttachmentCharacter)]); + NSRange rangeToReplace = NSMakeRange(textLength, 0); + NSDictionary *attrs; + +#if ENABLE(MULTI_REPRESENTATION_HEIC) + if (RetainPtr data = [fileWrapper regularFileContents]) { + RefPtr imageElement = dynamicDowncast(element); + if (imageElement && imageElement->isMultiRepresentationHEIC()) + attachment = adoptNS([[PlatformNSAdaptiveImageGlyph alloc] initWithImageContent:data.get()]); + if (attachment) + attributeName = NSAdaptiveImageGlyphAttributeName; + } +#endif + + if (!attachment) { + RetainPtr textAttachment = adoptNS([[PlatformNSTextAttachment alloc] initWithFileWrapper:fileWrapper.get()]); + + if (auto& ariaLabel = element.getAttribute("aria-label"_s); !ariaLabel.isEmpty()) + [textAttachment setAccessibilityLabel:ariaLabel.createNSString().get()]; + if (auto& altText = element.getAttribute("alt"_s); !altText.isEmpty()) + [textAttachment setAccessibilityLabel:altText.createNSString().get()]; + +#if PLATFORM(IOS_FAMILY) + float verticalAlign = 0.0; + _caches->floatPropertyValueForNode(element, CSSPropertyVerticalAlign, verticalAlign); + [textAttachment setBounds:CGRectMake(0, (verticalAlign / 100) * element.clientHeight(), element.clientWidth(), element.clientHeight())]; +#endif + if (fileWrapper) { +#if PLATFORM(IOS_FAMILY) + UNUSED_VARIABLE(ignoreOrientation); +#else + if (ignoreOrientation) + [textAttachment setIgnoresOrientation:YES]; +#endif + } else { + textAttachment = adoptNS([[PlatformNSTextAttachment alloc] initWithData:nil ofType:nil]); + [textAttachment setImage:webCoreTextAttachmentMissingPlatformImage()]; + } + + attachment = textAttachment; + } + + [_attrStr replaceCharactersInRange:rangeToReplace withString:string.get()]; + rangeToReplace.length = [string length]; + if (rangeToReplace.location < _domRangeStartIndex) + _domRangeStartIndex += rangeToReplace.length; + attrs = attributesForElement(element); + if (rangeToReplace.length > 0) { + [_attrStr setAttributes:attrs range:rangeToReplace]; + rangeToReplace.length = 1; + [_attrStr addAttribute:attributeName value:attachment.get() range:rangeToReplace]; + } + _flags.isSoft = NO; + retval = YES; + } + return retval; +} + +void HTMLConverter::_addQuoteForElement(Element& element, BOOL opening, NSInteger level) +{ + unichar c = ((level % 2) == 0) ? (opening ? 0x201c : 0x201d) : (opening ? 0x2018 : 0x2019); + RetainPtr string = adoptNS([[NSString alloc] initWithCharacters:&c length:1]); + NSUInteger textLength = [_attrStr length]; + NSRange rangeToReplace = NSMakeRange(textLength, 0); + [_attrStr replaceCharactersInRange:rangeToReplace withString:string.get()]; + rangeToReplace.length = [string length]; + if (rangeToReplace.location < _domRangeStartIndex) + _domRangeStartIndex += rangeToReplace.length; + RetainPtr attrs = attributesForElement(element); + if (rangeToReplace.length > 0) + [_attrStr setAttributes:attrs.get() range:rangeToReplace]; + _flags.isSoft = NO; +} + +void HTMLConverter::_addValue(NSString *value, Element& element) +{ + NSUInteger textLength = [_attrStr length]; + NSUInteger valueLength = [value length]; + NSRange rangeToReplace = NSMakeRange(textLength, 0); + if (valueLength) { + [_attrStr replaceCharactersInRange:rangeToReplace withString:value]; + rangeToReplace.length = valueLength; + if (rangeToReplace.location < _domRangeStartIndex) + _domRangeStartIndex += rangeToReplace.length; + RetainPtr attrs = attributesForElement(element); + if (rangeToReplace.length > 0) + [_attrStr setAttributes:attrs.get() range:rangeToReplace]; + _flags.isSoft = NO; + } +} + +void HTMLConverter::_fillInBlock(NSTextBlock *block, Element& element, PlatformColor *backgroundColor, CGFloat extraMargin, CGFloat extraPadding, BOOL isTable) +{ + float result = 0; + + RetainPtr width = element.getAttribute(widthAttr).createNSString(); + if ((width && [width length]) || !isTable) { + if (_caches->floatPropertyValueForNode(element, CSSPropertyWidth, result)) + [block setValue:result type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockWidth]; + } + + if (_caches->floatPropertyValueForNode(element, CSSPropertyMinWidth, result)) + [block setValue:result type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMinimumWidth]; + if (_caches->floatPropertyValueForNode(element, CSSPropertyMaxWidth, result)) + [block setValue:result type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMaximumWidth]; + if (_caches->floatPropertyValueForNode(element, CSSPropertyMinHeight, result)) + [block setValue:result type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMinimumHeight]; + if (_caches->floatPropertyValueForNode(element, CSSPropertyMaxHeight, result)) + [block setValue:result type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMaximumHeight]; + + if (_caches->floatPropertyValueForNode(element, CSSPropertyPaddingLeft, result)) + [block setWidth:result + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinXEdge]; + else + [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinXEdge]; + + if (_caches->floatPropertyValueForNode(element, CSSPropertyPaddingTop, result)) + [block setWidth:result + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinYEdge]; + else + [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinYEdge]; + + if (_caches->floatPropertyValueForNode(element, CSSPropertyPaddingRight, result)) + [block setWidth:result + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxXEdge]; + else + [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxXEdge]; + + if (_caches->floatPropertyValueForNode(element, CSSPropertyPaddingBottom, result)) + [block setWidth:result + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxYEdge]; + else + [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxYEdge]; + + if (_caches->floatPropertyValueForNode(element, CSSPropertyBorderLeftWidth, result)) + [block setWidth:result type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMinXEdge]; + if (_caches->floatPropertyValueForNode(element, CSSPropertyBorderTopWidth, result)) + [block setWidth:result type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMinYEdge]; + if (_caches->floatPropertyValueForNode(element, CSSPropertyBorderRightWidth, result)) + [block setWidth:result type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMaxXEdge]; + if (_caches->floatPropertyValueForNode(element, CSSPropertyBorderBottomWidth, result)) + [block setWidth:result type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMaxYEdge]; + + if (_caches->floatPropertyValueForNode(element, CSSPropertyMarginLeft, result)) + [block setWidth:result + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinXEdge]; + else + [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinXEdge]; + if (_caches->floatPropertyValueForNode(element, CSSPropertyMarginTop, result)) + [block setWidth:result + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinYEdge]; + else + [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinYEdge]; + if (_caches->floatPropertyValueForNode(element, CSSPropertyMarginRight, result)) + [block setWidth:result + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxXEdge]; + else + [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxXEdge]; + if (_caches->floatPropertyValueForNode(element, CSSPropertyMarginBottom, result)) + [block setWidth:result + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxYEdge]; + else + [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxYEdge]; + + RetainPtr color; + if ((color = _colorForElement(element, CSSPropertyBackgroundColor))) + [block setBackgroundColor:color.get()]; + if (!color && backgroundColor) + [block setBackgroundColor:backgroundColor]; + + if ((color = _colorForElement(element, CSSPropertyBorderLeftColor))) + [block setBorderColor:color.get() forEdge:NSMinXEdge]; + + if ((color = _colorForElement(element, CSSPropertyBorderTopColor))) + [block setBorderColor:color.get() forEdge:NSMinYEdge]; + if ((color = _colorForElement(element, CSSPropertyBorderRightColor))) + [block setBorderColor:color.get() forEdge:NSMaxXEdge]; + if ((color = _colorForElement(element, CSSPropertyBorderBottomColor))) + [block setBorderColor:color.get() forEdge:NSMaxYEdge]; +} + +static inline BOOL read2DigitNumber(std::span& p, int8_t& outval) +{ + BOOL result = NO; + char c1 = consume(p); + if (isASCIIDigit(c1)) { + char c2 = consume(p); + if (isASCIIDigit(c2)) { + outval = 10 * (c1 - '0') + (c2 - '0'); + result = YES; + } + } + return result; +} + +static inline NSDate *_dateForString(NSString *string) +{ + auto p = unsafeSpanIncludingNullTerminator([string UTF8String]); + RetainPtr dateComponents = adoptNS([[NSDateComponents alloc] init]); + + // Set the time zone to GMT + [dateComponents setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; + + NSInteger year = 0; + while (p.front() && isASCIIDigit(p.front())) + year = 10 * year + consume(p) - '0'; + if (consume(p) != '-') + return nil; + [dateComponents setYear:year]; + + int8_t component; + if (!read2DigitNumber(p, component) || consume(p) != '-') + return nil; + [dateComponents setMonth:component]; + + if (!read2DigitNumber(p, component) || consume(p) != 'T') + return nil; + [dateComponents setDay:component]; + + if (!read2DigitNumber(p, component) || consume(p) != ':') + return nil; + [dateComponents setHour:component]; + + if (!read2DigitNumber(p, component) || consume(p) != ':') + return nil; + [dateComponents setMinute:component]; + + if (!read2DigitNumber(p, component) || consume(p) != 'Z') + return nil; + [dateComponents setSecond:component]; + + auto calendar = adoptNS([[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]); + return [calendar dateFromComponents:dateComponents.get()]; +} + +static NSInteger _colCompare(id block1, id block2, void *) +{ + NSInteger col1 = [(NSTextTableBlock *)block1 startingColumn]; + NSInteger col2 = [(NSTextTableBlock *)block2 startingColumn]; + return ((col1 < col2) ? NSOrderedAscending : ((col1 == col2) ? NSOrderedSame : NSOrderedDescending)); +} + +void HTMLConverter::_processMetaElementWithName(NSString *name, NSString *content) +{ + NSString *key = nil; + if (NSOrderedSame == [@"CocoaVersion" compare:name options:NSCaseInsensitiveSearch]) { + CGFloat versionNumber = [content doubleValue]; + if (versionNumber > 0.0) { + // ??? this should be keyed off of version number in future + [_documentAttrs removeObjectForKey:NSConvertedDocumentAttribute]; + [_documentAttrs setObject:@(versionNumber) forKey:NSCocoaVersionDocumentAttribute]; + } +#if PLATFORM(IOS_FAMILY) + } else if (NSOrderedSame == [@"Generator" compare:name options:NSCaseInsensitiveSearch]) { + key = NSGeneratorDocumentAttribute; +#endif + } else if (NSOrderedSame == [@"Keywords" compare:name options:NSCaseInsensitiveSearch]) { + if (content && [content length] > 0) { + NSArray *array; + // ??? need better handling here and throughout + if ([content rangeOfString:@", "].length == 0 && [content rangeOfString:@","].length > 0) + array = [content componentsSeparatedByString:@","]; + else if ([content rangeOfString:@", "].length == 0 && [content rangeOfString:@" "].length > 0) + array = [content componentsSeparatedByString:@" "]; + else + array = [content componentsSeparatedByString:@", "]; + [_documentAttrs setObject:array forKey:NSKeywordsDocumentAttribute]; + } + } else if (NSOrderedSame == [@"Author" compare:name options:NSCaseInsensitiveSearch]) + key = NSAuthorDocumentAttribute; + else if (NSOrderedSame == [@"LastAuthor" compare:name options:NSCaseInsensitiveSearch]) + key = NSEditorDocumentAttribute; + else if (NSOrderedSame == [@"Company" compare:name options:NSCaseInsensitiveSearch]) + key = NSCompanyDocumentAttribute; + else if (NSOrderedSame == [@"Copyright" compare:name options:NSCaseInsensitiveSearch]) + key = NSCopyrightDocumentAttribute; + else if (NSOrderedSame == [@"Subject" compare:name options:NSCaseInsensitiveSearch]) + key = NSSubjectDocumentAttribute; + else if (NSOrderedSame == [@"Description" compare:name options:NSCaseInsensitiveSearch] || NSOrderedSame == [@"Comment" compare:name options:NSCaseInsensitiveSearch]) + key = NSCommentDocumentAttribute; + else if (NSOrderedSame == [@"CreationTime" compare:name options:NSCaseInsensitiveSearch]) { + if (content && [content length] > 0) { + NSDate *date = _dateForString(content); + if (date) + [_documentAttrs setObject:date forKey:NSCreationTimeDocumentAttribute]; + } + } else if (NSOrderedSame == [@"ModificationTime" compare:name options:NSCaseInsensitiveSearch]) { + if (content && [content length] > 0) { + NSDate *date = _dateForString(content); + if (date) + [_documentAttrs setObject:date forKey:NSModificationTimeDocumentAttribute]; + } + } +#if PLATFORM(IOS_FAMILY) + else if (NSOrderedSame == [@"DisplayName" compare:name options:NSCaseInsensitiveSearch] || NSOrderedSame == [@"IndexTitle" compare:name options:NSCaseInsensitiveSearch]) + key = NSDisplayNameDocumentAttribute; + else if (NSOrderedSame == [@"robots" compare:name options:NSCaseInsensitiveSearch]) { + if ([content rangeOfString:@"noindex" options:NSCaseInsensitiveSearch].length > 0) + [_documentAttrs setObject:[NSNumber numberWithInteger:1] forKey:NSNoIndexDocumentAttribute]; + } +#endif + if (key && content && [content length] > 0) + [_documentAttrs setObject:content forKey:key]; +} + +void HTMLConverter::_processHeadElement(Element& element) +{ + // FIXME: Should gather data from other sources e.g. Word, but for that we would need to be able to get comments from DOM + + for (HTMLMetaElement* child = Traversal::firstChild(element); child; child = Traversal::nextSibling(*child)) { + RetainPtr name = child->name().createNSString(); + RetainPtr content = child->content().createNSString(); + if (name && content) + _processMetaElementWithName(name.get(), content.get()); + } +} + +void HTMLConverter::_enterBlockquote() +{ + _topPresentationIntent = [NSPresentationIntent blockQuoteIntentWithIdentity:++_topPresentationIntentIdentity nestedInsideIntent:_topPresentationIntent.get()]; +} + +void HTMLConverter::_exitBlockquote() +{ + if (_topPresentationIntent) + _topPresentationIntent = [_topPresentationIntent parentIntent]; +} + +BOOL HTMLConverter::_enterElement(Element& element, BOOL embedded) +{ + String displayValue = _caches->propertyValueForNode(element, CSSPropertyDisplay); + if (element.hasTagName(blockquoteTag)) + _enterBlockquote(); + + if (element.hasTagName(headTag) && !embedded) + _processHeadElement(element); + else if ((!m_ignoreUserSelectNoneContent || !m_userSelectNoneStateCache.nodeOnlyContainsUserSelectNone(element)) && (!displayValue.length() || !(displayValue == noneAtom() || displayValue == "table-column"_s || displayValue == "table-column-group"_s))) { + if (_caches->isBlockElement(element) && !element.hasTagName(brTag) && !(displayValue == "table-cell"_s && ![_textTables count]) + && !([_textLists count] > 0 && displayValue == "block"_s && !element.hasTagName(liTag) && !element.hasTagName(ulTag) && !element.hasTagName(olTag))) + _newParagraphForElement(element, element.tagName().createNSString().get(), NO, YES); + return YES; + } + return NO; +} + +void HTMLConverter::_addLinkForElement(Element& element, NSRange range) +{ +#if ENABLE(DATA_DETECTION) + if (DataDetection::isDataDetectorElement(element)) + return; +#endif + + RetainPtr urlString = element.getAttribute(hrefAttr).createNSString(); + RetainPtr strippedString = [urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if (urlString && [urlString length] > 0 && strippedString && [strippedString length] > 0 && ![strippedString hasPrefix:@"#"]) { + RetainPtr url = element.document().completeURL(urlString.get()).createNSURL(); + if (!url) + url = element.document().completeURL(strippedString.get()).createNSURL(); + if (!url) + url = [NSURL _web_URLWithString:strippedString.get() relativeToURL:nil]; + [_attrStr addAttribute:NSLinkAttributeName value:url ? (id)url.get() : (id)urlString.get() range:range]; + } +} + +void HTMLConverter::_addTableForElement(Element *tableElement) +{ + RetainPtr table = adoptNS([(NSTextTable *)[PlatformNSTextTable alloc] init]); + CGFloat cellSpacingVal = 1; + CGFloat cellPaddingVal = 1; + [table setNumberOfColumns:1]; + [table setLayoutAlgorithm:NSTextTableAutomaticLayoutAlgorithm]; + [table setCollapsesBorders:NO]; + [table setHidesEmptyCells:NO]; + + if (tableElement) { + ASSERT(tableElement); + Element& coreTableElement = *tableElement; + + RetainPtr cellSpacing = coreTableElement.getAttribute(cellspacingAttr).createNSString(); + if (cellSpacing && [cellSpacing length] > 0 && ![cellSpacing hasSuffix:@"%"]) + cellSpacingVal = [cellSpacing floatValue]; + RetainPtr cellPadding = coreTableElement.getAttribute(cellpaddingAttr).createNSString(); + if (cellPadding && [cellPadding length] > 0 && ![cellPadding hasSuffix:@"%"]) + cellPaddingVal = [cellPadding floatValue]; + + _fillInBlock(table.get(), coreTableElement, nil, 0, 0, YES); + + if (_caches->propertyValueForNode(coreTableElement, CSSPropertyBorderCollapse) == "collapse"_s) { + [table setCollapsesBorders:YES]; + cellSpacingVal = 0; + } + if (_caches->propertyValueForNode(coreTableElement, CSSPropertyEmptyCells) == "hide"_s) + [table setHidesEmptyCells:YES]; + if (_caches->propertyValueForNode(coreTableElement, CSSPropertyTableLayout) == "fixed"_s) + [table setLayoutAlgorithm:NSTextTableFixedLayoutAlgorithm]; + } + + [_textTables addObject:table.get()]; + [_textTableSpacings addObject:@(cellSpacingVal)]; + [_textTablePaddings addObject:@(cellPaddingVal)]; + [_textTableRows addObject:[NSNumber numberWithInteger:0]]; + [_textTableRowArrays addObject:[NSMutableArray array]]; +} + +void HTMLConverter::_addTableCellForElement(Element* element) +{ + NSTextTable *table = [_textTables lastObject]; + NSInteger rowNumber = [[_textTableRows lastObject] integerValue]; + NSInteger columnNumber = 0; + NSInteger rowSpan = 1; + NSInteger colSpan = 1; + NSMutableArray *rowArray = [_textTableRowArrays lastObject]; + NSUInteger count = [rowArray count]; + PlatformColor *color = ([_textTableRowBackgroundColors count] > 0) ? [_textTableRowBackgroundColors lastObject] : nil; + NSTextTableBlock *previousBlock; + CGFloat cellSpacingVal = [[_textTableSpacings lastObject] floatValue]; + if ([color isEqual:[PlatformColorClass clearColor]]) color = nil; + for (NSUInteger i = 0; i < count; i++) { + previousBlock = [rowArray objectAtIndex:i]; + if (columnNumber >= [previousBlock startingColumn] && columnNumber < [previousBlock startingColumn] + [previousBlock columnSpan]) + columnNumber = [previousBlock startingColumn] + [previousBlock columnSpan]; + } + + RetainPtr block; + + if (element) { + if (RefPtr tableCellElement = dynamicDowncast(*element)) { + rowSpan = tableCellElement->rowSpan(); + if (rowSpan < 1) + rowSpan = 1; + colSpan = tableCellElement->colSpan(); + if (colSpan < 1) + colSpan = 1; + } + + block = adoptNS([[PlatformNSTextTableBlock alloc] initWithTable:table startingRow:rowNumber rowSpan:rowSpan startingColumn:columnNumber columnSpan:colSpan]); + + String verticalAlign = _caches->propertyValueForNode(*element, CSSPropertyVerticalAlign); + + _fillInBlock(block.get(), *element, color, cellSpacingVal / 2, 0, NO); + if (verticalAlign == "middle"_s) + [block setVerticalAlignment:NSTextBlockMiddleAlignment]; + else if (verticalAlign == "bottom"_s) + [block setVerticalAlignment:NSTextBlockBottomAlignment]; + else if (verticalAlign == "baseline"_s) + [block setVerticalAlignment:NSTextBlockBaselineAlignment]; + else if (verticalAlign == "top"_s) + [block setVerticalAlignment:NSTextBlockTopAlignment]; + } else { + block = adoptNS([[PlatformNSTextTableBlock alloc] initWithTable:table startingRow:rowNumber rowSpan:rowSpan startingColumn:columnNumber columnSpan:colSpan]); + } + + [_textBlocks addObject:block.get()]; + [rowArray addObject:block.get()]; + [rowArray sortUsingFunction:_colCompare context:NULL]; +} + +BOOL HTMLConverter::_processElement(Element& element, NSInteger depth) +{ + BOOL retval = YES; + BOOL isBlockLevel = _caches->isBlockElement(element); + String displayValue = _caches->propertyValueForNode(element, CSSPropertyDisplay); + if (isBlockLevel) + [_writingDirectionArray removeAllObjects]; + else { + String bidi = _caches->propertyValueForNode(element, CSSPropertyUnicodeBidi); + if (bidi == "embed"_s) { + NSUInteger val = NSWritingDirectionEmbedding; + if (_caches->propertyValueForNode(element, CSSPropertyDirection) == "rtl"_s) + val |= NSWritingDirectionRightToLeft; + [_writingDirectionArray addObject:[NSNumber numberWithUnsignedInteger:val]]; + } else if (bidi == "bidi-override"_s) { + NSUInteger val = NSWritingDirectionOverride; + if (_caches->propertyValueForNode(element, CSSPropertyDirection) == "rtl"_s) + val |= NSWritingDirectionRightToLeft; + [_writingDirectionArray addObject:[NSNumber numberWithUnsignedInteger:val]]; + } + } + if (displayValue == "table"_s || (![_textTables count] && displayValue == "table-row-group"_s)) { + Element* tableElement = &element; + if (displayValue == "table-row-group"_s) { + // If we are starting in medias res, the first thing we see may be the tbody, so go up to the table + tableElement = _blockLevelElementForNode(element.parentInComposedTree()); + if (!tableElement || _caches->propertyValueForNode(*tableElement, CSSPropertyDisplay) != "table"_s) + tableElement = &element; + } + while ([_textTables count] > [_textBlocks count]) + _addTableCellForElement(nil); + _addTableForElement(tableElement); + } else if (displayValue == "table-footer-group"_s && [_textTables count] > 0) { + m_textTableFooters.add((__bridge CFTypeRef)[_textTables lastObject], &element); + retval = NO; + } else if (displayValue == "table-row"_s && [_textTables count] > 0) { + auto color = _colorForElement(element, CSSPropertyBackgroundColor); + if (!color) + color = (PlatformColor *)[PlatformColorClass clearColor]; + [_textTableRowBackgroundColors addObject:color.get()]; + } else if (displayValue == "table-cell"_s) { + while ([_textTables count] < [_textBlocks count] + 1) + _addTableForElement(nil); + _addTableCellForElement(&element); +#if ENABLE(ATTACHMENT_ELEMENT) + } else if (RefPtr attachment = dynamicDowncast(element)) { + if (attachment->file()) { + RetainPtr url = [NSURL fileURLWithPath:attachment->file()->path().createNSString().get()]; + if (url) + _addAttachmentForElement(element, url.get(), isBlockLevel, NO); + } + retval = NO; +#endif + } else if (RefPtr imageElement = dynamicDowncast(element)) { +#if ENABLE(MULTI_REPRESENTATION_HEIC) + if (imageElement->isMultiRepresentationHEIC()) + retval = !_addMultiRepresentationHEICAttachmentForImageElement(*imageElement); +#endif + RetainPtr urlString = element.imageSourceURL().createNSString(); + if (retval && urlString && [urlString length] > 0) { + RetainPtr url = element.document().completeURL(urlString.get()).createNSURL(); + if (!url) + url = [NSURL _web_URLWithString:[urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:nil]; +#if PLATFORM(IOS_FAMILY) + BOOL usePlaceholderImage = NO; +#else + BOOL usePlaceholderImage = YES; +#endif + if (url) + _addAttachmentForElement(element, url.get(), isBlockLevel, usePlaceholderImage); + } + retval = NO; + } else if (element.hasTagName(objectTag)) { + RetainPtr baseString = element.getAttribute(codebaseAttr).createNSString(); + RetainPtr urlString = element.getAttribute(dataAttr).createNSString(); + RetainPtr declareString = element.getAttribute(declareAttr).createNSString(); + if (urlString && [urlString length] > 0 && ![@"true" isEqualToString:declareString.get()]) { + RetainPtr baseURL; + RetainPtr url; + if (baseString && [baseString length] > 0) { + baseURL = element.document().completeURL(baseString.get()).createNSURL(); + if (!baseURL) + baseURL = [NSURL _web_URLWithString:[baseString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:nil]; + } + if (baseURL) + url = [NSURL _web_URLWithString:[urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:baseURL.get()]; + if (!url) + url = element.document().completeURL(urlString.get()).createNSURL(); + if (!url) + url = [NSURL _web_URLWithString:[urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:nil]; + if (url) + retval = !_addAttachmentForElement(element, url.get(), isBlockLevel, NO); + } + } else if (auto* frameElement = dynamicDowncast(element)) { + if (RefPtr contentDocument = frameElement->contentDocument()) { + _traverseNode(*contentDocument, depth + 1, true /* embedded */); + retval = NO; + } + } else if (element.hasTagName(brTag)) { + Element* blockElement = _blockLevelElementForNode(element.parentInComposedTree()); + RetainPtr breakClass = element.getAttribute(classAttr).createNSString(); + RetainPtr blockTag = blockElement ? blockElement->tagName().createNSString() : nil; + BOOL isExtraBreak = [AppleInterchangeNewline.createNSString() isEqualToString:breakClass.get()]; + BOOL blockElementIsParagraph = ([@"P" isEqualToString:blockTag.get()] || [@"LI" isEqualToString:blockTag.get()] || ([blockTag hasPrefix:@"H"] && 2 == [blockTag length])); + if (isExtraBreak) + _flags.hasTrailingNewline = YES; + else { + if (blockElement && blockElementIsParagraph) + _newLineForElement(element); + else + _newParagraphForElement(element, element.tagName().createNSString().get(), YES, NO); + } + } else if (element.hasTagName(ulTag)) { + TextList textList; + textList.ordered = false; + + if (CheckedPtr renderer = element.renderer()) + textList.styleType = renderer->style().listStyleType(); + + [_textLists addObject:textList.createTextList().get()]; + } else if (element.hasTagName(olTag)) { + TextList textList; + textList.ordered = true; + + if (CheckedPtr renderer = element.renderer()) + textList.styleType = renderer->style().listStyleType(); + + if (RefPtr olElement = dynamicDowncast(element)) + textList.startingItemNumber = olElement->start(); + else + textList.startingItemNumber = 1; + + [_textLists addObject:textList.createTextList().get()]; + } else if (element.hasTagName(qTag)) { + _addQuoteForElement(element, YES, _quoteLevel++); + } else if (element.hasTagName(inputTag)) { + if (RefPtr inputElement = dynamicDowncast(element)) { + if (inputElement->type() == textAtom()) { + RetainPtr value = inputElement->value()->createNSString(); + if (value && [value length] > 0) + _addValue(value.get(), element); + } + } + } else if (element.hasTagName(textareaTag)) { + if (RefPtr textAreaElement = dynamicDowncast(element)) { + RetainPtr value = textAreaElement->value()->createNSString(); + if (value && [value length] > 0) + _addValue(value.get(), element); + } + retval = NO; + } + return retval; +} + +void HTMLConverter::_addMarkersToList(NSTextList *list, NSRange range) +{ + NSInteger itemNum = [list startingItemNumber]; + NSString *string = [_attrStr string]; + NSString *stringToInsert; + NSDictionary *attrsToInsert = nil; + NSParagraphStyle *paragraphStyle; + NSTextTab *tab = nil; + NSTextTab *tabToRemove; + NSRange paragraphRange; + NSRange styleRange; + NSUInteger textLength = [_attrStr length]; + NSUInteger listIndex; + NSUInteger insertLength; + NSUInteger i; + NSUInteger count; + NSArray *textLists; + CGFloat markerLocation; + CGFloat listLocation; + + if (range.length == 0 || range.location >= textLength) + return; + if (NSMaxRange(range) > textLength) + range.length = textLength - range.location; + paragraphStyle = [_attrStr attribute:NSParagraphStyleAttributeName atIndex:range.location effectiveRange:NULL]; + if (paragraphStyle) { + textLists = [paragraphStyle textLists]; + listIndex = [textLists indexOfObject:list]; + if (textLists && listIndex != NSNotFound) { + for (NSUInteger idx = range.location; idx < NSMaxRange(range);) { + paragraphRange = [string paragraphRangeForRange:NSMakeRange(idx, 0)]; + paragraphStyle = [_attrStr attribute:NSParagraphStyleAttributeName atIndex:idx effectiveRange:&styleRange]; + if ([[paragraphStyle textLists] count] == listIndex + 1) { + stringToInsert = [NSString stringWithFormat:@"\t%@\t", [list markerForItemNumber:itemNum++]]; + insertLength = [stringToInsert length]; + attrsToInsert = [PlatformNSTextList _standardMarkerAttributesForAttributes:[_attrStr attributesAtIndex:paragraphRange.location effectiveRange:NULL]]; + + [_attrStr replaceCharactersInRange:NSMakeRange(paragraphRange.location, 0) withString:stringToInsert]; + [_attrStr setAttributes:attrsToInsert range:NSMakeRange(paragraphRange.location, insertLength)]; + range.length += insertLength; + paragraphRange.length += insertLength; + if (paragraphRange.location < _domRangeStartIndex) + _domRangeStartIndex += insertLength; + + auto newStyle = adoptNS([paragraphStyle mutableCopy]); + listLocation = (listIndex + 1) * 36; + markerLocation = listLocation - 25; + [newStyle setFirstLineHeadIndent:0]; + [newStyle setHeadIndent:listLocation]; + while ((count = [[newStyle tabStops] count]) > 0) { + for (i = 0, tabToRemove = nil; !tabToRemove && i < count; i++) { + tab = [[newStyle tabStops] objectAtIndex:i]; + if ([tab location] <= listLocation) + tabToRemove = tab; + } + if (tabToRemove) + [newStyle removeTabStop:tab]; + else + break; + } + [newStyle addTabStop:adoptNS([[PlatformNSTextTab alloc] initWithType:NSLeftTabStopType location:markerLocation]).get()]; + [newStyle addTabStop:adoptNS([[PlatformNSTextTab alloc] initWithTextAlignment:NSTextAlignmentNatural location:listLocation options:@{ }]).get()]; + [_attrStr addAttribute:NSParagraphStyleAttributeName value:newStyle.get() range:paragraphRange]; + + idx = NSMaxRange(paragraphRange); + } else { + // skip any deeper-nested lists + idx = NSMaxRange(styleRange); + } + } + } + } +} + +void HTMLConverter::_exitElement(Element& element, NSInteger depth, NSUInteger startIndex) +{ + String displayValue = _caches->propertyValueForNode(element, CSSPropertyDisplay); + NSRange range = NSMakeRange(startIndex, [_attrStr length] - startIndex); + if (range.length > 0 && element.hasTagName(aTag)) + _addLinkForElement(element, range); + if (!_flags.reachedEnd && _caches->isBlockElement(element)) { + [_writingDirectionArray removeAllObjects]; + if (displayValue == "table-cell"_s && ![_textBlocks count]) { + _newTabForElement(element); + } else if ([_textLists count] > 0 && displayValue == "block"_s && !element.hasTagName(liTag) && !element.hasTagName(ulTag) && !element.hasTagName(olTag)) { + _newLineForElement(element); + } else { + _newParagraphForElement(element, element.tagName().createNSString().get(), !range.length, YES); + } + } else if ([_writingDirectionArray count] > 0) { + String bidi = _caches->propertyValueForNode(element, CSSPropertyUnicodeBidi); + if (bidi == "embed"_s || bidi == "bidi-override"_s) + [_writingDirectionArray removeLastObject]; + } + range = NSMakeRange(startIndex, [_attrStr length] - startIndex); + if (displayValue == "table"_s && [_textTables count] > 0) { + NSTextTable *key = [_textTables lastObject]; + Element* footer = m_textTableFooters.get((__bridge CFTypeRef)key); + while ([_textTables count] < [_textBlocks count] + 1) + [_textBlocks removeLastObject]; + if (footer) { + _traverseFooterNode(*footer, depth + 1); + m_textTableFooters.remove((__bridge CFTypeRef)key); + } + [_textTables removeLastObject]; + [_textTableSpacings removeLastObject]; + [_textTablePaddings removeLastObject]; + [_textTableRows removeLastObject]; + [_textTableRowArrays removeLastObject]; + } else if (displayValue == "table-row"_s && [_textTables count] > 0) { + NSTextTable *table = [_textTables lastObject]; + NSTextTableBlock *block; + NSMutableArray *rowArray = [_textTableRowArrays lastObject], *previousRowArray; + NSUInteger i, count; + NSInteger numberOfColumns = [table numberOfColumns]; + NSInteger openColumn; + NSInteger rowNumber = [[_textTableRows lastObject] integerValue]; + do { + rowNumber++; + previousRowArray = rowArray; + rowArray = [NSMutableArray array]; + count = [previousRowArray count]; + for (i = 0; i < count; i++) { + block = [previousRowArray objectAtIndex:i]; + if ([block startingColumn] + [block columnSpan] > numberOfColumns) numberOfColumns = [block startingColumn] + [block columnSpan]; + if ([block startingRow] + [block rowSpan] > rowNumber) [rowArray addObject:block]; + } + count = [rowArray count]; + openColumn = 0; + for (i = 0; i < count; i++) { + block = [rowArray objectAtIndex:i]; + if (openColumn >= [block startingColumn] && openColumn < [block startingColumn] + [block columnSpan]) openColumn = [block startingColumn] + [block columnSpan]; + } + } while (openColumn >= numberOfColumns); + if ((NSUInteger)numberOfColumns > [table numberOfColumns]) + [table setNumberOfColumns:numberOfColumns]; + [_textTableRows removeLastObject]; + [_textTableRows addObject:[NSNumber numberWithInteger:rowNumber]]; + [_textTableRowArrays removeLastObject]; + [_textTableRowArrays addObject:rowArray]; + if ([_textTableRowBackgroundColors count] > 0) + [_textTableRowBackgroundColors removeLastObject]; + } else if (displayValue == "table-cell"_s && [_textBlocks count] > 0) { + while ([_textTables count] > [_textBlocks count]) { + [_textTables removeLastObject]; + [_textTableSpacings removeLastObject]; + [_textTablePaddings removeLastObject]; + [_textTableRows removeLastObject]; + [_textTableRowArrays removeLastObject]; + } + [_textBlocks removeLastObject]; + } else if ((element.hasTagName(ulTag) || element.hasTagName(olTag)) && [_textLists count] > 0) { + NSTextList *list = [_textLists lastObject]; + _addMarkersToList(list, range); + [_textLists removeLastObject]; + } else if (element.hasTagName(qTag)) { + _addQuoteForElement(element, NO, --_quoteLevel); + } else if (element.hasTagName(spanTag)) { + RetainPtr className = element.getAttribute(classAttr).createNSString(); + NSMutableString *mutableString; + NSUInteger i, count = 0; + unichar c; + if ([@"Apple-converted-space" isEqualToString:className.get()]) { + mutableString = [_attrStr mutableString]; + for (i = range.location; i < NSMaxRange(range); i++) { + c = [mutableString characterAtIndex:i]; + if (0xa0 == c) + [mutableString replaceCharactersInRange:NSMakeRange(i, 1) withString:@" "]; + } + } else if ([@"Apple-converted-tab" isEqualToString:className.get()]) { + mutableString = [_attrStr mutableString]; + for (i = range.location; i < NSMaxRange(range); i++) { + NSRange rangeToReplace = NSMakeRange(NSNotFound, 0); + c = [mutableString characterAtIndex:i]; + if (' ' == c || 0xa0 == c) { + count++; + if (count >= 4 || i + 1 >= NSMaxRange(range)) + rangeToReplace = NSMakeRange(i + 1 - count, count); + } else { + if (count > 0) + rangeToReplace = NSMakeRange(i - count, count); + } + if (rangeToReplace.length > 0) { + [mutableString replaceCharactersInRange:rangeToReplace withString:@"\t"]; + range.length -= (rangeToReplace.length - 1); + i -= (rangeToReplace.length - 1); + if (NSMaxRange(rangeToReplace) <= _domRangeStartIndex) { + _domRangeStartIndex -= (rangeToReplace.length - 1); + } else if (rangeToReplace.location < _domRangeStartIndex) { + _domRangeStartIndex = rangeToReplace.location; + } + count = 0; + } + } + } + } + + if (element.hasTagName(blockquoteTag)) + _exitBlockquote(); +} + +void HTMLConverter::_processText(Text& text) +{ + if (m_ignoreUserSelectNoneContent && m_userSelectNoneStateCache.nodeOnlyContainsUserSelectNone(text)) + return; + NSUInteger textLength = [_attrStr length]; + unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n'; + BOOL suppressLeadingSpace = ((_flags.isSoft && lastChar == ' ') || lastChar == '\n' || lastChar == '\r' || lastChar == '\t' || lastChar == NSParagraphSeparatorCharacter || lastChar == NSLineSeparatorCharacter || lastChar == NSFormFeedCharacter || lastChar == WebNextLineCharacter); + NSRange rangeToReplace = NSMakeRange(textLength, 0); + + String originalString = text.data(); + unsigned startOffset = 0; + unsigned endOffset = originalString.length(); + if (&text == m_start.containerNode()) { + startOffset = m_start.offsetInContainerNode(); + _domRangeStartIndex = [_attrStr length]; + _flags.reachedStart = YES; + } + if (&text == m_end.containerNode()) { + endOffset = m_end.offsetInContainerNode(); + _flags.reachedEnd = YES; + } + if ((startOffset > 0 || endOffset < originalString.length()) && endOffset >= startOffset) + originalString = originalString.substring(startOffset, endOffset - startOffset); + String outputString = originalString; + + // FIXME: Use RenderText's content instead. + bool wasSpace = false; + if (_caches->propertyValueForNode(text, CSSPropertyWhiteSpace).startsWith("pre"_s)) { + if (textLength && originalString.length() && _flags.isSoft) { + unichar c = originalString.characterAt(0); + if (c == '\n' || c == '\r' || c == NSParagraphSeparatorCharacter || c == NSLineSeparatorCharacter || c == NSFormFeedCharacter || c == WebNextLineCharacter) + rangeToReplace = NSMakeRange(textLength - 1, 1); + } + } else { + unsigned count = originalString.length(); + bool wasLeading = true; + StringBuilder builder; + Latin1Character noBreakSpaceRepresentation = 0; + for (unsigned i = 0; i < count; i++) { + char16_t c = originalString.characterAt(i); + bool isWhitespace = c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == 0xc || c == 0x200b; + if (isWhitespace) + wasSpace = (!wasLeading || !suppressLeadingSpace); + else { + if (wasSpace) + builder.append(' '); + if (c != noBreakSpace) + builder.append(c); + else { + if (!noBreakSpaceRepresentation) + noBreakSpaceRepresentation = _caches->propertyValueForNode(text, CSSPropertyWebkitNbspMode) == "space"_s ? ' ' : noBreakSpace; + builder.append(noBreakSpaceRepresentation); + } + wasSpace = false; + wasLeading = false; + } + } + if (wasSpace) + builder.append(' '); + outputString = builder.toString(); + } + + if (outputString.length()) { + String textTransform = _caches->propertyValueForNode(text, CSSPropertyTextTransform); + if (textTransform == "capitalize"_s) + outputString = capitalize(outputString); // FIXME: Needs to take locale into account to work correctly. + else if (textTransform == "uppercase"_s) + outputString = outputString.convertToUppercaseWithoutLocale(); // FIXME: Needs locale to work correctly. + else if (textTransform == "lowercase"_s) + outputString = outputString.convertToLowercaseWithoutLocale(); // FIXME: Needs locale to work correctly. + + [_attrStr replaceCharactersInRange:rangeToReplace withString:outputString.createNSString().get()]; + rangeToReplace.length = outputString.length(); + if (rangeToReplace.length) + [_attrStr setAttributes:aggregatedAttributesForAncestors(text) range:rangeToReplace]; + _flags.isSoft = wasSpace; + } +} + +void HTMLConverter::_traverseNode(Node& node, unsigned depth, bool embedded) +{ + if (_flags.reachedEnd) + return; + if (!_flags.reachedStart && !_caches->isAncestorsOfStartToBeConverted(node)) + return; + + unsigned startOffset = 0; + unsigned endOffset = UINT_MAX; + bool isStart = false; + bool isEnd = false; + if (&node == m_start.containerNode()) { + startOffset = m_start.computeOffsetInContainerNode(); + isStart = true; + _flags.reachedStart = YES; + } + if (&node == m_end.containerNode()) { + endOffset = m_end.computeOffsetInContainerNode(); + isEnd = true; + } + + if (node.isDocumentNode() || node.isDocumentFragment()) { + Node* child = node.firstChild(); + ASSERT(child == firstChildInComposedTreeIgnoringUserAgentShadow(node)); + for (NSUInteger i = 0; child; i++) { + if (isStart && i == startOffset) + _domRangeStartIndex = [_attrStr length]; + if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i)) + _traverseNode(*child, depth + 1, embedded); + if (isEnd && i + 1 >= endOffset) + _flags.reachedEnd = YES; + if (_flags.reachedEnd) + break; + ASSERT(child->nextSibling() == nextSiblingInComposedTreeIgnoringUserAgentShadow(*child)); + child = child->nextSibling(); + } + } else if (RefPtr element = dynamicDowncast(node)) { + if (_enterElement(*element, embedded)) { + NSUInteger startIndex = [_attrStr length]; + if (_processElement(*element, depth)) { + if (auto* shadowRoot = shadowRootIgnoringUserAgentShadow(*element)) // Traverse through shadow root to detect start and end. + _traverseNode(*shadowRoot, depth + 1, embedded); + else { + auto* child = firstChildInComposedTreeIgnoringUserAgentShadow(node); + for (NSUInteger i = 0; child; i++) { + if (isStart && i == startOffset) + _domRangeStartIndex = [_attrStr length]; + if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i)) + _traverseNode(*child, depth + 1, embedded); + if (isEnd && i + 1 >= endOffset) + _flags.reachedEnd = YES; + if (_flags.reachedEnd) + break; + child = nextSiblingInComposedTreeIgnoringUserAgentShadow(*child); + } + } + _exitElement(*element, depth, std::min(startIndex, [_attrStr length])); + } + } + } else if (RefPtr text = dynamicDowncast(node)) + _processText(*text); + + if (isEnd) + _flags.reachedEnd = YES; +} + +void HTMLConverter::_traverseFooterNode(Element& element, unsigned depth) +{ + if (_flags.reachedEnd) + return; + if (!_flags.reachedStart && !_caches->isAncestorsOfStartToBeConverted(element)) + return; + + unsigned startOffset = 0; + unsigned endOffset = UINT_MAX; + bool isStart = false; + bool isEnd = false; + if (&element == m_start.containerNode()) { + startOffset = m_start.computeOffsetInContainerNode(); + isStart = true; + _flags.reachedStart = YES; + } + if (&element == m_end.containerNode()) { + endOffset = m_end.computeOffsetInContainerNode(); + isEnd = true; + } + + if (_enterElement(element, YES)) { + NSUInteger startIndex = [_attrStr length]; + if (_processElement(element, depth)) { + auto* child = firstChildInComposedTreeIgnoringUserAgentShadow(element); + for (NSUInteger i = 0; child; i++) { + if (isStart && i == startOffset) + _domRangeStartIndex = [_attrStr length]; + if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i)) + _traverseNode(*child, depth + 1, true /* embedded */); + if (isEnd && i + 1 >= endOffset) + _flags.reachedEnd = YES; + if (_flags.reachedEnd) + break; + child = nextSiblingInComposedTreeIgnoringUserAgentShadow(*child); + } + _exitElement(element, depth, startIndex); + } + } + if (isEnd) + _flags.reachedEnd = YES; +} + +void HTMLConverter::_adjustTrailingNewline() +{ + NSUInteger textLength = [_attrStr length]; + unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : 0; + BOOL alreadyHasTrailingNewline = (lastChar == '\n' || lastChar == '\r' || lastChar == NSParagraphSeparatorCharacter || lastChar == NSLineSeparatorCharacter || lastChar == WebNextLineCharacter); + if (_flags.hasTrailingNewline && !alreadyHasTrailingNewline) + [_attrStr replaceCharactersInRange:NSMakeRange(textLength, 0) withString:@"\n"]; +} + +Node* HTMLConverterCaches::cacheAncestorsOfStartToBeConverted(const Position& start, const Position& end) +{ + auto commonAncestor = commonInclusiveAncestor(start, end); + Node* ancestor = start.containerNode(); + + while (ancestor) { + m_ancestorsUnderCommonAncestor.add(*ancestor); + if (ancestor == commonAncestor) + break; + ancestor = ancestor->parentInComposedTree(); + } + + return commonAncestor; +} + +namespace WebCore { + +// This function supports more HTML features than the editing variant below, such as tables. +AttributedString attributedString(const SimpleRange& range, IgnoreUserSelectNone treatment) +{ + return HTMLConverter { range, treatment }.convert(); +} + +} diff --git a/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm b/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm index ed7711e8216a4..6bceb5fcabd04 100644 --- a/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm +++ b/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm @@ -383,7 +383,7 @@ static void replaceRichContentWithAttachments(LocalFrame& frame, DocumentFragmen // See `HTMLConverter.mm` for more details. if (info.fileName.startsWith(WebContentReader::placeholderAttachmentFilenamePrefix)) { RefPtr document = frame.document(); - if (RefPtr existingAttachment = document->attachmentForIdentifier({ info.data->span() })) { + if (RefPtr existingAttachment = document->attachmentForIdentifier({ byteCast(info.data->span()) })) { parent->replaceChild(*existingAttachment.get(), WTFMove(originalElement)); continue; } diff --git a/Source/WebCore/fileapi/FileReaderLoader.cpp b/Source/WebCore/fileapi/FileReaderLoader.cpp index 29b2d8998d207..2aba718e95c32 100644 --- a/Source/WebCore/fileapi/FileReaderLoader.cpp +++ b/Source/WebCore/fileapi/FileReaderLoader.cpp @@ -327,7 +327,7 @@ String FileReaderLoader::stringResult() // No conversion is needed. break; case ReadAsBinaryString: - m_stringResult = m_rawData->span().first(m_bytesLoaded); + m_stringResult = byteCast(m_rawData->span().first(m_bytesLoaded)); break; case ReadAsText: convertToText(); diff --git a/Source/WebCore/html/FTPDirectoryDocument.cpp b/Source/WebCore/html/FTPDirectoryDocument.cpp index 8a3d263655581..0e890482a74d5 100644 --- a/Source/WebCore/html/FTPDirectoryDocument.cpp +++ b/Source/WebCore/html/FTPDirectoryDocument.cpp @@ -295,7 +295,7 @@ bool FTPDirectoryDocumentParser::loadDocumentTemplate() return false; } - HTMLDocumentParser::insert(String(templateDocumentData.get()->span())); + HTMLDocumentParser::insert(String(byteCast(templateDocumentData.get()->span()))); Ref document = *this->document(); diff --git a/Source/WebCore/html/MediaFragmentURIParser.cpp b/Source/WebCore/html/MediaFragmentURIParser.cpp index a17af4bd0bc7a..fd5aa7462e0f7 100644 --- a/Source/WebCore/html/MediaFragmentURIParser.cpp +++ b/Source/WebCore/html/MediaFragmentURIParser.cpp @@ -45,7 +45,7 @@ constexpr int secondsPerHour = 3600; constexpr int secondsPerMinute = 60; constexpr unsigned nptIdentifierLength = 4; // "npt:" -static String collectDigits(std::span input, unsigned& position) +static String collectDigits(std::span input, unsigned& position) { StringBuilder digits; @@ -56,7 +56,7 @@ static String collectDigits(std::span input, unsigned& position) return digits.toString(); } -static StringView collectFraction(std::span input, unsigned& position) +static StringView collectFraction(std::span input, unsigned& position) { // http://www.ietf.org/rfc/rfc2326.txt // [ "." *DIGIT ] @@ -192,7 +192,7 @@ void MediaFragmentURIParser::parseTimeFragment() m_fragments.clear(); } -bool MediaFragmentURIParser::parseNPTFragment(std::span timeString, MediaTime& startTime, MediaTime& endTime) +bool MediaFragmentURIParser::parseNPTFragment(std::span timeString, MediaTime& startTime, MediaTime& endTime) { unsigned offset = 0; if (timeString.size() >= nptIdentifierLength && timeString[0] == 'n' && timeString[1] == 'p' && timeString[2] == 't' && timeString[3] == ':') @@ -231,7 +231,7 @@ bool MediaFragmentURIParser::parseNPTFragment(std::span timeString, return true; } -bool MediaFragmentURIParser::parseNPTTime(std::span timeString, unsigned& offset, MediaTime& time) +bool MediaFragmentURIParser::parseNPTTime(std::span timeString, unsigned& offset, MediaTime& time) { enum Mode { minutes, hours }; Mode mode = minutes; diff --git a/Source/WebCore/html/MediaFragmentURIParser.h b/Source/WebCore/html/MediaFragmentURIParser.h index 8d44aed23fe48..13571305151b1 100644 --- a/Source/WebCore/html/MediaFragmentURIParser.h +++ b/Source/WebCore/html/MediaFragmentURIParser.h @@ -47,8 +47,8 @@ class MediaFragmentURIParser final { enum TimeFormat { None, Invalid, NormalPlayTime, SMPTETimeCode, WallClockTimeCode }; void parseTimeFragment(); - bool parseNPTFragment(std::span, MediaTime& startTime, MediaTime& endTime); - bool parseNPTTime(std::span, unsigned& offset, MediaTime&); + bool parseNPTFragment(std::span, MediaTime& startTime, MediaTime& endTime); + bool parseNPTTime(std::span, unsigned& offset, MediaTime&); URL m_url; TimeFormat m_timeFormat; diff --git a/Source/WebCore/html/parser/HTMLDocumentParserFastPath.cpp b/Source/WebCore/html/parser/HTMLDocumentParserFastPath.cpp index ea7fa367d9644..ad16efe035eab 100644 --- a/Source/WebCore/html/parser/HTMLDocumentParserFastPath.cpp +++ b/Source/WebCore/html/parser/HTMLDocumentParserFastPath.cpp @@ -192,7 +192,7 @@ template static bool insertInUniquedSortedVector(Vector& vector, template class HTMLFastPathParser { using CharacterSpan = std::span; - static_assert(std::is_same_v || std::is_same_v); + static_assert(std::is_same_v || std::is_same_v); public: HTMLFastPathParser(CharacterSpan source, Document& document, ContainerNode& destinationParent) @@ -473,7 +473,7 @@ class HTMLFastPathParser { // We first try to scan text as an unmodified subsequence of the input. // However, if there are escape sequences, we have to copy the text to a // separate buffer and we might go outside of `Char` range if we are in an - // `LChar` parser. + // `Latin1Character` parser. String scanText() { auto* start = m_parsingBuffer.position(); diff --git a/Source/WebCore/html/parser/HTMLEntityParser.cpp b/Source/WebCore/html/parser/HTMLEntityParser.cpp index f686432072cfa..f030b8835a66e 100644 --- a/Source/WebCore/html/parser/HTMLEntityParser.cpp +++ b/Source/WebCore/html/parser/HTMLEntityParser.cpp @@ -123,7 +123,7 @@ template class StringParsingBufferSource { explicit StringParsingBufferSource(StringParsingBuffer&); static bool isEmpty() { return false; } - UChar currentCharacter() const { return m_source.atEnd() ? 0 : *m_source; } + char16_t currentCharacter() const { return m_source.atEnd() ? 0 : char16_t { *m_source }; } void advance() { m_source.advance(); } void pushEverythingBack() { m_source.setPosition(m_startPosition); } void pushBackButKeep(unsigned keepCount) { m_source.setPosition(m_startPosition + keepCount); } @@ -281,9 +281,9 @@ DecodedHTMLEntity consumeHTMLEntity(SegmentedString& source, UChar additionalAll return consumeHTMLEntity(SegmentedStringSource { source }, additionalAllowedCharacter); } -DecodedHTMLEntity consumeHTMLEntity(StringParsingBuffer& source) +DecodedHTMLEntity consumeHTMLEntity(StringParsingBuffer& source) { - return consumeHTMLEntity(StringParsingBufferSource { source }, 0); + return consumeHTMLEntity(StringParsingBufferSource { source }, 0); } DecodedHTMLEntity consumeHTMLEntity(StringParsingBuffer& source) diff --git a/Source/WebCore/html/parser/HTMLEntityParser.h b/Source/WebCore/html/parser/HTMLEntityParser.h index 7063190a5cfeb..2e84673171c40 100644 --- a/Source/WebCore/html/parser/HTMLEntityParser.h +++ b/Source/WebCore/html/parser/HTMLEntityParser.h @@ -30,7 +30,7 @@ #include #include #include -#include +#include namespace WebCore { @@ -41,8 +41,8 @@ class SegmentedString; DecodedHTMLEntity consumeHTMLEntity(SegmentedString&, UChar additionalAllowedCharacter = 0); // This function assumes the source is complete, and does not expect a null character. -DecodedHTMLEntity consumeHTMLEntity(StringParsingBuffer&); -DecodedHTMLEntity consumeHTMLEntity(StringParsingBuffer&); +DecodedHTMLEntity consumeHTMLEntity(StringParsingBuffer&); +DecodedHTMLEntity consumeHTMLEntity(StringParsingBuffer&); // This function does not check for "not enough characters" at all. DecodedHTMLEntity decodeNamedHTMLEntityForXMLParser(const char*); diff --git a/Source/WebCore/html/parser/HTMLNameCache.h b/Source/WebCore/html/parser/HTMLNameCache.h index 2946cf5982344..55794d51a3654 100644 --- a/Source/WebCore/html/parser/HTMLNameCache.h +++ b/Source/WebCore/html/parser/HTMLNameCache.h @@ -39,7 +39,7 @@ class HTMLNameCache { return makeQualifiedName(string); } - ALWAYS_INLINE static QualifiedName makeAttributeQualifiedName(std::span string) + ALWAYS_INLINE static QualifiedName makeAttributeQualifiedName(std::span string) { return makeQualifiedName(string); } @@ -49,7 +49,7 @@ class HTMLNameCache { return makeAtomString(string); } - ALWAYS_INLINE static AtomString makeAttributeValue(std::span string) + ALWAYS_INLINE static AtomString makeAttributeValue(std::span string) { return makeAtomString(string); } diff --git a/Source/WebCore/html/parser/HTMLParserIdioms.h b/Source/WebCore/html/parser/HTMLParserIdioms.h index 0a95d9a79d99d..9b34a4d21c03b 100644 --- a/Source/WebCore/html/parser/HTMLParserIdioms.h +++ b/Source/WebCore/html/parser/HTMLParserIdioms.h @@ -102,8 +102,8 @@ inline bool isHTMLLineBreak(UChar character) ALWAYS_INLINE bool containsHTMLLineBreak(StringView view) { if (view.is8Bit()) - return charactersContain(view.span8()); - return charactersContain(view.span16()); + return charactersContain(view.span8()); + return charactersContain(view.span16()); } template inline bool isComma(CharacterType character) diff --git a/Source/WebCore/html/parser/HTMLSrcsetParser.cpp b/Source/WebCore/html/parser/HTMLSrcsetParser.cpp index b7e09f6f065e5..827244b08cc95 100644 --- a/Source/WebCore/html/parser/HTMLSrcsetParser.cpp +++ b/Source/WebCore/html/parser/HTMLSrcsetParser.cpp @@ -210,7 +210,7 @@ Vector parseImageCandidatesFromSrcsetAttribute(StringView attrib { // FIXME: We should consider replacing the direct pointers in the parsing process with StringView and positions. if (attribute.is8Bit()) - return parseImageCandidatesFromSrcsetAttribute(attribute.span8()); + return parseImageCandidatesFromSrcsetAttribute(attribute.span8()); else return parseImageCandidatesFromSrcsetAttribute(attribute.span16()); } diff --git a/Source/WebCore/html/parser/HTMLToken.h b/Source/WebCore/html/parser/HTMLToken.h index 83967aede180d..e53d14fbed68b 100644 --- a/Source/WebCore/html/parser/HTMLToken.h +++ b/Source/WebCore/html/parser/HTMLToken.h @@ -97,10 +97,10 @@ class HTMLToken { bool selfClosing() const; const AttributeList& attributes() const; - void beginStartTag(LChar); + void beginStartTag(Latin1Character); - void beginEndTag(LChar); - void beginEndTag(const Vector&); + void beginEndTag(Latin1Character); + void beginEndTag(const Vector&); void beginAttribute(); void appendToAttributeName(UChar); @@ -120,9 +120,9 @@ class HTMLToken { const DataVector& characters() const; bool charactersIsAll8BitData() const; - void appendToCharacter(LChar); - void appendToCharacter(UChar); - void appendToCharacter(const Vector&); + void appendToCharacter(Latin1Character); + void appendToCharacter(char16_t); + void appendToCharacter(const Vector&); template void appendToCharacter(std::span); // Comment. @@ -251,7 +251,7 @@ inline void HTMLToken::setSelfClosing() m_selfClosing = true; } -inline void HTMLToken::beginStartTag(LChar character) +inline void HTMLToken::beginStartTag(Latin1Character character) { ASSERT(character); ASSERT(m_type == Type::Uninitialized); @@ -266,7 +266,7 @@ inline void HTMLToken::beginStartTag(LChar character) m_data.append(character); } -inline void HTMLToken::beginEndTag(LChar character) +inline void HTMLToken::beginEndTag(Latin1Character character) { ASSERT(m_type == Type::Uninitialized); m_type = Type::EndTag; @@ -280,7 +280,7 @@ inline void HTMLToken::beginEndTag(LChar character) m_data.append(character); } -inline void HTMLToken::beginEndTag(const Vector& characters) +inline void HTMLToken::beginEndTag(const Vector& characters) { ASSERT(m_type == Type::Uninitialized); m_type = Type::EndTag; @@ -358,7 +358,7 @@ inline bool HTMLToken::charactersIsAll8BitData() const return m_data8BitCheck <= 0xFF; } -inline void HTMLToken::appendToCharacter(LChar character) +inline void HTMLToken::appendToCharacter(Latin1Character character) { ASSERT(m_type == Type::Uninitialized || m_type == Type::Character); m_type = Type::Character; @@ -373,7 +373,7 @@ inline void HTMLToken::appendToCharacter(UChar character) m_data8BitCheck |= character; } -inline void HTMLToken::appendToCharacter(const Vector& characters) +inline void HTMLToken::appendToCharacter(const Vector& characters) { ASSERT(m_type == Type::Uninitialized || m_type == Type::Character); m_type = Type::Character; diff --git a/Source/WebCore/html/parser/HTMLTokenizer.cpp b/Source/WebCore/html/parser/HTMLTokenizer.cpp index da8a0c788212e..30641889e1d27 100644 --- a/Source/WebCore/html/parser/HTMLTokenizer.cpp +++ b/Source/WebCore/html/parser/HTMLTokenizer.cpp @@ -39,7 +39,7 @@ namespace WebCore { using namespace HTMLNames; -static inline LChar convertASCIIAlphaToLower(UChar character) +static inline Latin1Character convertASCIIAlphaToLower(char16_t character) { ASSERT(isASCIIAlpha(character)); return toASCIILowerUnchecked(character); @@ -72,7 +72,7 @@ inline void HTMLTokenizer::bufferASCIICharacter(UChar character) { ASSERT(character != kEndOfFileMarker); ASSERT(isASCII(character)); - LChar narrowedCharacter = character; + Latin1Character narrowedCharacter = character; m_token.appendToCharacter(narrowedCharacter); } diff --git a/Source/WebCore/html/parser/HTMLTokenizer.h b/Source/WebCore/html/parser/HTMLTokenizer.h index 60758a64fc509..1fb5d423d80dd 100644 --- a/Source/WebCore/html/parser/HTMLTokenizer.h +++ b/Source/WebCore/html/parser/HTMLTokenizer.h @@ -200,12 +200,12 @@ class HTMLTokenizer { Vector m_appropriateEndTagName; // https://html.spec.whatwg.org/#temporary-buffer - Vector m_temporaryBuffer; + Vector m_temporaryBuffer; // We occasionally want to emit both a character token and an end tag // token (e.g., when lexing script). We buffer the name of the end tag // token here so we remember it next time we re-enter the tokenizer. - Vector m_bufferedEndTagName; + Vector m_bufferedEndTagName; const HTMLParserOptions m_options; }; diff --git a/Source/WebCore/html/parser/HTMLTreeBuilder.cpp b/Source/WebCore/html/parser/HTMLTreeBuilder.cpp index 51ee40f937c8f..c8a27b6a60f2d 100644 --- a/Source/WebCore/html/parser/HTMLTreeBuilder.cpp +++ b/Source/WebCore/html/parser/HTMLTreeBuilder.cpp @@ -193,7 +193,7 @@ class HTMLTreeBuilder::ExternalCharacterTokenBuffer { String takeRemainingWhitespace() { ASSERT(!isEmpty()); - Vector whitespace; + Vector whitespace; do { UChar character = m_text[0]; if (isASCIIWhitespace(character)) diff --git a/Source/WebCore/html/track/VTTScanner.cpp b/Source/WebCore/html/track/VTTScanner.cpp index f880ef3b15dc7..9b9a729aaea77 100644 --- a/Source/WebCore/html/track/VTTScanner.cpp +++ b/Source/WebCore/html/track/VTTScanner.cpp @@ -55,7 +55,7 @@ bool VTTScanner::scan(char c) return true; } -bool VTTScanner::scan(std::span characters) +bool VTTScanner::scan(std::span characters) { unsigned matchLength = m_is8Bit ? m_end.characters8 - m_data.characters8 : m_end.characters16 - m_data.characters16; if (matchLength < characters.size()) diff --git a/Source/WebCore/html/track/VTTScanner.h b/Source/WebCore/html/track/VTTScanner.h index 8abb31c17ae00..de22ae7333b33 100644 --- a/Source/WebCore/html/track/VTTScanner.h +++ b/Source/WebCore/html/track/VTTScanner.h @@ -50,7 +50,7 @@ class VTTScanner { public: explicit VTTScanner(const String& line); - typedef const LChar* Position; + typedef const Latin1Character* Position; class Run { public: @@ -78,7 +78,7 @@ class VTTScanner { // Scan the character |c|. bool scan(char); // Scan the first |charactersCount| characters of the string |characters|. - bool scan(std::span characters); + bool scan(std::span characters); // Scan the literal |characters|. template @@ -87,21 +87,21 @@ class VTTScanner { // Skip (advance the input pointer) as long as the specified // |characterPredicate| returns true, and the input pointer is not passed // the end of the input. - template + template void skipWhile(); // Like skipWhile, but using a negated predicate. - template + template void skipUntil(); // Return the run of characters for which the specified // |characterPredicate| returns true. The start of the run will be the // current input pointer. - template + template Run collectWhile(); // Like collectWhile, but using a negated predicate. - template + template Run collectUntil(); // Scan the string |toMatch|, using the specified |run| as the sequence to @@ -132,19 +132,19 @@ class VTTScanner { Position position() const { return m_data.characters8; } Position end() const { return m_end.characters8; } void seekTo(Position); - UChar currentChar() const; + char16_t currentChar() const; void advance(unsigned amount = 1); - // Adapt a UChar-predicate to an LChar-predicate. + // Adapt a char16_t-predicate to an Latin1Character-predicate. // (For use with skipWhile/Until from ParsingUtilities.h). - template - static inline bool LCharPredicateAdapter(LChar c) { return characterPredicate(c); } + template + static inline bool Latin1CharacterPredicateAdapter(Latin1Character c) { return characterPredicate(c); } union { - const LChar* characters8; - const UChar* characters16; + const Latin1Character* characters8; + const char16_t* characters16; } m_data; union { - const LChar* characters8; - const UChar* characters16; + const Latin1Character* characters8; + const char16_t* characters16; } m_end; const String m_source; bool m_is8Bit; @@ -154,55 +154,55 @@ inline size_t VTTScanner::Run::length() const { if (m_is8Bit) return m_end - m_start; - return reinterpret_cast(m_end) - reinterpret_cast(m_start); + return reinterpret_cast(m_end) - reinterpret_cast(m_start); } template inline bool VTTScanner::scan(const char (&characters)[charactersCount]) { - return scan({ byteCast(&characters[0]), charactersCount - 1 }); + return scan({ byteCast(&characters[0]), charactersCount - 1 }); } -template +template inline void VTTScanner::skipWhile() { if (m_is8Bit) - WebCore::skipWhile >(m_data.characters8, m_end.characters8); + WebCore::skipWhile >(m_data.characters8, m_end.characters8); else WebCore::skipWhile(m_data.characters16, m_end.characters16); } -template +template inline void VTTScanner::skipUntil() { if (m_is8Bit) - WebCore::skipUntil >(m_data.characters8, m_end.characters8); + WebCore::skipUntil >(m_data.characters8, m_end.characters8); else WebCore::skipUntil(m_data.characters16, m_end.characters16); } -template +template inline VTTScanner::Run VTTScanner::collectWhile() { if (m_is8Bit) { - const LChar* current = m_data.characters8; - WebCore::skipWhile>(current, m_end.characters8); + const Latin1Character* current = m_data.characters8; + WebCore::skipWhile>(current, m_end.characters8); return Run(position(), current, m_is8Bit); } - const UChar* current = m_data.characters16; + const char16_t* current = m_data.characters16; WebCore::skipWhile(current, m_end.characters16); return Run(position(), reinterpret_cast(current), m_is8Bit); } -template +template inline VTTScanner::Run VTTScanner::collectUntil() { if (m_is8Bit) { - const LChar* current = m_data.characters8; - WebCore::skipUntil >(current, m_end.characters8); + const Latin1Character* current = m_data.characters8; + WebCore::skipUntil >(current, m_end.characters8); return Run(position(), current, m_is8Bit); } - const UChar* current = m_data.characters16; + const char16_t* current = m_data.characters16; WebCore::skipUntil(current, m_end.characters16); return Run(position(), reinterpret_cast(current), m_is8Bit); } @@ -213,10 +213,10 @@ inline void VTTScanner::seekTo(Position position) m_data.characters8 = position; } -inline UChar VTTScanner::currentChar() const +inline char16_t VTTScanner::currentChar() const { ASSERT(position() < end()); - return m_is8Bit ? *m_data.characters8 : *m_data.characters16; + return m_is8Bit ? char16_t { *m_data.characters8 } : *m_data.characters16; } inline void VTTScanner::advance(unsigned amount) diff --git a/Source/WebCore/html/track/WebVTTParser.cpp b/Source/WebCore/html/track/WebVTTParser.cpp index 5bad85caeeaf1..c7fcca3808a96 100644 --- a/Source/WebCore/html/track/WebVTTParser.cpp +++ b/Source/WebCore/html/track/WebVTTParser.cpp @@ -231,7 +231,7 @@ void WebVTTParser::parse() void WebVTTParser::fileFinished() { ASSERT(m_state != Finished); - parseBytes("\n\n"_span); + parseBytes(byteCast("\n\n"_span)); m_state = Finished; } diff --git a/Source/WebCore/inspector/InspectorStyleSheet.cpp b/Source/WebCore/inspector/InspectorStyleSheet.cpp index 413d123ab28a8..cca8f403f605c 100644 --- a/Source/WebCore/inspector/InspectorStyleSheet.cpp +++ b/Source/WebCore/inspector/InspectorStyleSheet.cpp @@ -343,7 +343,7 @@ void StyleSheetHandler::endRuleHeader(unsigned offset) ASSERT(!m_currentRuleDataStack.isEmpty()); if (m_parsedText.is8Bit()) - setRuleHeaderEnd(m_parsedText.span8().first(offset)); + setRuleHeaderEnd(m_parsedText.span8().first(offset)); else setRuleHeaderEnd(m_parsedText.span16().first(offset)); } @@ -465,7 +465,7 @@ void StyleSheetHandler::fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData) return; if (m_parsedText.is8Bit()) { - fixUnparsedProperties(m_parsedText.span8(), ruleData); + fixUnparsedProperties(m_parsedText.span8(), ruleData); return; } diff --git a/Source/WebCore/layout/formattingContexts/inline/text/TextUtil.cpp b/Source/WebCore/layout/formattingContexts/inline/text/TextUtil.cpp index c56e0889c728b..cfb869ed7ce00 100644 --- a/Source/WebCore/layout/formattingContexts/inline/text/TextUtil.cpp +++ b/Source/WebCore/layout/formattingContexts/inline/text/TextUtil.cpp @@ -684,8 +684,8 @@ bool TextUtil::canUseSimplifiedTextMeasuring(StringView textContent, const FontC bool TextUtil::hasPositionDependentContentWidth(StringView textContent) { if (textContent.is8Bit()) - return charactersContain(textContent.span8()); - return charactersContain(textContent.span16()); + return charactersContain(textContent.span8()); + return charactersContain(textContent.span16()); } } diff --git a/Source/WebCore/loader/FormSubmission.cpp b/Source/WebCore/loader/FormSubmission.cpp index f47cbc47d836d..9dfe1ad553933 100644 --- a/Source/WebCore/loader/FormSubmission.cpp +++ b/Source/WebCore/loader/FormSubmission.cpp @@ -77,7 +77,7 @@ static void appendMailtoPostFormDataToURL(URL& url, const FormData& data, const Vector bodyData(std::span("body=", static_cast(5))); FormDataBuilder::encodeStringAsFormData(bodyData, body.utf8()); - body = makeStringByReplacingAll(bodyData.span(), '+', "%20"_s); + body = makeStringByReplacingAll(byteCast(bodyData.span()), '+', "%20"_s); auto query = url.query(); if (query.isEmpty()) @@ -223,7 +223,7 @@ Ref FormSubmission::create(HTMLFormElement& form, HTMLFormContro if (isMultiPartForm) { formData = FormData::createMultiPart(domFormData); - boundary = String(formData->boundary()); + boundary = String(byteCast(formData->boundary().span())); } else { formData = FormData::create(domFormData, attributes.method() == Method::Get ? FormData::EncodingType::FormURLEncoded : FormData::parseEncodingType(encodingType)); if (copiedAttributes.method() == Method::Post && isMailtoForm) { diff --git a/Source/WebCore/loader/PrivateClickMeasurement.cpp b/Source/WebCore/loader/PrivateClickMeasurement.cpp index d8921dd1fc204..6e20b0613c551 100644 --- a/Source/WebCore/loader/PrivateClickMeasurement.cpp +++ b/Source/WebCore/loader/PrivateClickMeasurement.cpp @@ -263,7 +263,7 @@ bool PrivateClickMeasurement::hasHigherPriorityThan(const PrivateClickMeasuremen static URL makeValidURL(const RegistrableDomain& domain, const char* path) { - URL validURL { makeString("https://"_s, domain.string(), span(path)) }; + URL validURL { makeString("https://"_s, domain.string(), unsafeSpan(path)) }; return validURL.isValid() ? validURL : URL { }; } diff --git a/Source/WebCore/loader/ResourceCryptographicDigest.cpp b/Source/WebCore/loader/ResourceCryptographicDigest.cpp index b946c510d3800..3abd0e05d3e7b 100644 --- a/Source/WebCore/loader/ResourceCryptographicDigest.cpp +++ b/Source/WebCore/loader/ResourceCryptographicDigest.cpp @@ -85,7 +85,7 @@ std::optional parseCryptographicDigest(StringParsin return parseCryptographicDigestImpl(buffer); } -std::optional parseCryptographicDigest(StringParsingBuffer& buffer) +std::optional parseCryptographicDigest(StringParsingBuffer& buffer) { return parseCryptographicDigestImpl(buffer); } @@ -118,7 +118,7 @@ std::optional parseEncodedCryptographicDiges return parseEncodedCryptographicDigestImpl(buffer); } -std::optional parseEncodedCryptographicDigest(StringParsingBuffer& buffer) +std::optional parseEncodedCryptographicDigest(StringParsingBuffer& buffer) { return parseEncodedCryptographicDigestImpl(buffer); } diff --git a/Source/WebCore/loader/ResourceCryptographicDigest.h b/Source/WebCore/loader/ResourceCryptographicDigest.h index 2be4f4fb52b67..48c853978444b 100644 --- a/Source/WebCore/loader/ResourceCryptographicDigest.h +++ b/Source/WebCore/loader/ResourceCryptographicDigest.h @@ -29,6 +29,7 @@ #include #include #include +#include #include namespace WebCore { @@ -65,11 +66,11 @@ struct EncodedResourceCryptographicDigest { String digest; }; -std::optional parseCryptographicDigest(StringParsingBuffer&); -std::optional parseCryptographicDigest(StringParsingBuffer&); +std::optional parseCryptographicDigest(StringParsingBuffer&); +std::optional parseCryptographicDigest(StringParsingBuffer&); -std::optional parseEncodedCryptographicDigest(StringParsingBuffer&); -std::optional parseEncodedCryptographicDigest(StringParsingBuffer&); +std::optional parseEncodedCryptographicDigest(StringParsingBuffer&); +std::optional parseEncodedCryptographicDigest(StringParsingBuffer&); std::optional decodeEncodedResourceCryptographicDigest(const EncodedResourceCryptographicDigest&); diff --git a/Source/WebCore/loader/TextResourceDecoder.cpp b/Source/WebCore/loader/TextResourceDecoder.cpp index 0cd4fe1873ee1..fa7d9ef2e7917 100644 --- a/Source/WebCore/loader/TextResourceDecoder.cpp +++ b/Source/WebCore/loader/TextResourceDecoder.cpp @@ -531,7 +531,7 @@ bool TextResourceDecoder::checkForHeadCharset(std::span data, boo int len = 0; int pos = findXMLEncoding(ptr, xmlDeclarationEnd - ptr, len); if (pos != -1) - setEncoding(findTextEncoding(ptr + pos, len), EncodingFromXMLHeader); + setEncoding(findTextEncoding(byteCast(ptr + pos), len), EncodingFromXMLHeader); // continue looking for a charset - it may be specified in an HTTP-Equiv meta } else if (bytesEqual(ptr, '<', 0, '?', 0, 'x', 0)) { setEncoding(PAL::UTF16LittleEndianEncoding(), AutoDetectedEncoding); diff --git a/Source/WebCore/loader/cache/CachedScript.cpp b/Source/WebCore/loader/cache/CachedScript.cpp index 10b363dbda0c1..970594548d039 100644 --- a/Source/WebCore/loader/cache/CachedScript.cpp +++ b/Source/WebCore/loader/cache/CachedScript.cpp @@ -82,7 +82,7 @@ StringView CachedScript::script(ShouldDecodeAsUTF8Only shouldDecodeAsUTF8Only) } if (m_decodingState == DataAndDecodedStringHaveSameBytes) - return { contiguousData->span() }; + return { byteCast(contiguousData->span()) }; bool shouldForceRedecoding = m_wasForceDecodedAsUTF8 != (shouldDecodeAsUTF8Only == ShouldDecodeAsUTF8Only::Yes); if (!m_script || shouldForceRedecoding) { diff --git a/Source/WebCore/page/NavigatorBase.cpp b/Source/WebCore/page/NavigatorBase.cpp index 71cb38b1cf266..5aed65a74f3e7 100644 --- a/Source/WebCore/page/NavigatorBase.cpp +++ b/Source/WebCore/page/NavigatorBase.cpp @@ -94,7 +94,7 @@ String NavigatorBase::platform() const static std::once_flag onceKey; std::call_once(onceKey, [] { struct utsname osname; - platformName.construct(uname(&osname) >= 0 ? makeString(span(osname.sysname), " "_s, span(osname.machine)) : emptyString()); + platformName.construct(uname(&osname) >= 0 ? makeString(unsafeSpan(osname.sysname), " "_s, unsafeSpan(osname.machine)) : emptyString()); }); return platformName->isolatedCopy(); #elif PLATFORM(IOS_FAMILY) diff --git a/Source/WebCore/page/PrintContext.cpp b/Source/WebCore/page/PrintContext.cpp index f1b72fc4c2854..7f96ed5358045 100644 --- a/Source/WebCore/page/PrintContext.cpp +++ b/Source/WebCore/page/PrintContext.cpp @@ -385,7 +385,7 @@ String PrintContext::pageProperty(LocalFrame* frame, const char* propertyName, i if (!strcmp(propertyName, "size")) return makeString(style->pageSize().width.value(), ' ', style->pageSize().height.value()); - return makeString("pageProperty() unimplemented for: "_s, span(propertyName)); + return makeString("pageProperty() unimplemented for: "_s, unsafeSpan(propertyName)); } bool PrintContext::isPageBoxVisible(LocalFrame* frame, int pageNumber) diff --git a/Source/WebCore/platform/Decimal.cpp b/Source/WebCore/platform/Decimal.cpp index 5dbd49dee25f6..ae1662524e19b 100644 --- a/Source/WebCore/platform/Decimal.cpp +++ b/Source/WebCore/platform/Decimal.cpp @@ -545,7 +545,7 @@ Decimal Decimal::fromDouble(double doubleValue) if (std::isfinite(doubleValue)) { NumberToStringBuffer buffer; auto* result = numberToString(doubleValue, buffer); - return fromString(span8(result)); + return fromString(byteCast(unsafeSpan(result))); } if (std::isinf(doubleValue)) diff --git a/Source/WebCore/platform/SharedBufferChunkReader.cpp b/Source/WebCore/platform/SharedBufferChunkReader.cpp index c750e817e2195..5cc46b06f86ca 100644 --- a/Source/WebCore/platform/SharedBufferChunkReader.cpp +++ b/Source/WebCore/platform/SharedBufferChunkReader.cpp @@ -60,7 +60,7 @@ void SharedBufferChunkReader::setSeparator(const Vector& separator) void SharedBufferChunkReader::setSeparator(const char* separator) { m_separator.clear(); - m_separator.append(span(separator)); + m_separator.append(unsafeSpan(separator)); } bool SharedBufferChunkReader::nextChunk(Vector& chunk, bool includeSeparator) diff --git a/Source/WebCore/platform/audio/gstreamer/AudioDecoderGStreamer.cpp b/Source/WebCore/platform/audio/gstreamer/AudioDecoderGStreamer.cpp index 7640bf894795e..598cb3494a3ac 100644 --- a/Source/WebCore/platform/audio/gstreamer/AudioDecoderGStreamer.cpp +++ b/Source/WebCore/platform/audio/gstreamer/AudioDecoderGStreamer.cpp @@ -166,7 +166,7 @@ GStreamerInternalAudioDecoder::GStreamerInternalAudioDecoder(const String& codec { GST_DEBUG_OBJECT(element.get(), "Configuring decoder for codec %s", codecName.ascii().data()); - const char* parser = nullptr; + ASCIILiteral parser; if (codecName.startsWith("mp4a"_s)) { m_inputCaps = adoptGRef(gst_caps_new_simple("audio/mpeg", "mpegversion", G_TYPE_INT, 4, "channels", G_TYPE_INT, config.numberOfChannels, nullptr)); auto codecData = wrapSpanData(config.description); @@ -181,7 +181,7 @@ GStreamerInternalAudioDecoder::GStreamerInternalAudioDecoder(const String& codec m_inputCaps = adoptGRef(gst_caps_new_simple("audio/x-opus", "channel-mapping-family", G_TYPE_INT, channelMappingFamily, nullptr)); m_header = wrapSpanData(config.description); if (m_header) - parser = "opusparse"; + parser = "opusparse"_s; } else if (codecName == "alaw"_s) m_inputCaps = adoptGRef(gst_caps_new_simple("audio/x-alaw", "rate", G_TYPE_INT, config.sampleRate, "channels", G_TYPE_INT, config.numberOfChannels, nullptr)); else if (codecName == "ulaw"_s) @@ -192,7 +192,7 @@ GStreamerInternalAudioDecoder::GStreamerInternalAudioDecoder(const String& codec GST_WARNING("Decoder config description for flac codec is mandatory"); return; } - parser = "flacparse"; + parser = "flacparse"_s; m_inputCaps = adoptGRef(gst_caps_new_empty_simple("audio/x-flac")); } else if (codecName == "vorbis"_s) { m_header = wrapSpanData(config.description); @@ -200,7 +200,7 @@ GStreamerInternalAudioDecoder::GStreamerInternalAudioDecoder(const String& codec GST_WARNING("Decoder config description for vorbis codec is mandatory"); return; } - parser = "oggparse"; + parser = "oggparse"_s; m_inputCaps = adoptGRef(gst_caps_new_empty_simple("application/ogg")); } else if (codecName.startsWith("pcm-"_s)) { auto components = codecName.split('-'); @@ -223,7 +223,7 @@ GStreamerInternalAudioDecoder::GStreamerInternalAudioDecoder(const String& codec m_inputCaps = adoptGRef(gst_caps_new_simple("audio/x-raw", "format", G_TYPE_STRING, gst_audio_format_to_string(gstPcmFormat), "rate", G_TYPE_INT, config.sampleRate, "channels", G_TYPE_INT, config.numberOfChannels, "layout", G_TYPE_STRING, "interleaved", nullptr)); - parser = "rawaudioparse"; + parser = "rawaudioparse"_s; } else return; @@ -235,18 +235,18 @@ GStreamerInternalAudioDecoder::GStreamerInternalAudioDecoder(const String& codec auto* factory = gst_element_get_factory(element.get()); isParserRequired = !gst_element_factory_can_sink_all_caps(factory, m_inputCaps.get()); } - if (!g_strcmp0(parser, "rawaudioparse")) { - harnessedElement = makeGStreamerElement(parser, nullptr); + if (parser == "rawaudioparse"_s) { + harnessedElement = makeGStreamerElement(parser); if (!harnessedElement) { - GST_WARNING_OBJECT(element.get(), "Required parser %s not found", parser); + GST_WARNING_OBJECT(element.get(), "Required parser %s not found", parser.characters()); m_inputCaps.clear(); return; } } else if (parser && isParserRequired) { // The decoder won't accept the input caps, so put a parser in front. - auto* parserElement = makeGStreamerElement(parser, nullptr); + auto* parserElement = makeGStreamerElement(parser); if (!parserElement) { - GST_WARNING_OBJECT(element.get(), "Required parser %s not found, decoding will fail", parser); + GST_WARNING_OBJECT(element.get(), "Required parser %s not found, decoding will fail", parser.characters()); m_inputCaps.clear(); return; } diff --git a/Source/WebCore/platform/audio/gstreamer/AudioDestinationGStreamer.cpp b/Source/WebCore/platform/audio/gstreamer/AudioDestinationGStreamer.cpp index 6f68ec4207603..073505856671a 100644 --- a/Source/WebCore/platform/audio/gstreamer/AudioDestinationGStreamer.cpp +++ b/Source/WebCore/platform/audio/gstreamer/AudioDestinationGStreamer.cpp @@ -149,8 +149,8 @@ AudioDestinationGStreamer::AudioDestinationGStreamer(AudioIOCallback& callback, } } - GstElement* audioConvert = makeGStreamerElement("audioconvert", nullptr); - GstElement* audioResample = makeGStreamerElement("audioresample", nullptr); + GstElement* audioConvert = makeGStreamerElement("audioconvert"_s); + GstElement* audioResample = makeGStreamerElement("audioresample"_s); auto queue = gst_element_factory_make("queue", nullptr); g_object_set(queue, "max-size-buffers", 2, "max-size-bytes", 0, "max-size-time", static_cast(0), nullptr); @@ -166,7 +166,7 @@ AudioDestinationGStreamer::AudioDestinationGStreamer(AudioIOCallback& callback, // 1) Some platform sinks don't support non-interleaved audio without special caps (rialtowebaudiosink). // 2) Interaudio sink/src doesn't fully support non-interleaved audio (webkit audio sink) // 3) audiomixer doesn't support non-interleaved audio in output pipeline (webkit audio sink) - GstElement* capsFilter = makeGStreamerElement("capsfilter", nullptr); + GstElement* capsFilter = makeGStreamerElement("capsfilter"_s); GRefPtr caps = adoptGRef(gst_caps_new_simple("audio/x-raw", "layout", G_TYPE_STRING, "interleaved", nullptr)); g_object_set(capsFilter, "caps", caps.get(), nullptr); gst_bin_add(GST_BIN_CAST(m_pipeline.get()), capsFilter); diff --git a/Source/WebCore/platform/audio/gstreamer/AudioEncoderGStreamer.cpp b/Source/WebCore/platform/audio/gstreamer/AudioEncoderGStreamer.cpp index ae62dce82ca23..946ef3468c4ca 100644 --- a/Source/WebCore/platform/audio/gstreamer/AudioEncoderGStreamer.cpp +++ b/Source/WebCore/platform/audio/gstreamer/AudioEncoderGStreamer.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include namespace WebCore { @@ -189,7 +190,7 @@ GStreamerInternalAudioEncoder::GStreamerInternalAudioEncoder(AudioEncoder::Descr , m_encoder(WTFMove(encoderElement)) { static Atomic counter = 0; - auto binName = makeString("audio-encoder-"_s, span(GST_OBJECT_NAME(m_encoder.get())), '-', counter.exchangeAdd(1)); + auto binName = makeString("audio-encoder-"_s, unsafeSpan(GST_OBJECT_NAME(m_encoder.get())), '-', counter.exchangeAdd(1)); GRefPtr harnessedElement = gst_bin_new(binName.ascii().data()); auto audioconvert = gst_element_factory_make("audioconvert", nullptr); @@ -288,17 +289,19 @@ GStreamerInternalAudioEncoder::~GStreamerInternalAudioEncoder() String GStreamerInternalAudioEncoder::initialize(const String& codecName, const AudioEncoder::Config& config) { GST_DEBUG_OBJECT(m_harness->element(), "Initializing encoder for codec %s", codecName.ascii().data()); + + auto name = GMallocString::unsafeAdoptFromUTF8(gst_element_get_name(m_encoder.get())); + if (codecName.startsWith("mp4a"_s)) { - const char* streamFormat = config.isAacADTS.value_or(false) ? "adts" : "raw"; - m_outputCaps = adoptGRef(gst_caps_new_simple("audio/mpeg", "mpegversion", G_TYPE_INT, 4, "stream-format", G_TYPE_STRING, streamFormat, nullptr)); - if (gstObjectHasProperty(m_encoder.get(), "bitrate") && config.bitRate && config.bitRate < std::numeric_limits::max()) + m_outputCaps = adoptGRef(gst_caps_new_simple("audio/mpeg", "mpegversion", G_TYPE_INT, 4, + "stream-format", G_TYPE_STRING, config.isAacADTS.value_or(false) ? "adts" : "raw", nullptr)); + if (gstObjectHasProperty(m_encoder.get(), "bitrate"_s) && config.bitRate && config.bitRate < std::numeric_limits::max()) g_object_set(m_encoder.get(), "bitrate", static_cast(config.bitRate), nullptr); } else if (codecName == "mp3"_s) m_outputCaps = adoptGRef(gst_caps_new_simple("audio/mpeg", "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, nullptr)); else if (codecName == "opus"_s) { if (auto parameters = config.opusConfig) { - GUniquePtr name(gst_element_get_name(m_encoder.get())); - if (LIKELY(g_str_has_prefix(name.get(), "opusenc"))) { + if (LIKELY(startsWith(name.span(), "opusenc"_s))) { if (config.bitRate && config.bitRate < std::numeric_limits::max()) { if (config.bitRate >= 4000 && config.bitRate <= 650000) g_object_set(m_encoder.get(), "bitrate", static_cast(config.bitRate), nullptr); @@ -326,8 +329,7 @@ String GStreamerInternalAudioEncoder::initialize(const String& codecName, const else if (codecName == "flac"_s) { m_outputCaps = adoptGRef(gst_caps_new_empty_simple("audio/x-flac")); if (auto parameters = config.flacConfig) { - GUniquePtr name(gst_element_get_name(m_encoder.get())); - if (LIKELY(g_str_has_prefix(name.get(), "flacenc"))) + if (startsWith(name.span(), "flacenc"_s)) g_object_set(m_encoder.get(), "blocksize", static_cast(parameters->blockSize), "quality", parameters->compressLevel, nullptr); } } else if (codecName == "vorbis"_s) { diff --git a/Source/WebCore/platform/audio/gstreamer/AudioFileReaderGStreamer.cpp b/Source/WebCore/platform/audio/gstreamer/AudioFileReaderGStreamer.cpp index cbee6c5281fa0..6b7b8d2c74aa6 100644 --- a/Source/WebCore/platform/audio/gstreamer/AudioFileReaderGStreamer.cpp +++ b/Source/WebCore/platform/audio/gstreamer/AudioFileReaderGStreamer.cpp @@ -275,8 +275,8 @@ void AudioFileReader::handleMessage(GstMessage* message) GST_INFO_OBJECT(m_pipeline.get(), "State changed (old: %s, new: %s, pending: %s)", gst_element_state_get_name(oldState), gst_element_state_get_name(newState), gst_element_state_get_name(pending)); - auto dotFileName = makeString(span(GST_OBJECT_NAME(m_pipeline.get())), '_', span(gst_element_state_get_name(oldState)), '_', span(gst_element_state_get_name(newState))); - GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN_CAST(m_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.utf8().data()); + auto dotFileName = makeString(unsafeSpan(GST_OBJECT_NAME(m_pipeline.get())), '_', unsafeSpan(gst_element_state_get_name(oldState)), '_', unsafeSpan(gst_element_state_get_name(newState))); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN_CAST(m_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.ascii().data()); break; } case GST_MESSAGE_LATENCY: @@ -293,7 +293,7 @@ void AudioFileReader::handleNewDeinterleavePad(GstPad* pad) // in an appsink so we can pull the data from each // channel. Pipeline looks like: // ... deinterleave ! appsink. - GstElement* sink = makeGStreamerElement("appsink", nullptr); + GstElement* sink = makeGStreamerElement("appsink"_s); if (!m_firstChannelType) { auto caps = adoptGRef(gst_pad_query_caps(pad, nullptr)); @@ -346,16 +346,16 @@ void AudioFileReader::plugDeinterleave(GstPad* pad) return; auto padCaps = adoptGRef(gst_pad_query_caps(pad, nullptr)); - if (!doCapsHaveType(padCaps.get(), "audio/x-raw")) + if (!doCapsHaveType(padCaps.get(), "audio/x-raw"_s)) return; // A decodebin pad was added, plug in a deinterleave element to // separate each planar channel. Sub pipeline looks like // ... decodebin2 ! audioconvert ! audioresample ! capsfilter ! deinterleave. - GstElement* audioConvert = makeGStreamerElement("audioconvert", nullptr); - GstElement* audioResample = makeGStreamerElement("audioresample", nullptr); + GstElement* audioConvert = makeGStreamerElement("audioconvert"_s); + GstElement* audioResample = makeGStreamerElement("audioresample"_s); GstElement* capsFilter = gst_element_factory_make("capsfilter", nullptr); - m_deInterleave = makeGStreamerElement("deinterleave", "deinterleave"); + m_deInterleave = makeGStreamerElement("deinterleave"_s, "deinterleave"_s); g_object_set(m_deInterleave.get(), "keep-positions", TRUE, nullptr); g_signal_connect_swapped(m_deInterleave.get(), "pad-added", G_CALLBACK(deinterleavePadAddedCallback), this); @@ -409,11 +409,11 @@ void AudioFileReader::decodeAudioForBusCreation() }, this, nullptr); ASSERT(!m_data.empty()); - auto* source = makeGStreamerElement("giostreamsrc", nullptr); + auto* source = makeGStreamerElement("giostreamsrc"_s); auto memoryStream = adoptGRef(g_memory_input_stream_new_from_data(m_data.data(), m_data.size(), nullptr)); g_object_set(source, "stream", memoryStream.get(), nullptr); - m_decodebin = makeGStreamerElement("decodebin", "decodebin"); + m_decodebin = makeGStreamerElement("decodebin"_s, "decodebin"_s); g_signal_connect(m_decodebin.get(), "autoplug-select", G_CALLBACK(decodebinAutoplugSelectCallback), nullptr); g_signal_connect_swapped(m_decodebin.get(), "pad-added", G_CALLBACK(decodebinPadAddedCallback), this); diff --git a/Source/WebCore/platform/audio/gstreamer/AudioSourceProviderGStreamer.cpp b/Source/WebCore/platform/audio/gstreamer/AudioSourceProviderGStreamer.cpp index 51547b0226c00..80496cfbe6ff4 100644 --- a/Source/WebCore/platform/audio/gstreamer/AudioSourceProviderGStreamer.cpp +++ b/Source/WebCore/platform/audio/gstreamer/AudioSourceProviderGStreamer.cpp @@ -111,7 +111,7 @@ AudioSourceProviderGStreamer::AudioSourceProviderGStreamer(MediaStreamTrackPriva m_audioSinkBin = gst_parse_bin_from_description("tee name=audioTee", true, nullptr); - auto* decodebin = makeGStreamerElement("uridecodebin3", nullptr); + auto* decodebin = makeGStreamerElement("uridecodebin3"_s); g_signal_connect_swapped(decodebin, "source-setup", G_CALLBACK(+[](AudioSourceProviderGStreamer* provider, GstElement* sourceElement) { if (!WEBKIT_IS_MEDIA_STREAM_SRC(sourceElement)) { @@ -123,7 +123,7 @@ AudioSourceProviderGStreamer::AudioSourceProviderGStreamer(MediaStreamTrackPriva g_signal_connect_swapped(decodebin, "pad-added", G_CALLBACK(+[](AudioSourceProviderGStreamer* provider, GstPad* pad) { auto padCaps = adoptGRef(gst_pad_query_caps(pad, nullptr)); - bool isAudio = doCapsHaveType(padCaps.get(), "audio"); + bool isAudio = doCapsHaveType(padCaps.get(), "audio"_s); RELEASE_ASSERT(isAudio); auto sinkPad = adoptGRef(gst_element_get_static_pad(provider->m_audioSinkBin.get(), "sink")); @@ -205,11 +205,11 @@ void AudioSourceProviderGStreamer::configureAudioBin(GstElement* audioBin, GstEl GstElement* audioTee = gst_element_factory_make("tee", "audioTee"); GstElement* audioQueue = gst_element_factory_make("queue", nullptr); - GstElement* audioConvert = makeGStreamerElement("audioconvert", nullptr); - GstElement* audioConvert2 = makeGStreamerElement("audioconvert", nullptr); - GstElement* audioResample = makeGStreamerElement("audioresample", nullptr); - GstElement* audioResample2 = makeGStreamerElement("audioresample", nullptr); - GstElement* volumeElement = makeGStreamerElement("volume", "volume"); + GstElement* audioConvert = makeGStreamerElement("audioconvert"_s); + GstElement* audioConvert2 = makeGStreamerElement("audioconvert"_s); + GstElement* audioResample = makeGStreamerElement("audioresample"_s); + GstElement* audioResample2 = makeGStreamerElement("audioresample"_s); + GstElement* volumeElement = makeGStreamerElement("volume"_s, "volume"_s); gst_bin_add_many(GST_BIN_CAST(m_audioSinkBin.get()), audioTee, audioQueue, audioConvert, audioResample, volumeElement, audioConvert2, audioResample2, audioSink, nullptr); @@ -324,10 +324,10 @@ void AudioSourceProviderGStreamer::setClient(WeakPtr& // ensure deinterleave and the sinks downstream receive buffers in // the format specified by the capsfilter. auto* audioQueue = gst_element_factory_make("queue", "queue"); - auto* audioConvert = makeGStreamerElement("audioconvert", "audioconvert"); - auto* audioResample = makeGStreamerElement("audioresample", "audioresample"); + auto* audioConvert = makeGStreamerElement("audioconvert"_s, "audioconvert"_s); + auto* audioResample = makeGStreamerElement("audioresample"_s, "audioresample"_s); auto* capsFilter = gst_element_factory_make("capsfilter", "capsfilter"); - auto* deInterleave = makeGStreamerElement("deinterleave", "deinterleave"); + auto* deInterleave = makeGStreamerElement("deinterleave"_s, "deinterleave"_s); GST_DEBUG("Setting up audio deinterleave chain"); g_object_set(deInterleave, "keep-positions", TRUE, nullptr); @@ -377,7 +377,7 @@ void AudioSourceProviderGStreamer::handleNewDeinterleavePad(GstPad* pad) // channel. Pipeline looks like: // ... deinterleave ! queue ! appsink. auto* queue = gst_element_factory_make("queue", nullptr); - auto* sink = makeGStreamerElement("appsink", nullptr); + auto* sink = makeGStreamerElement("appsink"_s); static GstAppSinkCallbacks callbacks = { nullptr, diff --git a/Source/WebCore/platform/audio/gstreamer/PlatformRawAudioDataGStreamer.cpp b/Source/WebCore/platform/audio/gstreamer/PlatformRawAudioDataGStreamer.cpp index 25dcd9a74b664..aa9c4dafdc3b6 100644 --- a/Source/WebCore/platform/audio/gstreamer/PlatformRawAudioDataGStreamer.cpp +++ b/Source/WebCore/platform/audio/gstreamer/PlatformRawAudioDataGStreamer.cpp @@ -185,17 +185,32 @@ size_t PlatformRawAudioDataGStreamer::memoryCost() const return gst_buffer_get_size(gst_sample_get_buffer(m_sample.get())); } +#ifndef GST_DISABLE_GST_DEBUG +static ASCIILiteral layoutToString(GstAudioLayout layout) +{ + switch (layout) { + case GST_AUDIO_LAYOUT_INTERLEAVED: + return "interleaved"_s; + case GST_AUDIO_LAYOUT_NON_INTERLEAVED: + return "planar"_s; + } + return "unknown"_s; +} +#endif + void PlatformRawAudioData::copyTo(std::span destination, AudioSampleFormat format, size_t planeIndex, std::optional frameOffset, std::optional, unsigned long) { auto& self = *reinterpret_cast(this); - [[maybe_unused]] auto [sourceFormat, sourceLayout] = convertAudioSampleFormatToGStreamerFormat(self.format()); - auto [destinationFormat, destinationLayout] = convertAudioSampleFormatToGStreamerFormat(format); auto sourceOffset = frameOffset.value_or(0); #ifndef GST_DISABLE_GST_DEBUG - const char* destinationFormatDescription = gst_audio_format_to_string(destinationFormat); - GST_TRACE("Copying %s data at planeIndex %zu, destination format is %s, source offset: %zu", gst_audio_format_to_string(sourceFormat), planeIndex, destinationFormatDescription, sourceOffset); + [[maybe_unused]] auto[gstSourceFormat, sourceLayout] = convertAudioSampleFormatToGStreamerFormat(self.format()); + auto [gstDestinationFormat, destinationLayout] = convertAudioSampleFormatToGStreamerFormat(format); + auto destinationFormatDescription = CStringView::unsafeFromUTF8(gst_audio_format_to_string(gstDestinationFormat)); + GST_TRACE("Copying %s %s data at planeIndex %zu, destination format is %s %s, source offset: %zu", + layoutToString(sourceLayout).characters(), gst_audio_format_to_string(gstSourceFormat), planeIndex, + layoutToString(destinationLayout).characters(), destinationFormatDescription.utf8(), sourceOffset); #endif GST_TRACE("Input caps: %" GST_PTR_FORMAT, gst_sample_get_caps(self.sample())); @@ -215,7 +230,7 @@ void PlatformRawAudioData::copyTo(std::span destination, AudioSampleFor } GstAudioInfo destinationInfo; - gst_audio_info_set_format(&destinationInfo, destinationFormat, static_cast(self.sampleRate()), self.numberOfChannels(), nullptr); + gst_audio_info_set_format(&destinationInfo, gstDestinationFormat, static_cast(self.sampleRate()), self.numberOfChannels(), nullptr); GST_AUDIO_INFO_LAYOUT(&destinationInfo) = destinationLayout; auto outputCaps = adoptGRef(gst_audio_info_to_caps(&destinationInfo)); diff --git a/Source/WebCore/platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp b/Source/WebCore/platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp index eda12afc7da0b..7f7221bb5e47e 100644 --- a/Source/WebCore/platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp +++ b/Source/WebCore/platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp @@ -90,7 +90,7 @@ struct _WebKitWebAudioSrcPrivate { _WebKitWebAudioSrcPrivate() { - sourcePad = webkitGstGhostPadFromStaticTemplate(&srcTemplate, "src", nullptr); + sourcePad = webkitGstGhostPadFromStaticTemplate(&srcTemplate, "src"_s, nullptr); g_rec_mutex_init(&mutex); } @@ -214,7 +214,7 @@ static void webKitWebAudioSrcConstructed(GObject* object) priv->task = adoptGRef(gst_task_new(reinterpret_cast(webKitWebAudioSrcRenderIteration), src, nullptr)); gst_task_set_lock(priv->task.get(), &priv->mutex); - priv->source = makeGStreamerElement("appsrc", "webaudioSrc"); + priv->source = makeGStreamerElement("appsrc"_s, "webaudioSrc"_s); // Configure the appsrc for minimal latency. g_object_set(priv->source.get(), "block", TRUE, "blocksize", priv->bufferSize, "format", GST_FORMAT_TIME, "is-live", TRUE, nullptr); diff --git a/Source/WebCore/platform/encryptedmedia/CDMUtilities.cpp b/Source/WebCore/platform/encryptedmedia/CDMUtilities.cpp index 077e4fb4ae3e4..78d829d9007cb 100644 --- a/Source/WebCore/platform/encryptedmedia/CDMUtilities.cpp +++ b/Source/WebCore/platform/encryptedmedia/CDMUtilities.cpp @@ -45,17 +45,15 @@ RefPtr parseJSONObject(const SharedBuffer& buffer) return nullptr; // Parse the buffer contents as JSON, returning the root object (if any). - String json { buffer.span() }; - - auto value = JSON::Value::parseJSON(json); + auto value = JSON::Value::parseJSON(byteCast(buffer.span())); if (!value) return nullptr; return value->asObject(); } -}; +} -}; +} #endif // ENABLE(ENCRYPTED_MEDIA) diff --git a/Source/WebCore/platform/glib/UserAgentGLib.cpp b/Source/WebCore/platform/glib/UserAgentGLib.cpp index f0313e9154d39..50d134bf418a1 100644 --- a/Source/WebCore/platform/glib/UserAgentGLib.cpp +++ b/Source/WebCore/platform/glib/UserAgentGLib.cpp @@ -66,7 +66,7 @@ static const String platformVersionForUAString() struct utsname name; uname(&name); - static NeverDestroyed uaOSVersion(makeString(span(name.sysname), ' ', span(name.machine))); + static NeverDestroyed uaOSVersion(makeString(unsafeSpan(name.sysname), ' ', unsafeSpan(name.machine))); return uaOSVersion; #else // We will always claim to be Safari in Intel Mac OS X, since Safari without diff --git a/Source/WebCore/platform/graphics/AV1Utilities.cpp b/Source/WebCore/platform/graphics/AV1Utilities.cpp index 312c32ebbaa76..6daea111b96d0 100644 --- a/Source/WebCore/platform/graphics/AV1Utilities.cpp +++ b/Source/WebCore/platform/graphics/AV1Utilities.cpp @@ -213,18 +213,18 @@ String createAV1CodecParametersString(const AV1CodecConfigurationRecord& configu builder.append("av01"_s); auto appendOneDigit = [&](uint8_t number) { - builder.append(static_cast('0' + number % 10)); + builder.append(static_cast('0' + number % 10)); }; auto appendTwoDigits = [&](uint8_t number) { - builder.append(static_cast('0' + number / 10 % 10)); - builder.append(static_cast('0' + number % 10)); + builder.append(static_cast('0' + number / 10 % 10)); + builder.append(static_cast('0' + number % 10)); }; auto appendThreeDigits = [&](uint8_t number) { - builder.append(static_cast('0' + number / 100 % 10)); - builder.append(static_cast('0' + number / 10 % 10)); - builder.append(static_cast('0' + number % 10)); + builder.append(static_cast('0' + number / 100 % 10)); + builder.append(static_cast('0' + number / 10 % 10)); + builder.append(static_cast('0' + number % 10)); }; // The parameters sample entry 4CC, profile, level, tier, and bitDepth are diff --git a/Source/WebCore/platform/graphics/ColorSerialization.cpp b/Source/WebCore/platform/graphics/ColorSerialization.cpp index 894d36cb8fa7b..9b4262bf7f349 100644 --- a/Source/WebCore/platform/graphics/ColorSerialization.cpp +++ b/Source/WebCore/platform/graphics/ColorSerialization.cpp @@ -592,7 +592,7 @@ String serializationForCSS(SRGBA color, bool useColorFunctionSerializat case 0xFF: return makeString("rgb("_s, red, ", "_s, green, ", "_s, blue, ')'); default: - return makeString("rgba("_s, red, ", "_s, green, ", "_s, blue, ", 0."_s, span(fractionDigitsForFractionalAlphaValue(alpha).data()), ')'); + return makeString("rgba("_s, red, ", "_s, green, ", "_s, blue, ", 0."_s, unsafeSpan(fractionDigitsForFractionalAlphaValue(alpha).data()), ')'); } } diff --git a/Source/WebCore/platform/graphics/FontCascade.cpp b/Source/WebCore/platform/graphics/FontCascade.cpp index 513c41ba81daa..97eb651e5356a 100644 --- a/Source/WebCore/platform/graphics/FontCascade.cpp +++ b/Source/WebCore/platform/graphics/FontCascade.cpp @@ -584,7 +584,7 @@ static inline String normalizeSpacesInternal(std::span char return normalized.toString(); } -String FontCascade::normalizeSpaces(std::span characters) +String FontCascade::normalizeSpaces(std::span characters) { return normalizeSpacesInternal(characters); } @@ -1097,7 +1097,7 @@ bool FontCascade::isCJKIdeographOrSymbol(char32_t c) return isCJKIdeograph(c); } -std::pair FontCascade::expansionOpportunityCountInternal(std::span characters, TextDirection direction, ExpansionBehavior expansionBehavior) +std::pair FontCascade::expansionOpportunityCountInternal(std::span characters, TextDirection direction, ExpansionBehavior expansionBehavior) { unsigned count = 0; bool isAfterExpansion = expansionBehavior.left == ExpansionBehavior::Behavior::Forbid; diff --git a/Source/WebCore/platform/graphics/FontCascade.h b/Source/WebCore/platform/graphics/FontCascade.h index 181becbced7a2..a7df4d5bdfb06 100644 --- a/Source/WebCore/platform/graphics/FontCascade.h +++ b/Source/WebCore/platform/graphics/FontCascade.h @@ -217,8 +217,8 @@ class FontCascade final : public CanMakeWeakPtr, public CanMakeChec enum class CodePath : uint8_t { Auto, Simple, Complex, SimpleWithGlyphOverflow }; WEBCORE_EXPORT CodePath codePath(const TextRun&, std::optional from = std::nullopt, std::optional to = std::nullopt) const; - static CodePath characterRangeCodePath(std::span) { return CodePath::Simple; } - WEBCORE_EXPORT static CodePath characterRangeCodePath(std::span); + static CodePath characterRangeCodePath(std::span) { return CodePath::Simple; } + WEBCORE_EXPORT static CodePath characterRangeCodePath(std::span); bool primaryFontIsSystemFont() const; @@ -252,8 +252,8 @@ class FontCascade final : public CanMakeWeakPtr, public CanMakeChec int offsetForPositionForComplexText(const TextRun&, float position, bool includePartialGlyphs) const; void adjustSelectionRectForComplexText(const TextRun&, LayoutRect& selectionRect, unsigned from, unsigned to) const; - static std::pair expansionOpportunityCountInternal(std::span, TextDirection, ExpansionBehavior); - static std::pair expansionOpportunityCountInternal(std::span, TextDirection, ExpansionBehavior); + static std::pair expansionOpportunityCountInternal(std::span, TextDirection, ExpansionBehavior); + static std::pair expansionOpportunityCountInternal(std::span, TextDirection, ExpansionBehavior); friend struct WidthIterator; friend class ComplexTextController; @@ -304,7 +304,7 @@ class FontCascade final : public CanMakeWeakPtr, public CanMakeChec static bool treatAsZeroWidthSpaceInComplexScript(char32_t c) { return c < space || (c >= deleteCharacter && c < noBreakSpace) || c == softHyphen || c == zeroWidthSpace || (c >= leftToRightMark && c <= rightToLeftMark) || (c >= leftToRightEmbed && c <= rightToLeftOverride) || c == zeroWidthNoBreakSpace || isInvisibleReplacementObjectCharacter(c); } static bool canReceiveTextEmphasis(char32_t); - static inline UChar normalizeSpaces(UChar character) + static inline char16_t normalizeSpaces(char16_t character) { if (treatAsSpace(character)) return space; @@ -315,8 +315,8 @@ class FontCascade final : public CanMakeWeakPtr, public CanMakeChec return character; } - static String normalizeSpaces(std::span); - static String normalizeSpaces(std::span); + static String normalizeSpaces(std::span); + static String normalizeSpaces(std::span); static String normalizeSpaces(StringView); bool useBackslashAsYenSymbol() const { return m_useBackslashAsYenSymbol; } diff --git a/Source/WebCore/platform/graphics/Latin1TextIterator.h b/Source/WebCore/platform/graphics/Latin1TextIterator.h index 55e49d40a0f38..76193683ddf15 100644 --- a/Source/WebCore/platform/graphics/Latin1TextIterator.h +++ b/Source/WebCore/platform/graphics/Latin1TextIterator.h @@ -27,9 +27,9 @@ namespace WebCore { class Latin1TextIterator { public: - // The passed in LChar pointer starts at 'currentIndex'. The iterator operates on the range [currentIndex, lastIndex]. - // 'endCharacter' denotes the maximum length of the UChar array, which might exceed 'lastIndex'. - Latin1TextIterator(std::span characters, unsigned currentIndex, unsigned lastIndex) + // The passed in Latin1Character pointer starts at 'currentIndex'. The iterator operates on the range [currentIndex, lastIndex]. + // 'endCharacter' denotes the maximum length of the char16_t array, which might exceed 'lastIndex'. + Latin1TextIterator(std::span characters, unsigned currentIndex, unsigned lastIndex) : m_characters(characters.data()) , m_currentIndex(currentIndex) , m_originalIndex(currentIndex) @@ -60,17 +60,17 @@ class Latin1TextIterator { m_currentIndex = index; } - const LChar* remainingCharacters() const + const Latin1Character* remainingCharacters() const { auto relativeIndex = m_currentIndex - m_originalIndex; return m_characters + relativeIndex; } unsigned currentIndex() const { return m_currentIndex; } - const LChar* characters() const { return m_characters; } + const Latin1Character* characters() const { return m_characters; } private: - const LChar* const m_characters; + const Latin1Character* const m_characters; unsigned m_currentIndex; const unsigned m_originalIndex; const unsigned m_lastIndex; diff --git a/Source/WebCore/platform/graphics/TextRun.h b/Source/WebCore/platform/graphics/TextRun.h index 443395b660a02..8e63978174421 100644 --- a/Source/WebCore/platform/graphics/TextRun.h +++ b/Source/WebCore/platform/graphics/TextRun.h @@ -116,11 +116,11 @@ class TextRun final : public CanMakeCheckedPtr { return result; } - UChar operator[](unsigned i) const { RELEASE_ASSERT(i < m_text.length()); return m_text[i]; } - std::span span8() const { ASSERT(is8Bit()); return m_text.span8(); } - std::span span16() const { ASSERT(!is8Bit()); return m_text.span16(); } - std::span subspan8(unsigned i) const { return span8().subspan(i); } - std::span subspan16(unsigned i) const { return span16().subspan(i); } + char16_t operator[](unsigned i) const { RELEASE_ASSERT(i < m_text.length()); return m_text[i]; } + std::span span8() const { ASSERT(is8Bit()); return m_text.span8(); } + std::span span16() const { ASSERT(!is8Bit()); return m_text.span16(); } + std::span subspan8(unsigned i) const { return span8().subspan(i); } + std::span subspan16(unsigned i) const { return span16().subspan(i); } bool is8Bit() const { return m_text.is8Bit(); } unsigned length() const { return m_text.length(); } diff --git a/Source/WebCore/platform/graphics/avfoundation/CDMFairPlayStreaming.cpp b/Source/WebCore/platform/graphics/avfoundation/CDMFairPlayStreaming.cpp index bdbf11165b463..95211d8a898bc 100644 --- a/Source/WebCore/platform/graphics/avfoundation/CDMFairPlayStreaming.cpp +++ b/Source/WebCore/platform/graphics/avfoundation/CDMFairPlayStreaming.cpp @@ -92,9 +92,8 @@ static Vector> extractSinfData(const SharedBuffer& buffer) // JSON of the format: "{ sinf: [ ] }" if (buffer.size() > std::numeric_limits::max()) return { }; - String json { buffer.makeContiguous()->span() }; - auto value = JSON::Value::parseJSON(json); + auto value = JSON::Value::parseJSON(byteCast(buffer.makeContiguous()->span())); if (!value) return { }; @@ -214,9 +213,8 @@ std::optional>> CDMPrivateFairPlayStreaming::extractKey // JSON of the format: "{ "codc" : [integer], "mtyp" : [integer], "cont" : "mpts"} }" if (buffer.size() > std::numeric_limits::max()) return { }; - String json { buffer.makeContiguous()->span() }; - auto value = JSON::Value::parseJSON(json); + auto value = JSON::Value::parseJSON(byteCast(buffer.makeContiguous()->span())); if (!value) return { }; diff --git a/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm b/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm index 79cd641b084be..cd564dc81b45a 100644 --- a/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm +++ b/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm @@ -340,7 +340,7 @@ void fail() return nullptr; // Parse the buffer contents as JSON, returning the root object (if any). - return JSON::Value::parseJSON(buffer.makeContiguous()->span()); + return JSON::Value::parseJSON(byteCast(buffer.makeContiguous()->span())); } bool CDMInstanceFairPlayStreamingAVFObjC::supportsPersistableState() diff --git a/Source/WebCore/platform/graphics/cocoa/GraphicsContextGLCocoa.mm b/Source/WebCore/platform/graphics/cocoa/GraphicsContextGLCocoa.mm index 7de3bbba73808..e877997d3590e 100644 --- a/Source/WebCore/platform/graphics/cocoa/GraphicsContextGLCocoa.mm +++ b/Source/WebCore/platform/graphics/cocoa/GraphicsContextGLCocoa.mm @@ -104,8 +104,8 @@ static EGLDisplay initializeEGLDisplay(const GraphicsContextGLAttributes& attrs) } #if ASSERT_ENABLED - const char* clientExtensions = EGL_QueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); - ASSERT(clientExtensions); + auto clientExtensions = unsafeSpan(EGL_QueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS)); + ASSERT(clientExtensions.data()); #endif Vector displayAttributes; @@ -149,9 +149,9 @@ static EGLDisplay initializeEGLDisplay(const GraphicsContextGLAttributes& attrs) } LOG(WebGL, "ANGLE initialised Major: %d Minor: %d", majorVersion, minorVersion); -#if ASSERT_ENABLED && ENABLE(WEBXR) - const char* displayExtensions = EGL_QueryString(display, EGL_EXTENSIONS); - ASSERT(strstr(displayExtensions, "EGL_ANGLE_metal_shared_event_sync")); +#if ASSERT_ENABLED + auto displayExtensions = unsafeSpan(EGL_QueryString(display, EGL_EXTENSIONS)); + ASSERT(WTF::contains(displayExtensions, "EGL_ANGLE_metal_shared_event_sync"_span)); #endif return display; diff --git a/Source/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp b/Source/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp index 271e30a68097f..1ff1dab277ee7 100644 --- a/Source/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp +++ b/Source/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp @@ -494,7 +494,7 @@ static String fontNameMapName(FT_Face face, unsigned id) switch (name.platform_id) { case TT_PLATFORM_MACINTOSH: if (name.encoding_id == TT_MAC_ID_ROMAN) - return String({ name.string, name.string_len }); + return String({ byteCast(name.string), name.string_len }); // FIXME: implement other macintosh encodings. break; case TT_PLATFORM_APPLE_UNICODE: diff --git a/Source/WebCore/platform/graphics/freetype/FontPlatformDataFreeType.cpp b/Source/WebCore/platform/graphics/freetype/FontPlatformDataFreeType.cpp index c51a63adb1599..0e47050460fc6 100644 --- a/Source/WebCore/platform/graphics/freetype/FontPlatformDataFreeType.cpp +++ b/Source/WebCore/platform/graphics/freetype/FontPlatformDataFreeType.cpp @@ -205,7 +205,7 @@ String FontPlatformData::familyName() const { FcChar8* family = nullptr; FcPatternGetString(m_pattern.get(), FC_FAMILY, 0, &family); - return String::fromUTF8(span8(reinterpret_cast(family))); + return byteCast(unsafeSpan(byteCast(family))); } Vector FontPlatformData::variationAxes(ShouldLocalizeAxisNames shouldLocalizeAxisNames) const diff --git a/Source/WebCore/platform/graphics/gstreamer/AudioTrackPrivateGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/AudioTrackPrivateGStreamer.cpp index 762886bf6296e..6cef100713c71 100644 --- a/Source/WebCore/platform/graphics/gstreamer/AudioTrackPrivateGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/AudioTrackPrivateGStreamer.cpp @@ -33,6 +33,7 @@ #include "MediaPlayerPrivateGStreamer.h" #include #include +#include #include namespace WebCore { @@ -134,9 +135,9 @@ void AudioTrackPrivateGStreamer::updateConfigurationFromCaps(GRefPtr&& }); #if GST_CHECK_VERSION(1, 20, 0) - GUniquePtr mimeCodec(gst_codec_utils_caps_get_mime_codec(caps.get())); + auto mimeCodec = GMallocString::unsafeAdoptFromUTF8(gst_codec_utils_caps_get_mime_codec(caps.get())); if (mimeCodec) - configuration.codec = span(mimeCodec.get()); + configuration.codec = mimeCodec.span(); #endif if (areEncryptedCaps(caps.get())) { diff --git a/Source/WebCore/platform/graphics/gstreamer/DMABufVideoSinkGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/DMABufVideoSinkGStreamer.cpp index 5d8d75bbdf6d1..410bd82869c61 100644 --- a/Source/WebCore/platform/graphics/gstreamer/DMABufVideoSinkGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/DMABufVideoSinkGStreamer.cpp @@ -90,7 +90,7 @@ static void webKitDMABufVideoSinkConstructed(GObject* object) WebKitDMABufVideoSink* sink = WEBKIT_DMABUF_VIDEO_SINK(object); - sink->priv->appSink = makeGStreamerElement("appsink", "webkit-dmabuf-video-appsink"); + sink->priv->appSink = makeGStreamerElement("appsink"_s, "webkit-dmabuf-video-appsink"_s); ASSERT(sink->priv->appSink); g_object_set(sink->priv->appSink.get(), "enable-last-sample", FALSE, "emit-signals", TRUE, "max-buffers", 1, nullptr); @@ -195,7 +195,7 @@ bool webKitDMABufVideoSinkIsEnabled() bool webKitDMABufVideoSinkProbePlatform() { - return webkitGstCheckVersion(1, 20, 0) && isGStreamerPluginAvailable("app"); + return webkitGstCheckVersion(1, 20, 0) && isGStreamerPluginAvailable("app"_s); } void webKitDMABufVideoSinkSetMediaPlayerPrivate(WebKitDMABufVideoSink* sink, MediaPlayerPrivateGStreamer* player) diff --git a/Source/WebCore/platform/graphics/gstreamer/GLVideoSinkGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/GLVideoSinkGStreamer.cpp index 4f9b81163aa3c..d389b481a1c90 100644 --- a/Source/WebCore/platform/graphics/gstreamer/GLVideoSinkGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/GLVideoSinkGStreamer.cpp @@ -66,7 +66,7 @@ static void webKitGLVideoSinkConstructed(GObject* object) GST_OBJECT_FLAG_SET(GST_OBJECT_CAST(sink), GST_ELEMENT_FLAG_SINK); gst_bin_set_suppressed_flags(GST_BIN_CAST(sink), static_cast(GST_ELEMENT_FLAG_SOURCE | GST_ELEMENT_FLAG_SINK)); - sink->priv->appSink = makeGStreamerElement("appsink", "webkit-gl-video-appsink"); + sink->priv->appSink = makeGStreamerElement("appsink"_s, "webkit-gl-video-appsink"_s); ASSERT(sink->priv->appSink); g_object_set(sink->priv->appSink.get(), "enable-last-sample", FALSE, "emit-signals", TRUE, "max-buffers", 1, nullptr); @@ -81,8 +81,8 @@ static void webKitGLVideoSinkConstructed(GObject* object) if (imxVideoConvertG2D) gst_bin_add(GST_BIN_CAST(sink), imxVideoConvertG2D); - GstElement* upload = makeGStreamerElement("glupload", nullptr); - GstElement* colorconvert = makeGStreamerElement("glcolorconvert", nullptr); + GstElement* upload = makeGStreamerElement("glupload"_s); + GstElement* colorconvert = makeGStreamerElement("glcolorconvert"_s); ASSERT(upload); ASSERT(colorconvert); @@ -131,9 +131,10 @@ static GstStateChangeReturn webKitGLVideoSinkChangeState(GstElement* element, Gs case GST_STATE_CHANGE_NULL_TO_READY: case GST_STATE_CHANGE_READY_TO_READY: case GST_STATE_CHANGE_READY_TO_PAUSED: { - if (!setGstElementGLContext(element, GST_GL_DISPLAY_CONTEXT_TYPE)) + static ASCIILiteral gstGlDisplayContextyType = ASCIILiteral::fromLiteralUnsafe(GST_GL_DISPLAY_CONTEXT_TYPE); + if (!setGstElementGLContext(element, gstGlDisplayContextyType)) return GST_STATE_CHANGE_FAILURE; - if (!setGstElementGLContext(element, "gst.gl.app_context")) + if (!setGstElementGLContext(element, "gst.gl.app_context"_s)) return GST_STATE_CHANGE_FAILURE; break; } @@ -195,7 +196,7 @@ bool webKitGLVideoSinkProbePlatform() return false; } - return isGStreamerPluginAvailable("app") && isGStreamerPluginAvailable("opengl"); + return isGStreamerPluginAvailable("app"_s) && isGStreamerPluginAvailable("opengl"_s); } #undef GST_CAT_DEFAULT diff --git a/Source/WebCore/platform/graphics/gstreamer/GStreamerAudioMixer.cpp b/Source/WebCore/platform/graphics/gstreamer/GStreamerAudioMixer.cpp index 8b30e0f14b6a3..c544db374fb33 100644 --- a/Source/WebCore/platform/graphics/gstreamer/GStreamerAudioMixer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/GStreamerAudioMixer.cpp @@ -32,7 +32,7 @@ GST_DEBUG_CATEGORY_STATIC(webkit_media_gst_audio_mixer_debug); bool GStreamerAudioMixer::isAvailable() { - return isGStreamerPluginAvailable("inter") && isGStreamerPluginAvailable("audiomixer"); + return isGStreamerPluginAvailable("inter"_s) && isGStreamerPluginAvailable("audiomixer"_s); } GStreamerAudioMixer& GStreamerAudioMixer::singleton() @@ -48,7 +48,7 @@ GStreamerAudioMixer::GStreamerAudioMixer() registerActivePipeline(m_pipeline); connectSimpleBusMessageCallback(m_pipeline.get()); - m_mixer = makeGStreamerElement("audiomixer", nullptr); + m_mixer = makeGStreamerElement("audiomixer"_s); auto* audioSink = createAutoAudioSink({ }); gst_bin_add_many(GST_BIN_CAST(m_pipeline.get()), m_mixer.get(), audioSink, nullptr); @@ -88,13 +88,14 @@ void GStreamerAudioMixer::ensureState(GstStateChange stateChange) GRefPtr GStreamerAudioMixer::registerProducer(GstElement* interaudioSink) { - GstElement* src = makeGStreamerElement("interaudiosrc", nullptr); + GstElement* src = makeGStreamerElement("interaudiosrc"_s, unsafeSpan(GST_ELEMENT_NAME(interaudioSink))); + g_object_set(src, "channel", GST_ELEMENT_NAME(interaudioSink), nullptr); g_object_set(interaudioSink, "channel", GST_ELEMENT_NAME(interaudioSink), nullptr); auto bin = gst_bin_new(nullptr); - auto audioResample = makeGStreamerElement("audioresample", nullptr); - auto audioConvert = makeGStreamerElement("audioconvert", nullptr); + auto audioResample = makeGStreamerElement("audioresample"_s); + auto audioConvert = makeGStreamerElement("audioconvert"_s); gst_bin_add_many(GST_BIN_CAST(bin), audioResample, audioConvert, nullptr); gst_element_link(audioConvert, audioResample); diff --git a/Source/WebCore/platform/graphics/gstreamer/GStreamerAudioMixer.h b/Source/WebCore/platform/graphics/gstreamer/GStreamerAudioMixer.h index a1e216fe30176..eed44195a2b2f 100644 --- a/Source/WebCore/platform/graphics/gstreamer/GStreamerAudioMixer.h +++ b/Source/WebCore/platform/graphics/gstreamer/GStreamerAudioMixer.h @@ -23,6 +23,7 @@ #include "GRefPtrGStreamer.h" #include +#include namespace WebCore { diff --git a/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.cpp b/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.cpp index 1157a1e720430..7bc83361a193b 100644 --- a/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.cpp @@ -48,6 +48,8 @@ #include #include #include +#include +#include #include #include #include @@ -111,17 +113,15 @@ namespace WebCore { static GstClockTime s_webkitGstInitTime; -GstPad* webkitGstGhostPadFromStaticTemplate(GstStaticPadTemplate* staticPadTemplate, const gchar* name, GstPad* target) +WARN_UNUSED_RETURN GstPad* webkitGstGhostPadFromStaticTemplate(GstStaticPadTemplate* staticPadTemplate, CStringView name, GstPad* target) { GstPad* pad; - GstPadTemplate* padTemplate = gst_static_pad_template_get(staticPadTemplate); + GRefPtr padTemplate = gst_static_pad_template_get(staticPadTemplate); if (target) - pad = gst_ghost_pad_new_from_template(name, target, padTemplate); + pad = gst_ghost_pad_new_from_template(name.utf8(), target, padTemplate.get()); else - pad = gst_ghost_pad_new_no_target_from_template(name, padTemplate); - - gst_object_unref(padTemplate); + pad = gst_ghost_pad_new_no_target_from_template(name.utf8(), padTemplate.get()); return pad; } @@ -237,35 +237,35 @@ bool getSampleVideoInfo(GstSample* sample, GstVideoInfo& videoInfo) std::optional getStreamIdFromPad(const GRefPtr& pad) { - GUniquePtr streamIdAsCharacters(gst_pad_get_stream_id(pad.get())); - if (!streamIdAsCharacters) { + auto streamIdAsString = GMallocString::unsafeAdoptFromUTF8(gst_pad_get_stream_id(pad.get())); + if (!streamIdAsString) { GST_DEBUG_OBJECT(pad.get(), "Failed to get stream-id from pad"); return std::nullopt; } - std::optional streamId(parseStreamId(StringView::fromLatin1(streamIdAsCharacters.get()))); + std::optional streamId(parseStreamId(streamIdAsString.span())); if (!streamId) - GST_WARNING_OBJECT(pad.get(), "Got invalid stream-id from pad: %s", streamIdAsCharacters.get()); + GST_WARNING_OBJECT(pad.get(), "Got invalid stream-id from pad: %s", streamIdAsString.utf8()); return streamId; } std::optional getStreamIdFromStream(const GRefPtr& stream) { - const gchar* streamIdAsCharacters = gst_stream_get_stream_id(stream.get()); - if (!streamIdAsCharacters) { + auto streamIdAsString = CStringView::unsafeFromUTF8(gst_stream_get_stream_id(stream.get())); + if (!streamIdAsString) { GST_DEBUG_OBJECT(stream.get(), "Failed to get stream-id from stream"); return std::nullopt; } - std::optional streamId(parseStreamId(StringView::fromLatin1(streamIdAsCharacters))); + std::optional streamId(parseStreamId(streamIdAsString.span())); if (!streamId) - GST_WARNING_OBJECT(stream.get(), "Got invalid stream-id from stream: %s", streamIdAsCharacters); + GST_WARNING_OBJECT(stream.get(), "Got invalid stream-id from stream: %s", streamIdAsString.utf8()); return streamId; } -std::optional parseStreamId(StringView stringId) +std::optional parseStreamId(const String& stringId) { auto maybeUUID = WTF::UUID::parse(stringId); if (maybeUUID.has_value()) @@ -281,7 +281,7 @@ std::optional parseStreamId(StringView stringId) return parseIntegerAllowingTrailingJunk(stringId.substring(position + 1)); } -StringView capsMediaType(const GstCaps* caps) +CStringView capsMediaType(const GstCaps* caps) { ASSERT(caps); GstStructure* structure = gst_caps_get_structure(caps, 0); @@ -299,14 +299,14 @@ StringView capsMediaType(const GstCaps* caps) return gstStructureGetName(structure); } -bool doCapsHaveType(const GstCaps* caps, const char* type) +bool doCapsHaveType(const GstCaps* caps, ASCIILiteral type) { auto mediaType = capsMediaType(caps); if (!mediaType) { GST_WARNING("Failed to get MediaType"); return false; } - return mediaType.startsWith(span(type)); + return startsWith(mediaType.span(), type); } bool areEncryptedCaps(const GstCaps* caps) @@ -333,13 +333,12 @@ void setGStreamerOptionsFromUIProcess(Vector&& options) Vector extractGStreamerOptionsFromCommandLine() { - GUniqueOutPtr contents; - gsize length; - if (!g_file_get_contents("/proc/self/cmdline", &contents.outPtr(), &length, nullptr)) + auto contents = gFileGetContents("/proc/self/cmdline"_s); + if (!contents) return { }; Vector options; - auto optionsString = String::fromUTF8(std::span(contents.get(), length)); + auto optionsString = String::fromUTF8(contents->span()); optionsString.split('\0', [&options](StringView item) { if (item.startsWith("--gst"_s)) options.append(item.toString()); @@ -397,8 +396,8 @@ bool ensureGStreamerInitialized() GST_DEBUG_CATEGORY_INIT(webkit_gst_common_debug, "webkitcommon", 0, "WebKit Common utilities"); if (isFastMallocEnabled()) { - const char* disableFastMalloc = getenv("WEBKIT_GST_DISABLE_FAST_MALLOC"); - if (!disableFastMalloc || !strcmp(disableFastMalloc, "0")) + auto disableFastMalloc = CStringView::unsafeFromUTF8(getenv("WEBKIT_GST_DISABLE_FAST_MALLOC")); + if (!disableFastMalloc || disableFastMalloc == "0"_s) gst_allocator_set_default(GST_ALLOCATOR(g_object_new(gst_allocator_fast_malloc_get_type(), nullptr))); } @@ -495,16 +494,16 @@ void registerWebKitGStreamerElements() // Prevent decodebin(3) from auto-plugging hlsdemux if it was disabled. UAs should be able // to fallback to MSE when this happens. - const char* hlsSupport = g_getenv("WEBKIT_GST_ENABLE_HLS_SUPPORT"); - if (!hlsSupport || !g_strcmp0(hlsSupport, "0")) { + auto hlsSupport = CStringView::unsafeFromUTF8(g_getenv("WEBKIT_GST_ENABLE_HLS_SUPPORT")); + if (!hlsSupport || hlsSupport == "0"_s) { if (auto factory = adoptGRef(gst_element_factory_find("hlsdemux"))) gst_plugin_feature_set_rank(GST_PLUGIN_FEATURE_CAST(factory.get()), GST_RANK_NONE); } // Prevent decodebin(3) from auto-plugging dashdemux if it was disabled. UAs should be able // to fallback to MSE when this happens. - const char* dashSupport = g_getenv("WEBKIT_GST_ENABLE_DASH_SUPPORT"); - if (!dashSupport || !g_strcmp0(dashSupport, "0")) { + auto dashSupport = CStringView::unsafeFromUTF8(g_getenv("WEBKIT_GST_ENABLE_DASH_SUPPORT")); + if (!dashSupport || dashSupport == "0"_s) { if (auto factory = adoptGRef(gst_element_factory_find("dashdemux"))) gst_plugin_feature_set_rank(GST_PLUGIN_FEATURE_CAST(factory.get()), GST_RANK_NONE); } @@ -571,16 +570,16 @@ static HashMap>& activePipelinesMap() void registerActivePipeline(const GRefPtr& pipeline) { - GUniquePtr name(gst_object_get_name(GST_OBJECT_CAST(pipeline.get()))); + auto name = GMallocString::unsafeAdoptFromUTF8(gst_object_get_name(GST_OBJECT_CAST(pipeline.get()))); Locker locker { s_activePipelinesMapLock }; - activePipelinesMap().add(span(name.get()), GRefPtr(pipeline)); + activePipelinesMap().add(name.span(), GRefPtr(pipeline)); } void unregisterPipeline(const GRefPtr& pipeline) { - GUniquePtr name(gst_object_get_name(GST_OBJECT_CAST(pipeline.get()))); + auto name = GMallocString::unsafeAdoptFromUTF8(gst_object_get_name(GST_OBJECT_CAST(pipeline.get()))); Locker locker { s_activePipelinesMapLock }; - activePipelinesMap().remove(span(name.get())); + activePipelinesMap().remove(name.span()); } void WebCoreLogObserver::didLogMessage(const WTFLogChannel& channel, WTFLogLevel level, Vector&& values) @@ -654,7 +653,7 @@ void deinitializeGStreamer() auto activeTracers = gst_tracing_get_active_tracers(); while (activeTracers) { auto tracer = adoptGRef(GST_TRACER_CAST(activeTracers->data)); - if (!isLeaksTracerActive && !g_strcmp0(G_OBJECT_TYPE_NAME(G_OBJECT(tracer.get())), "GstLeaksTracer")) + if (!isLeaksTracerActive && equal(unsafeSpan(G_OBJECT_TYPE_NAME(G_OBJECT(tracer.get()))), "GstLeaksTracer"_s)) isLeaksTracerActive = true; activeTracers = g_list_delete_link(activeTracers, activeTracers); } @@ -676,12 +675,12 @@ void deinitializeGStreamer() gst_deinit(); } -unsigned getGstPlayFlag(const char* nick) +unsigned getGstPlayFlag(ASCIILiteral nick) { static GFlagsClass* flagsClass = static_cast(g_type_class_ref(g_type_from_name("GstPlayFlags"))); ASSERT(flagsClass); - GFlagsValue* flag = g_flags_get_value_by_nick(flagsClass, nick); + GFlagsValue* flag = g_flags_get_value_by_nick(flagsClass, nick.characters()); if (!flag) return 0; @@ -892,7 +891,7 @@ void connectSimpleBusMessageCallback(GstElement* pipeline, Function GstMappedBuffer::createVector() const return std::span { data(), size() }; } -bool isGStreamerPluginAvailable(const char* name) +bool isGStreamerPluginAvailable(ASCIILiteral name) { - GRefPtr plugin = adoptGRef(gst_registry_find_plugin(gst_registry_get(), name)); + GRefPtr plugin = adoptGRef(gst_registry_find_plugin(gst_registry_get(), name.characters())); if (!plugin) - GST_WARNING("Plugin %s not found. Please check your GStreamer installation", name); + GST_WARNING("Plugin %s not found. Please check your GStreamer installation", name.characters()); return plugin; } @@ -952,7 +951,7 @@ bool gstElementFactoryEquals(GstElement* element, ASCIILiteral name) GstElement* createAutoAudioSink(const String& role) { - auto* audioSink = makeGStreamerElement("autoaudiosink", nullptr); + auto* audioSink = makeGStreamerElement("autoaudiosink"_s); g_signal_connect_data(audioSink, "child-added", G_CALLBACK(+[](GstChildProxy*, GObject* object, gchar*, gpointer userData) { auto* role = reinterpret_cast(userData); auto* objectClass = G_OBJECT_GET_CLASS(object); @@ -1038,33 +1037,23 @@ GstBuffer* gstBufferNewWrappedFast(void* data, size_t length) return gst_buffer_new_wrapped_full(static_cast(0), data, length, 0, length, data, fastFree); } -GstElement* makeGStreamerElement(const char* factoryName, const char* name) +GstElement* /* (transfer floating) */ makeGStreamerElement(CStringView factoryName, const String& name) { static Lock lock; - static Vector cache WTF_GUARDED_BY_LOCK(lock); - auto* element = gst_element_factory_make(factoryName, name); + static Vector cache WTF_GUARDED_BY_LOCK(lock); + auto* element = gst_element_factory_make(factoryName.utf8(), name.isEmpty() ? nullptr : name.ascii().data()); Locker locker { lock }; - if (!element && !cache.contains(factoryName)) { - cache.append(factoryName); - WTFLogAlways("GStreamer element %s not found. Please install it", factoryName); + if (!element) { + String factoryNameString(factoryName.span()); + if (!cache.contains(factoryNameString)) { + cache.append(WTFMove(factoryNameString)); + WTFLogAlways("GStreamer element %s not found. Please install it", factoryName.utf8()); + ASSERT_NOT_REACHED_WITH_MESSAGE("GStreamer element %s not found. Please install it", factoryName.utf8()); + } } return element; } -GstElement* makeGStreamerBin(const char* description, bool ghostUnlinkedPads) -{ - static Lock lock; - static Vector cache WTF_GUARDED_BY_LOCK(lock); - GUniqueOutPtr error; - auto* bin = gst_parse_bin_from_description(description, ghostUnlinkedPads, &error.outPtr()); - Locker locker { lock }; - if (!bin && !cache.contains(description)) { - cache.append(description); - WTFLogAlways("Unable to create bin for description: \"%s\". Error: %s", description, error->message); - } - return bin; -} - #if USE(GSTREAMER_WEBRTC) static ASCIILiteral webrtcStatsTypeName(int value) { @@ -1104,13 +1093,7 @@ static ASCIILiteral webrtcStatsTypeName(int value) #endif template -std::optional gstStructureGet(const GstStructure* structure, ASCIILiteral key) -{ - return gstStructureGet(structure, StringView { key }); -} - -template -std::optional gstStructureGet(const GstStructure* structure, StringView key) +std::optional gstStructureGet(const GstStructure* structure, CStringView key) { if (!structure) { ASSERT_NOT_REACHED_WITH_MESSAGE("tried to access a field of a null GstStructure"); @@ -1118,25 +1101,24 @@ std::optional gstStructureGet(const GstStructure* structure, StringView key) } T value; - auto strKey = key.toStringWithoutCopying(); if constexpr(std::is_same_v) { - if (gst_structure_get_int(structure, strKey.ascii().data(), &value)) + if (gst_structure_get_int(structure, key.utf8(), &value)) return value; } else if constexpr(std::is_same_v) { - if (gst_structure_get_int64(structure, strKey.ascii().data(), &value)) + if (gst_structure_get_int64(structure, key.utf8(), &value)) return value; } else if constexpr(std::is_same_v) { - if (gst_structure_get_uint(structure, strKey.ascii().data(), &value)) + if (gst_structure_get_uint(structure, key.utf8(), &value)) return value; } else if constexpr(std::is_same_v) { - if (gst_structure_get_uint64(structure, strKey.ascii().data(), &value)) + if (gst_structure_get_uint64(structure, key.utf8(), &value)) return value; } else if constexpr(std::is_same_v) { - if (gst_structure_get_double(structure, strKey.ascii().data(), &value)) + if (gst_structure_get_double(structure, key.utf8(), &value)) return value; } else if constexpr(std::is_same_v) { gboolean gstValue; - if (gst_structure_get_boolean(structure, strKey.ascii().data(), &gstValue)) { + if (gst_structure_get_boolean(structure, key.utf8(), &gstValue)) { value = gstValue; return value; } @@ -1145,60 +1127,45 @@ std::optional gstStructureGet(const GstStructure* structure, StringView key) return std::nullopt; } -template std::optional gstStructureGet(const GstStructure*, ASCIILiteral key); -template std::optional gstStructureGet(const GstStructure*, ASCIILiteral key); -template std::optional gstStructureGet(const GstStructure*, ASCIILiteral key); -template std::optional gstStructureGet(const GstStructure*, ASCIILiteral key); -template std::optional gstStructureGet(const GstStructure*, ASCIILiteral key); -template std::optional gstStructureGet(const GstStructure*, ASCIILiteral key); - -template std::optional gstStructureGet(const GstStructure*, StringView key); -template std::optional gstStructureGet(const GstStructure*, StringView key); -template std::optional gstStructureGet(const GstStructure*, StringView key); -template std::optional gstStructureGet(const GstStructure*, StringView key); -template std::optional gstStructureGet(const GstStructure*, StringView key); -template std::optional gstStructureGet(const GstStructure*, StringView key); +template std::optional gstStructureGet(const GstStructure*, CStringView key); +template std::optional gstStructureGet(const GstStructure*, CStringView key); +template std::optional gstStructureGet(const GstStructure*, CStringView key); +template std::optional gstStructureGet(const GstStructure*, CStringView key); +template std::optional gstStructureGet(const GstStructure*, CStringView key); +template std::optional gstStructureGet(const GstStructure*, CStringView key); -StringView gstStructureGetString(const GstStructure* structure, ASCIILiteral key) +CStringView gstStructureGetString(const GstStructure* structure, CStringView key) { if (!structure) { ASSERT_NOT_REACHED_WITH_MESSAGE("tried to access a field of a null GstStructure"); return { }; } - return gstStructureGetString(structure, StringView { key }); -} - -StringView gstStructureGetString(const GstStructure* structure, StringView key) -{ - if (!structure) { - ASSERT_NOT_REACHED_WITH_MESSAGE("tried to access a field of a null GstStructure"); + const GValue* value = gst_structure_get_value(structure, key.utf8()); + if (!value || !G_VALUE_HOLDS_STRING(value)) return { }; - } - - auto utf8String = key.utf8(); - return StringView::fromLatin1(gst_structure_get_string(structure, utf8String.data())); + return CStringView::unsafeFromUTF8(g_value_get_string(value)); } -StringView gstStructureGetName(const GstStructure* structure) +CStringView gstStructureGetName(const GstStructure* structure) { if (!structure) { ASSERT_NOT_REACHED_WITH_MESSAGE("tried to access a field of a null GstStructure"); return { }; } - return StringView::fromLatin1(gst_structure_get_name(structure)); + return CStringView::unsafeFromUTF8(gst_structure_get_name(structure)); } template -Vector gstStructureGetArray(const GstStructure* structure, ASCIILiteral key) +Vector gstStructureGetArray(const GstStructure* structure, CStringView key) { static_assert(std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v); Vector result; if (!structure) return result; - const GValue* array = gst_structure_get_value(structure, key.characters()); + const GValue* array = gst_structure_get_value(structure, key.utf8()); if (!GST_VALUE_HOLDS_ARRAY (array)) return result; unsigned size = gst_value_array_get_size(array); @@ -1220,7 +1187,7 @@ Vector gstStructureGetArray(const GstStructure* structure, ASCIILiteral key) return result; } -template Vector gstStructureGetArray(const GstStructure*, ASCIILiteral key); +template Vector gstStructureGetArray(const GstStructure*, CStringView key); static RefPtr gstStructureToJSON(const GstStructure*); @@ -1286,7 +1253,7 @@ static std::optional> gstStructureValueToJSON(const GValue* } if (valueType == G_TYPE_STRING) - return JSON::Value::create(makeString(span(g_value_get_string(value))))->asValue(); + return JSON::Value::create(String(byteCast(unsafeSpan(g_value_get_string(value)))))->asValue(); #if USE(GSTREAMER_WEBRTC) if (valueType == GST_TYPE_WEBRTC_STATS_TYPE) { @@ -1308,10 +1275,8 @@ static RefPtr gstStructureToJSON(const GstStructure* structure) return nullptr; gstStructureForeach(structure, [&](auto id, auto value) -> bool { - if (auto jsonValue = gstStructureValueToJSON(value)) { - auto fieldId = gstIdToString(id); - resultValue->setValue(fieldId.toString(), jsonValue->releaseNonNull()); - } + if (auto jsonValue = gstStructureValueToJSON(value)) + resultValue->setValue(gstIdToString(id), jsonValue->releaseNonNull()); return TRUE; }); return resultValue; @@ -1343,7 +1308,7 @@ PlatformVideoColorSpace videoColorSpaceFromInfo(const GstVideoInfo& info) { ensureGStreamerInitialized(); #ifndef GST_DISABLE_GST_DEBUG - GUniquePtr colorimetry(gst_video_colorimetry_to_string(&GST_VIDEO_INFO_COLORIMETRY(&info))); + auto colorimetry = GMallocString::unsafeAdoptFromUTF8(gst_video_colorimetry_to_string(&GST_VIDEO_INFO_COLORIMETRY(&info))); #endif PlatformVideoColorSpace colorSpace; switch (GST_VIDEO_INFO_COLORIMETRY(&info).matrix) { @@ -1370,7 +1335,7 @@ PlatformVideoColorSpace videoColorSpaceFromInfo(const GstVideoInfo& info) break; default: #ifndef GST_DISABLE_GST_DEBUG - GST_WARNING("Unhandled colorspace matrix from %s", colorimetry.get()); + GST_WARNING("Unhandled colorspace matrix from %s", colorimetry.utf8()); #endif break; } @@ -1420,7 +1385,7 @@ PlatformVideoColorSpace videoColorSpaceFromInfo(const GstVideoInfo& info) break; default: #ifndef GST_DISABLE_GST_DEBUG - GST_WARNING("Unhandled colorspace transfer from %s", colorimetry.get()); + GST_WARNING("Unhandled colorspace transfer from %s", colorimetry.utf8()); #endif break; } @@ -1461,7 +1426,7 @@ PlatformVideoColorSpace videoColorSpaceFromInfo(const GstVideoInfo& info) break; default: #ifndef GST_DISABLE_GST_DEBUG - GST_WARNING("Unhandled colorspace primaries from %s", colorimetry.get()); + GST_WARNING("Unhandled colorspace primaries from %s", colorimetry.utf8()); #endif break; } @@ -1603,69 +1568,69 @@ void fillVideoInfoColorimetryFromColorSpace(GstVideoInfo* info, const PlatformVi void configureAudioDecoderForHarnessing(const GRefPtr& element) { - if (gstObjectHasProperty(element.get(), "max-errors")) + if (gstObjectHasProperty(element.get(), "max-errors"_s)) g_object_set(element.get(), "max-errors", 0, nullptr); // rawaudioparse-specific: - if (gstObjectHasProperty(element.get(), "use-sink-caps")) + if (gstObjectHasProperty(element.get(), "use-sink-caps"_s)) g_object_set(element.get(), "use-sink-caps", TRUE, nullptr); } void configureVideoDecoderForHarnessing(const GRefPtr& element) { - if (gstObjectHasProperty(element.get(), "max-threads")) + if (gstObjectHasProperty(element.get(), "max-threads"_s)) g_object_set(element.get(), "max-threads", 1, nullptr); - if (gstObjectHasProperty(element.get(), "max-errors")) + if (gstObjectHasProperty(element.get(), "max-errors"_s)) g_object_set(element.get(), "max-errors", 0, nullptr); // avdec-specific: - if (gstObjectHasProperty(element.get(), "std-compliance")) + if (gstObjectHasProperty(element.get(), "std-compliance"_s)) gst_util_set_object_arg(G_OBJECT(element.get()), "std-compliance", "strict"); - if (gstObjectHasProperty(element.get(), "output-corrupt")) + if (gstObjectHasProperty(element.get(), "output-corrupt"_s)) g_object_set(element.get(), "output-corrupt", FALSE, nullptr); // dav1ddec-specific: - if (gstObjectHasProperty(element.get(), "n-threads")) + if (gstObjectHasProperty(element.get(), "n-threads"_s)) g_object_set(element.get(), "n-threads", 1, nullptr); } void configureMediaStreamVideoDecoder(GstElement* element) { - if (gstObjectHasProperty(element, "automatic-request-sync-points")) + if (gstObjectHasProperty(element, "automatic-request-sync-points"_s)) g_object_set(element, "automatic-request-sync-points", TRUE, nullptr); - if (gstObjectHasProperty(element, "discard-corrupted-frames")) + if (gstObjectHasProperty(element, "discard-corrupted-frames"_s)) g_object_set(element, "discard-corrupted-frames", TRUE, nullptr); - if (gstObjectHasProperty(element, "output-corrupt")) + if (gstObjectHasProperty(element, "output-corrupt"_s)) g_object_set(element, "output-corrupt", FALSE, nullptr); - if (gstObjectHasProperty(element, "max-errors")) + if (gstObjectHasProperty(element, "max-errors"_s)) g_object_set(element, "max-errors", -1, nullptr); } void configureVideoRTPDepayloader(GstElement* element) { - if (gstObjectHasProperty(element, "request-keyframe")) + if (gstObjectHasProperty(element, "request-keyframe"_s)) g_object_set(element, "request-keyframe", TRUE, nullptr); - if (gstObjectHasProperty(element, "wait-for-keyframe")) + if (gstObjectHasProperty(element, "wait-for-keyframe"_s)) g_object_set(element, "wait-for-keyframe", TRUE, nullptr); } -static bool gstObjectHasProperty(GstObject* gstObject, const char* name) +static bool gstObjectHasProperty(GstObject* gstObject, ASCIILiteral name) { - return g_object_class_find_property(G_OBJECT_GET_CLASS(gstObject), name); + return g_object_class_find_property(G_OBJECT_GET_CLASS(gstObject), name.characters()); } -bool gstObjectHasProperty(GstElement* element, const char* name) +bool gstObjectHasProperty(GstElement* element, ASCIILiteral name) { return gstObjectHasProperty(GST_OBJECT_CAST(element), name); } -bool gstObjectHasProperty(GstPad* pad, const char* name) +bool gstObjectHasProperty(GstPad* pad, ASCIILiteral name) { return gstObjectHasProperty(GST_OBJECT_CAST(pad), name); } @@ -1733,12 +1698,12 @@ bool gstStructureMapInPlace(GstStructure* structure, Function(unsafeSpan(gst_id_str_as_str(id))); #else - return StringView::fromLatin1(g_quark_to_string(id)); + return byteCast(unsafeSpan(g_quark_to_string(id))); #endif } @@ -1801,15 +1766,14 @@ GRefPtr buildDMABufCaps() #if GST_CHECK_VERSION(1, 24, 0) gst_caps_set_simple(caps.get(), "format", G_TYPE_STRING, "DMA_DRM", nullptr); - static const char* formats = g_getenv("WEBKIT_GST_DMABUF_FORMATS"); - if (formats && *formats) { - auto formatsString = StringView::fromLatin1(formats); + auto formats = CStringView::unsafeFromUTF8(g_getenv("WEBKIT_GST_DMABUF_FORMATS")); + if (!formats.isEmpty()) { GValue drmSupportedFormats = G_VALUE_INIT; g_value_init(&drmSupportedFormats, GST_TYPE_LIST); - for (auto token : formatsString.split(',')) { + for (auto token : String(formats.span()).split(',')) { GValue value = G_VALUE_INIT; g_value_init(&value, G_TYPE_STRING); - g_value_set_string(&value, token.toStringWithoutCopying().ascii().data()); + g_value_set_string(&value, token.utf8().data()); gst_value_list_append_and_take_value(&drmSupportedFormats, &value); } gst_caps_set_value(caps.get(), "drm-format", &drmSupportedFormats); @@ -1856,7 +1820,7 @@ GRefPtr buildDMABufCaps() #endif // USE(GBM) #if USE(GSTREAMER_GL) -static std::optional> requestGLContext(const char* contextType) +static std::optional> requestGLContext(ASCIILiteral contextType) { auto& sharedDisplay = PlatformDisplay::sharedDisplay(); auto* gstGLDisplay = sharedDisplay.gstGLDisplay(); @@ -1865,13 +1829,13 @@ static std::optional> requestGLContext(const char* contextTy if (!gstGLDisplay || !gstGLContext) return std::nullopt; - if (!g_strcmp0(contextType, GST_GL_DISPLAY_CONTEXT_TYPE)) { + if (contextType == ASCIILiteral::fromLiteralUnsafe(GST_GL_DISPLAY_CONTEXT_TYPE)) { GRefPtr displayContext = adoptGRef(gst_context_new(GST_GL_DISPLAY_CONTEXT_TYPE, FALSE)); gst_context_set_gl_display(displayContext.get(), gstGLDisplay); return displayContext; } - if (!g_strcmp0(contextType, "gst.gl.app_context")) { + if (contextType == "gst.gl.app_context"_s) { GRefPtr appContext = adoptGRef(gst_context_new("gst.gl.app_context", FALSE)); GstStructure* structure = gst_context_writable_structure(appContext.get()); gst_structure_set(structure, "context", GST_TYPE_GL_CONTEXT, gstGLContext, nullptr); @@ -1881,9 +1845,9 @@ static std::optional> requestGLContext(const char* contextTy return std::nullopt; } -bool setGstElementGLContext(GstElement* element, const char* contextType) +bool setGstElementGLContext(GstElement* element, ASCIILiteral contextType) { - GRefPtr oldContext = adoptGRef(gst_element_get_context(element, contextType)); + GRefPtr oldContext = adoptGRef(gst_element_get_context(element, contextType.characters())); if (!oldContext) { auto newContext = requestGLContext(contextType); if (!newContext) diff --git a/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.h b/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.h index 6818212332643..b9dd17d4b55b9 100644 --- a/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.h +++ b/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.h @@ -30,6 +30,7 @@ #include #include #include +#include namespace WebCore { @@ -62,21 +63,21 @@ inline bool webkitGstCheckVersion(guint major, guint minor, guint micro) return true; } -#define GST_VIDEO_CAPS_TYPE_PREFIX "video/" -#define GST_AUDIO_CAPS_TYPE_PREFIX "audio/" -#define GST_TEXT_CAPS_TYPE_PREFIX "text/" +#define GST_VIDEO_CAPS_TYPE_PREFIX "video/"_s +#define GST_AUDIO_CAPS_TYPE_PREFIX "audio/"_s +#define GST_TEXT_CAPS_TYPE_PREFIX "text/"_s -GstPad* webkitGstGhostPadFromStaticTemplate(GstStaticPadTemplate*, const gchar* name, GstPad* target); +WARN_UNUSED_RETURN GstPad* webkitGstGhostPadFromStaticTemplate(GstStaticPadTemplate*, CStringView name, GstPad* target); #if ENABLE(VIDEO) bool getVideoSizeAndFormatFromCaps(const GstCaps*, WebCore::IntSize&, GstVideoFormat&, int& pixelAspectRatioNumerator, int& pixelAspectRatioDenominator, int& stride); std::optional getVideoResolutionFromCaps(const GstCaps*); bool getSampleVideoInfo(GstSample*, GstVideoInfo&); #endif -StringView capsMediaType(const GstCaps*); +CStringView capsMediaType(const GstCaps*); std::optional getStreamIdFromPad(const GRefPtr&); std::optional getStreamIdFromStream(const GRefPtr&); -std::optional parseStreamId(StringView stringId); -bool doCapsHaveType(const GstCaps*, const char*); +std::optional parseStreamId(const String& stringId); +bool doCapsHaveType(const GstCaps*, ASCIILiteral); bool areEncryptedCaps(const GstCaps*); Vector extractGStreamerOptionsFromCommandLine(); void setGStreamerOptionsFromUIProcess(Vector&&); @@ -86,8 +87,8 @@ void registerWebKitGStreamerElements(); void registerWebKitGStreamerVideoEncoder(); void deinitializeGStreamer(); -unsigned getGstPlayFlag(const char* nick); -uint64_t toGstUnsigned64Time(const MediaTime&); +unsigned getGstPlayFlag(ASCIILiteral nick); +uint64_t toGstUnsigned64Time(const WTF::MediaTime&); inline GstClockTime toGstClockTime(const MediaTime& mediaTime) { @@ -269,7 +270,7 @@ void disconnectSimpleBusMessageCallback(GstElement*); enum class GstVideoDecoderPlatform { ImxVPU, Video4Linux, OpenMAX }; -bool isGStreamerPluginAvailable(const char* name); +bool isGStreamerPluginAvailable(ASCIILiteral name); bool gstElementFactoryEquals(GstElement*, ASCIILiteral name); GstElement* createAutoAudioSink(const String& role); @@ -282,21 +283,17 @@ bool webkitGstSetElementStateSynchronously(GstElement*, GstState, Function -std::optional gstStructureGet(const GstStructure*, ASCIILiteral key); -template -std::optional gstStructureGet(const GstStructure*, StringView key); +std::optional gstStructureGet(const GstStructure*, CStringView key); -StringView gstStructureGetString(const GstStructure*, ASCIILiteral key); -StringView gstStructureGetString(const GstStructure*, StringView key); +CStringView gstStructureGetString(const GstStructure*, CStringView key); -StringView gstStructureGetName(const GstStructure*); +CStringView gstStructureGetName(const GstStructure*); template -Vector gstStructureGetArray(const GstStructure*, ASCIILiteral key); +Vector gstStructureGetArray(const GstStructure*, CStringView key); String gstStructureToJSONString(const GstStructure*); @@ -312,8 +309,8 @@ void configureVideoDecoderForHarnessing(const GRefPtr&); void configureMediaStreamVideoDecoder(GstElement*); void configureVideoRTPDepayloader(GstElement*); -bool gstObjectHasProperty(GstElement*, const char* name); -bool gstObjectHasProperty(GstPad*, const char* name); +bool gstObjectHasProperty(GstElement*, ASCIILiteral name); +bool gstObjectHasProperty(GstPad*, ASCIILiteral name); GRefPtr wrapSpanData(const std::span&); @@ -349,7 +346,7 @@ using GstId = GQuark; bool gstStructureForeach(const GstStructure*, Function&&); void gstStructureIdSetValue(GstStructure*, GstId, const GValue*); bool gstStructureMapInPlace(GstStructure*, Function&&); -StringView gstIdToString(GstId); +String gstIdToString(GstId); void gstStructureFilterAndMapInPlace(GstStructure*, Function&&); #if USE(GBM) @@ -357,7 +354,7 @@ WARN_UNUSED_RETURN GRefPtr buildDMABufCaps(); #endif #if USE(GSTREAMER_GL) -bool setGstElementGLContext(GstElement*, const char* contextType); +bool setGstElementGLContext(GstElement*, ASCIILiteral contextType); #endif } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.cpp b/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.cpp index 5fec3d807d1d8..c0a7ede6ae51a 100644 --- a/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.cpp @@ -189,37 +189,39 @@ GStreamerRegistryScanner::ElementFactories::~ElementFactories() gst_plugin_feature_list_free(decryptorFactories); } -const char* GStreamerRegistryScanner::ElementFactories::elementFactoryTypeToString(GStreamerRegistryScanner::ElementFactories::Type factoryType) +#ifndef GST_DISABLE_GST_DEBUG +ASCIILiteral GStreamerRegistryScanner::ElementFactories::elementFactoryTypeToString(GStreamerRegistryScanner::ElementFactories::Type factoryType) { switch (factoryType) { case Type::AudioParser: - return "audio parser"; + return "audio parser"_s; case Type::AudioDecoder: - return "audio decoder"; + return "audio decoder"_s; case Type::VideoParser: - return "video parser"; + return "video parser"_s; case Type::VideoDecoder: - return "video decoder"; + return "video decoder"_s; case Type::Demuxer: - return "demuxer"; + return "demuxer"_s; case Type::AudioEncoder: - return "audio encoder"; + return "audio encoder"_s; case Type::VideoEncoder: - return "video encoder"; + return "video encoder"_s; case Type::Muxer: - return "muxer"; + return "muxer"_s; case Type::RtpPayloader: - return "RTP payloader"; + return "RTP payloader"_s; case Type::RtpDepayloader: - return "RTP depayloader"; + return "RTP depayloader"_s; case Type::Decryptor: - return "Decryptor"; + return "Decryptor"_s; case Type::All: break; } RELEASE_ASSERT_NOT_REACHED(); } +#endif GList* GStreamerRegistryScanner::ElementFactories::factory(GStreamerRegistryScanner::ElementFactories::Type factoryType) const { @@ -320,7 +322,7 @@ GStreamerRegistryScanner::RegistryLookupResult GStreamerRegistryScanner::Element break; } if (!hasValidCandidate) { - GST_WARNING("All %s elements matching caps %" GST_PTR_FORMAT " are disallowed", elementFactoryTypeToString(factoryType), caps.get()); + GST_WARNING("All %s elements matching caps %" GST_PTR_FORMAT " are disallowed", elementFactoryTypeToString(factoryType).characters(), caps.get()); isSupported = false; shouldCheckHardwareClassifier = CheckHardwareClassifier::No; } @@ -350,7 +352,7 @@ GStreamerRegistryScanner::RegistryLookupResult GStreamerRegistryScanner::Element if (!isSupported) selectedFactory.clear(); - GST_LOG("Lookup result for %s matching caps %" GST_PTR_FORMAT " : isSupported=%s, isUsingHardware=%s, factory=%" GST_PTR_FORMAT, elementFactoryTypeToString(factoryType), caps.get(), boolForPrinting(isSupported), boolForPrinting(isUsingHardware), selectedFactory.get()); + GST_LOG("Lookup result for %s matching caps %" GST_PTR_FORMAT " : isSupported=%s, isUsingHardware=%s, factory=%" GST_PTR_FORMAT, elementFactoryTypeToString(factoryType).characters(), caps.get(), boolForPrinting(isSupported), boolForPrinting(isUsingHardware), selectedFactory.get()); return { isSupported, isUsingHardware, selectedFactory }; } @@ -572,13 +574,13 @@ void GStreamerRegistryScanner::initializeDecoders(const GStreamerRegistryScanner { ElementFactories::Type::Demuxer, "video/x-ms-asf"_s, { }, { } }, }; - if (const char* hlsSupport = g_getenv("WEBKIT_GST_ENABLE_HLS_SUPPORT")) { - if (!g_strcmp0(hlsSupport, "1")) + if (auto hlsSupport = CStringView::unsafeFromUTF8(g_getenv("WEBKIT_GST_ENABLE_HLS_SUPPORT"))) { + if (hlsSupport == "1"_s) mapping.append({ ElementFactories::Type::Demuxer, "application/x-hls"_s, { "application/vnd.apple.mpegurl"_s, "application/x-mpegurl"_s }, { } }); } - if (const char* dashSupport = g_getenv("WEBKIT_GST_ENABLE_DASH_SUPPORT")) { - if (!g_strcmp0(dashSupport, "1")) + if (auto dashSupport = CStringView::unsafeFromUTF8(g_getenv("WEBKIT_GST_ENABLE_DASH_SUPPORT"))) { + if (dashSupport == "1"_s) mapping.append({ ElementFactories::Type::Demuxer, "application/dash+xml"_s, { }, { } }); } @@ -880,7 +882,7 @@ MediaPlayerEnums::SupportsType GStreamerRegistryScanner::isContentTypeSupported( } auto structure = gst_caps_get_structure(codecCaps.get(), 0); auto name = gstStructureGetName(structure); - auto caps = adoptGRef(gst_caps_new_simple("application/x-webm-enc", "original-media-type", G_TYPE_STRING, reinterpret_cast(name.rawCharacters()), nullptr)); + auto caps = adoptGRef(gst_caps_new_simple("application/x-webm-enc", "original-media-type", G_TYPE_STRING, name.utf8(), nullptr)); if (!factories.hasElementForCaps(ElementFactories::Type::Decryptor, caps)) return SupportsType::IsNotSupported; } @@ -964,33 +966,34 @@ GStreamerRegistryScanner::CodecLookupResult GStreamerRegistryScanner::isAVC1Code return { false, nullptr }; } - if (const char* maxVideoResolution = g_getenv("WEBKIT_GST_MAX_AVC1_RESOLUTION")) { - uint8_t levelAsInteger = gst_codec_utils_h264_get_level_idc(level); - GST_DEBUG("Maximum video resolution requested: %s, supplied codec level IDC: %u", maxVideoResolution, levelAsInteger); + CString levelAsCString = level.ascii(); + if (auto maxVideoResolution = CStringView::unsafeFromUTF8(g_getenv("WEBKIT_GST_MAX_AVC1_RESOLUTION"))) { + uint8_t levelAsInteger = gst_codec_utils_h264_get_level_idc(levelAsCString.data()); + GST_DEBUG("Maximum video resolution requested: %s, supplied codec level IDC: %u", maxVideoResolution.utf8(), levelAsInteger); uint8_t maxLevel = 0; - const char* maxLevelString = ""; - if (!g_strcmp0(maxVideoResolution, "1080P")) { + ASCIILiteral maxLevelString; + if (maxVideoResolution == "1080P"_s) { maxLevel = 40; - maxLevelString = "4"; - } else if (!g_strcmp0(maxVideoResolution, "720P")) { + maxLevelString = "4"_s; + } else if (maxVideoResolution == "720P"_s) { maxLevel = 31; - maxLevelString = "3.1"; - } else if (!g_strcmp0(maxVideoResolution, "480P")) { + maxLevelString = "3.1"_s; + } else if (maxVideoResolution == "480P"_s) { maxLevel = 30; - maxLevelString = "3"; + maxLevelString = "3"_s; } else { - g_warning("Invalid value for WEBKIT_GST_MAX_AVC1_RESOLUTION. Currently supported, 1080P, 720P and 480P."); + g_warning("Invalid value %s for WEBKIT_GST_MAX_AVC1_RESOLUTION. Currently supported, 1080P, 720P and 480P.", maxVideoResolution.utf8()); return { false, nullptr }; } if (levelAsInteger > maxLevel) return { false, nullptr }; - gst_caps_set_simple(h264Caps.get(), "level", G_TYPE_STRING, maxLevelString, nullptr); + gst_caps_set_simple(h264Caps.get(), "level", G_TYPE_STRING, maxLevelString.characters(), nullptr); return areCapsSupported(configuration, h264Caps, shouldCheckForHardwareUse); } GST_DEBUG("Checking video decoders for constrained caps"); - gst_caps_set_simple(h264Caps.get(), "level", G_TYPE_STRING, level, "profile", G_TYPE_STRING, profile, nullptr); + gst_caps_set_simple(h264Caps.get(), "level", G_TYPE_STRING, levelAsCString.data(), "profile", G_TYPE_STRING, profile.utf8(), nullptr); return areCapsSupported(configuration, h264Caps, shouldCheckForHardwareUse); } @@ -1084,7 +1087,7 @@ static inline Vector probeRtpExte Vector extensions; for (const auto& uri : candidates) { if (auto extension = adoptGRef(gst_rtp_header_extension_create_from_uri(uri.characters()))) - extensions.append(makeString(span(uri))); + extensions.append(String(byteCast(unsafeSpan(uri)))); } return extensions; } @@ -1147,14 +1150,14 @@ void GStreamerRegistryScanner::fillVideoRtpCapabilities(Configuration configurat element = gst_element_factory_make("webkitvideoencoder", nullptr); if (element) { - Vector profiles = { - "42e01f"_s, - "640c1f"_s, - "42001f"_s, - "4d001f"_s, - }; - - for (auto& profileLevelId : profiles) { + static constexpr std::array, 4> profiles = { { + { "42e01f"_s, 0x42e01f }, + { "640c1f"_s, 0x640c1f }, + { "42001f"_s, 0x42001f }, + { "4d001f"_s, 0x4d001f }, + } }; + + for (auto& [profileLevelId, spsAsInteger] : profiles) { if (WEBKIT_IS_VIDEO_ENCODER(element.get())) { auto codec = makeString("avc1."_s, profileLevelId); if (!videoEncoderSupportsCodec(WEBKIT_VIDEO_ENCODER(element.get()), codec)) diff --git a/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.h b/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.h index d0695a01573db..cb20c558f556e 100644 --- a/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.h +++ b/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.h @@ -137,7 +137,9 @@ class GStreamerRegistryScanner { explicit ElementFactories(OptionSet); ~ElementFactories(); - static const char* elementFactoryTypeToString(Type); +#ifndef GST_DISABLE_GST_DEBUG + static ASCIILiteral elementFactoryTypeToString(Type); +#endif GList* factory(Type) const; enum class CheckHardwareClassifier : bool { No, Yes }; diff --git a/Source/WebCore/platform/graphics/gstreamer/GStreamerSinksWorkarounds.cpp b/Source/WebCore/platform/graphics/gstreamer/GStreamerSinksWorkarounds.cpp index 16b7a6d117e74..2d3364492d3db 100644 --- a/Source/WebCore/platform/graphics/gstreamer/GStreamerSinksWorkarounds.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/GStreamerSinksWorkarounds.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -52,19 +53,20 @@ enum class WorkaroundMode { #define WEBKIT_GST_WORKAROUND_BASE_SINK_POSITION_FLUSH_DEFAULT_MODE "UseIfNeeded" #endif -static WorkaroundMode getWorkAroundModeFromEnvironment(const char* environmentVariableName, const char* defaultValue) +static WorkaroundMode getWorkAroundModeFromEnvironment(ASCIILiteral environmentVariableName, ASCIILiteral defaultValue) { - const char* textValue = getenv(environmentVariableName); + auto textValue = CStringView::unsafeFromUTF8(getenv(environmentVariableName.characters())); if (!textValue) textValue = defaultValue; - if (!g_ascii_strcasecmp(textValue, "UseIfNeeded")) + if (equalIgnoringASCIICase(textValue.span(), "UseIfNeeded"_s)) return WorkaroundMode::UseIfNeeded; - if (!g_ascii_strcasecmp(textValue, "ForceEnable")) + if (equalIgnoringASCIICase(textValue.span(), "ForceEnable"_s)) return WorkaroundMode::ForceEnable; - if (!g_ascii_strcasecmp(textValue, "ForceDisable")) + if (equalIgnoringASCIICase(textValue.span(), "ForceDisable"_s)) return WorkaroundMode::ForceDisable; - GST_ERROR("Invalid value for %s: '%s'. Accepted values are 'UseIfNeeded', 'ForceEnable' and 'ForceDisable'. Defaulting to `UseIfNeeded`...", environmentVariableName, textValue); + GST_ERROR("Invalid value for %s: '%s'. Accepted values are 'UseIfNeeded', 'ForceEnable' and 'ForceDisable'. Defaulting to `UseIfNeeded`...", + environmentVariableName.characters(), textValue.utf8()); return WorkaroundMode::UseIfNeeded; } @@ -100,10 +102,11 @@ class BaseSinkPositionFlushWorkaroundProbe { static bool checkIsNeeded() { #ifndef GST_DISABLE_GST_DEBUG - GUniquePtr versionString(gst_version_string()); - GST_DEBUG("BaseSinkPositionFlushWorkaroundProbe: running %s, the bug was fixed in 1.24.", versionString.get()); + auto versionString = GMallocString::unsafeAdoptFromUTF8(gst_version_string()); + GST_DEBUG("BaseSinkPositionFlushWorkaroundProbe: running %s, the bug was fixed in 1.24.", versionString.utf8()); #endif - WorkaroundMode mode = getWorkAroundModeFromEnvironment("WEBKIT_GST_WORKAROUND_BASE_SINK_POSITION_FLUSH", WEBKIT_GST_WORKAROUND_BASE_SINK_POSITION_FLUSH_DEFAULT_MODE); + WorkaroundMode mode = getWorkAroundModeFromEnvironment("WEBKIT_GST_WORKAROUND_BASE_SINK_POSITION_FLUSH"_s, + ASCIILiteral::fromLiteralUnsafe(WEBKIT_GST_WORKAROUND_BASE_SINK_POSITION_FLUSH_DEFAULT_MODE)); if (mode == WorkaroundMode::ForceEnable) { GST_DEBUG("BaseSinkPositionFlushWorkaroundProbe: forcing workaround to be enabled."); return true; @@ -205,10 +208,11 @@ class AppSinkFlushCapsWorkaroundProbe { } #ifndef GST_DISABLE_GST_DEBUG - GUniquePtr version(gst_plugins_base_version_string()); - GST_DEBUG("AppSinkFlushCapsWorkaroundProbe: gst-plugins-base version is %s, bug was fixed in 1.21.1 and backported to 1.20.3.", version.get()); + auto version = GMallocString::unsafeAdoptFromUTF8(gst_plugins_base_version_string()); + GST_DEBUG("AppSinkFlushCapsWorkaroundProbe: gst-plugins-base version is %s, bug was fixed in 1.21.1 and backported to 1.20.3.", version.utf8()); #endif - WorkaroundMode mode = getWorkAroundModeFromEnvironment("WEBKIT_GST_WORKAROUND_APP_SINK_FLUSH_CAPS", WEBKIT_GST_WORKAROUND_APP_SINK_FLUSH_CAPS_DEFAULT_MODE); + WorkaroundMode mode = getWorkAroundModeFromEnvironment("WEBKIT_GST_WORKAROUND_APP_SINK_FLUSH_CAPS"_s, + ASCIILiteral::fromLiteralUnsafe(WEBKIT_GST_WORKAROUND_APP_SINK_FLUSH_CAPS_DEFAULT_MODE)); if (mode == WorkaroundMode::ForceEnable) { GST_DEBUG("AppSinkFlushCapsWorkaroundProbe: forcing workaround to be enabled."); return true; diff --git a/Source/WebCore/platform/graphics/gstreamer/GStreamerVideoFrameConverter.cpp b/Source/WebCore/platform/graphics/gstreamer/GStreamerVideoFrameConverter.cpp index 0161efa74d6d2..f14557ffe69c8 100644 --- a/Source/WebCore/platform/graphics/gstreamer/GStreamerVideoFrameConverter.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/GStreamerVideoFrameConverter.cpp @@ -47,11 +47,11 @@ GStreamerVideoFrameConverter::GStreamerVideoFrameConverter() ensureGStreamerInitialized(); GST_DEBUG_CATEGORY_INIT(webkit_gst_video_frame_converter_debug, "webkitvideoframeconverter", 0, "WebKit GStreamer Video Frame Converter"); m_pipeline = gst_element_factory_make("pipeline", "video-frame-converter"); - m_src = makeGStreamerElement("appsrc", nullptr); - auto gldownload = makeGStreamerElement("gldownload", nullptr); - auto videoconvert = makeGStreamerElement("videoconvert", nullptr); - auto videoscale = makeGStreamerElement("videoscale", nullptr); - m_sink = makeGStreamerElement("appsink", nullptr); + m_src = makeGStreamerElement("appsrc"_s); + auto gldownload = makeGStreamerElement("gldownload"_s); + auto videoconvert = makeGStreamerElement("videoconvert"_s); + auto videoscale = makeGStreamerElement("videoscale"_s); + m_sink = makeGStreamerElement("appsink"_s); g_object_set(m_sink.get(), "enable-last-sample", FALSE, "max-buffers", 1, nullptr); gst_bin_add_many(GST_BIN_CAST(m_pipeline.get()), m_src.get(), gldownload, videoconvert, videoscale, m_sink.get(), nullptr); @@ -118,9 +118,9 @@ GRefPtr GStreamerVideoFrameConverter::convert(const GRefPtr(structure, "width"_s); auto height = gstStructureGet(structure, "height"_s); - auto formatStringView = gstStructureGetString(structure, "format"_s); - if (width && height && !formatStringView.isEmpty()) { - auto format = gst_video_format_from_string(formatStringView.toStringWithoutCopying().ascii().data()); + auto formatString = gstStructureGetString(structure, "format"_s); + if (width && height && !formatString.isEmpty()) { + auto format = gst_video_format_from_string(formatString.utf8()); gst_buffer_add_video_meta(writableBuffer.get(), GST_VIDEO_FRAME_FLAG_NONE, format, *width, *height); } gst_sample_set_buffer(convertedSample.get(), writableBuffer.get()); diff --git a/Source/WebCore/platform/graphics/gstreamer/ImageDecoderGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/ImageDecoderGStreamer.cpp index 5ae702a055a44..77057b3b54702 100644 --- a/Source/WebCore/platform/graphics/gstreamer/ImageDecoderGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/ImageDecoderGStreamer.cpp @@ -124,7 +124,7 @@ ImageDecoderGStreamer::ImageDecoderGStreamer(FragmentedSharedBuffer& data, const auto caps = adoptGRef(gst_pad_query_caps(pad.get(), nullptr)); auto identityHarness = GStreamerElementHarness::create(GRefPtr(gst_element_factory_make("identity", nullptr)), [](auto&, const auto&) { }); GST_DEBUG_OBJECT(pad.get(), "Caps on parser source pad: %" GST_PTR_FORMAT, caps.get()); - if (!caps || !doCapsHaveType(caps.get(), "video")) { + if (!caps || !doCapsHaveType(caps.get(), "video"_s)) { GST_WARNING_OBJECT(m_decoderHarness->element(), "Ignoring non-video track"); return identityHarness; } diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp index b5dd44ab736df..ccfc3659c2f56 100644 --- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp @@ -99,6 +99,7 @@ #include #include #include +#include #include #include #include @@ -1823,14 +1824,16 @@ bool MediaPlayerPrivateGStreamer::handleNeedContextMessage(GstMessage* message) { ASSERT(GST_MESSAGE_TYPE(message) == GST_MESSAGE_NEED_CONTEXT); - const gchar* contextType; - if (!gst_message_parse_context_type(message, &contextType)) + const gchar* contextTypeChars; + if (!gst_message_parse_context_type(message, &contextTypeChars)) return false; - GST_DEBUG_OBJECT(pipeline(), "Handling %s need-context message for %s", contextType, GST_MESSAGE_SRC_NAME(message)); + auto contextType = CStringView::unsafeFromUTF8(contextTypeChars); - if (!g_strcmp0(contextType, WEBKIT_WEB_SRC_RESOURCE_LOADER_CONTEXT_TYPE_NAME)) { - auto context = adoptGRef(gst_context_new(WEBKIT_WEB_SRC_RESOURCE_LOADER_CONTEXT_TYPE_NAME, FALSE)); + GST_DEBUG_OBJECT(pipeline(), "Handling %s need-context message for %s", contextType.utf8(), GST_MESSAGE_SRC_NAME(message)); + + if (contextType == WEBKIT_WEB_SRC_RESOURCE_LOADER_CONTEXT_TYPE_NAME) { + auto context = adoptGRef(gst_context_new(WEBKIT_WEB_SRC_RESOURCE_LOADER_CONTEXT_TYPE_NAME.characters(), FALSE)); GstStructure* contextStructure = gst_context_writable_structure(context.get()); gst_structure_set(contextStructure, "loader", G_TYPE_POINTER, m_loader.ptr(), nullptr); @@ -1839,16 +1842,17 @@ bool MediaPlayerPrivateGStreamer::handleNeedContextMessage(GstMessage* message) } #if ENABLE(ENCRYPTED_MEDIA) - if (!g_strcmp0(contextType, "drm-preferred-decryption-system-id")) { + if (contextType == "drm-preferred-decryption-system-id"_s) { initializationDataEncountered(parseInitDataFromProtectionMessage(message)); bool isCDMAttached = waitForCDMAttachment(); if (isCDMAttached && !isPlayerShuttingDown() && !m_cdmInstance->keySystem().isEmpty()) { - const char* preferredKeySystemUuid = GStreamerEMEUtilities::keySystemToUuid(m_cdmInstance->keySystem()); - GST_INFO_OBJECT(pipeline(), "working with key system %s, continuing with key system %s on %s", m_cdmInstance->keySystem().utf8().data(), preferredKeySystemUuid, GST_MESSAGE_SRC_NAME(message)); + ASCIILiteral preferredKeySystemUuid = GStreamerEMEUtilities::keySystemToUuid(m_cdmInstance->keySystem()); + GST_INFO_OBJECT(pipeline(), "working with key system %s, continuing with key system %s on %s", + m_cdmInstance->keySystem().ascii().data(), preferredKeySystemUuid.characters(), GST_MESSAGE_SRC_NAME(message)); GRefPtr context = adoptGRef(gst_context_new("drm-preferred-decryption-system-id", FALSE)); GstStructure* contextStructure = gst_context_writable_structure(context.get()); - gst_structure_set(contextStructure, "decryption-system-id", G_TYPE_STRING, preferredKeySystemUuid, nullptr); + gst_structure_set(contextStructure, "decryption-system-id", G_TYPE_STRING, preferredKeySystemUuid.characters(), nullptr); gst_element_set_context(GST_ELEMENT(GST_MESSAGE_SRC(message)), context.get()); return true; } @@ -1858,7 +1862,7 @@ bool MediaPlayerPrivateGStreamer::handleNeedContextMessage(GstMessage* message) } #endif // ENABLE(ENCRYPTED_MEDIA) - GST_DEBUG_OBJECT(pipeline(), "Unhandled %s need-context message for %s", contextType, GST_MESSAGE_SRC_NAME(message)); + GST_DEBUG_OBJECT(pipeline(), "Unhandled %s need-context message for %s", contextType.utf8(), GST_MESSAGE_SRC_NAME(message)); return false; } @@ -1995,7 +1999,6 @@ void MediaPlayerPrivateGStreamer::muteChangedCallback(MediaPlayerPrivateGStreame void MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message) { GUniqueOutPtr err; - GUniqueOutPtr debug; MediaPlayer::NetworkState error; bool issueError = true; bool attemptNextLocation = false; @@ -2029,7 +2032,7 @@ void MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message) m_queuedSyncErrors.exchangeSub(1); }); - gst_message_parse_error(message, &err.outPtr(), &debug.outPtr()); + gst_message_parse_error(message, &err.outPtr(), nullptr); if (m_shouldResetPipeline || m_didErrorOccur || m_ignoreErrors) { GST_WARNING_OBJECT(pipeline(), "Ignoring error: %s (url=%s) (code=%d)", err->message, m_url.string().utf8().data(), err->code); @@ -2044,7 +2047,7 @@ void MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message) GST_ERROR_OBJECT(pipeline(), "%s (url=%s) (code=%d)", err->message, m_url.string().utf8().data(), err->code); - m_errorMessage = String::fromLatin1(err->message); + m_errorMessage = String(byteCast(unsafeSpan(err->message))); #if ENABLE(MEDIA_TELEMETRY) MediaTelemetryReport::singleton().reportPlaybackState(MediaTelemetryReport::AVPipelineState::PlaybackError, m_errorMessage); @@ -2085,7 +2088,7 @@ void MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message) break; } case GST_MESSAGE_WARNING: - gst_message_parse_warning(message, &err.outPtr(), &debug.outPtr()); + gst_message_parse_warning(message, &err.outPtr(), nullptr); GST_WARNING_OBJECT(pipeline(), "%s (url=%s) (code=%d)", err->message, m_url.string().utf8().data(), err->code); break; case GST_MESSAGE_EOS: { @@ -2159,8 +2162,8 @@ void MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message) // Detect an audio sink element and store reference to it if it supersedes what we currently have. GstElement* element = GST_ELEMENT(GST_MESSAGE_SRC(message)); if (GST_OBJECT_FLAG_IS_SET(element, GST_ELEMENT_FLAG_SINK)) { - const gchar* klassStr = gst_element_get_metadata(element, "klass"); - if (g_strrstr(klassStr, "Sink") && g_strrstr(klassStr, "Audio") + auto klassStr = CStringView::unsafeFromUTF8(gst_element_get_metadata(element, "klass")); + if (contains(klassStr.span(), "Sink"_s) && contains(klassStr.span(), "Audio"_s) && (!m_audioSink || (m_audioSink.get() != element && GST_STATE(m_audioSink.get()) == GST_STATE_NULL))) m_audioSink = element; } @@ -2223,7 +2226,7 @@ void MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message) if (gst_structure_has_name(structure, "http-headers")) { GST_DEBUG_OBJECT(pipeline(), "Processing HTTP headers: %" GST_PTR_FORMAT, structure); if (auto uri = gstStructureGetString(structure, "uri"_s)) { - URL url { makeString(uri) }; + URL url { uri.span() }; if (url != m_url) { GST_DEBUG_OBJECT(pipeline(), "Ignoring HTTP response headers for non-main URI."); @@ -2248,7 +2251,7 @@ void MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message) // handle it here, until we remove the webkit+ protocol // prefix from webkitwebsrc. if (auto contentLengthValue = gstStructureGetString(responseHeaders.get(), contentLengthHeaderName)) { - if (auto parsedContentLength = parseInteger(contentLengthValue)) + if (auto parsedContentLength = parseInteger(contentLengthValue.span())) contentLength = *parsedContentLength; } } else @@ -2361,8 +2364,8 @@ void MediaPlayerPrivateGStreamer::updateBufferingStatus(GstBufferingMode mode, d m_previousBufferingPercentage = m_bufferingPercentage; #ifndef GST_DISABLE_GST_DEBUG - GUniquePtr modeString(g_enum_to_string(GST_TYPE_BUFFERING_MODE, mode)); - GST_DEBUG_OBJECT(pipeline(), "[Buffering] mode: %s, status: %f%%", modeString.get(), percentage); + auto modeString = GMallocString::unsafeAdoptFromUTF8(g_enum_to_string(GST_TYPE_BUFFERING_MODE, mode)); + GST_DEBUG_OBJECT(pipeline(), "[Buffering] mode: %s, status: %f%%", modeString.utf8(), percentage); #endif double highWatermark = 100.0; @@ -2554,9 +2557,8 @@ void MediaPlayerPrivateGStreamer::configureParsebin(GstElement* parsebin) #if GST_CHECK_VERSION(1, 20, 0) static auto exposeAutoPlug = *gstGetAutoplugSelectResult("expose"_s); auto& scanner = GStreamerRegistryScanner::singleton(); - GUniquePtr gstCodecName(gst_codec_utils_caps_get_mime_codec(caps)); - auto codecName = String::fromUTF8(gstCodecName.get()); - auto result = scanner.isCodecSupported(GStreamerRegistryScanner::Configuration::Decoding, codecName); + auto codecName = GMallocString::unsafeAdoptFromUTF8(gst_codec_utils_caps_get_mime_codec(caps)); + auto result = scanner.isCodecSupported(GStreamerRegistryScanner::Configuration::Decoding, codecName.span()); if (!result.isSupported) return tryAutoPlug; @@ -2565,6 +2567,9 @@ void MediaPlayerPrivateGStreamer::configureParsebin(GstElement* parsebin) if (decoderFactoryAcceptsCaps) return exposeAutoPlug; +#else + UNUSED_PARAM(factory); + UNUSED_PARAM(player); #endif return tryAutoPlug; @@ -2585,7 +2590,7 @@ void MediaPlayerPrivateGStreamer::configureParsebin(GstElement* parsebin) // Otherwise we need to ensure that the webkitthunderparser factory is present // and preferred over other parsers g_signal_connect(parsebin, "autoplug-factories", - G_CALLBACK(+[](GstElement*, GstPad*, GstCaps* caps, MediaPlayerPrivateGStreamer* player) -> GValueArray* { + G_CALLBACK(+[](GstElement*, GstPad*, GstCaps* caps, MediaPlayerPrivateGStreamer*) -> GValueArray* { ALLOW_DEPRECATED_DECLARATIONS_BEGIN; // GValueArray is deprecated GValueArray* result; // First, build a list of all decodable factories that can handle the caps, @@ -2618,24 +2623,24 @@ void MediaPlayerPrivateGStreamer::configureElement(GstElement* element) { configureElementPlatformQuirks(element); - GUniquePtr elementName(gst_element_get_name(element)); - String elementClass = WTF::span(gst_element_get_metadata(element, GST_ELEMENT_METADATA_KLASS)); + auto name = GMallocString::unsafeAdoptFromUTF8(gst_element_get_name(element)); + String elementClass(unsafeSpan(gst_element_get_metadata(element, GST_ELEMENT_METADATA_KLASS))); auto classifiers = elementClass.split('/'); // In GStreamer 1.20 and older urisourcebin mishandles source elements with dynamic pads. This // is not an issue in 1.22. Streams parsing is not needed for MediaStream cases because we do it // upfront for incoming WebRTC MediaStreams. It is however needed for MSE, otherwise decodebin3 // might not auto-plug hardware decoders. - if (webkitGstCheckVersion(1, 22, 0) && g_str_has_prefix(elementName.get(), "urisourcebin") && (isMediaSource() || isMediaStreamPlayer())) + if (webkitGstCheckVersion(1, 22, 0) && startsWith(name.span(), "urisourcebin"_s) && (isMediaSource() || isMediaStreamPlayer())) g_object_set(element, "use-buffering", FALSE, "parse-streams", !isMediaStreamPlayer(), nullptr); - if (g_str_has_prefix(elementName.get(), "parsebin")) + if (startsWith(name.span(), "parsebin"_s)) configureParsebin(element); // In case of playbin3 with