From a43cb15e81710eae9cc590690bfde1f1dcda0b3d Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Wed, 9 Jul 2025 14:13:22 -0400 Subject: [PATCH] LibJS+LibWeb: Replace JS::Utf16String with AK::Utf16String --- Libraries/LibJS/CMakeLists.txt | 1 - Libraries/LibJS/Forward.h | 1 - Libraries/LibJS/Print.cpp | 4 +- .../LibJS/Runtime/AbstractOperations.cpp | 6 +- Libraries/LibJS/Runtime/GlobalObject.cpp | 4 +- Libraries/LibJS/Runtime/Intl/Segmenter.cpp | 4 +- Libraries/LibJS/Runtime/Intl/Segments.cpp | 2 +- Libraries/LibJS/Runtime/Intl/Segments.h | 2 +- .../LibJS/Runtime/Intl/SegmentsPrototype.cpp | 2 +- Libraries/LibJS/Runtime/PrimitiveString.cpp | 210 ++++++++++-------- Libraries/LibJS/Runtime/PrimitiveString.h | 12 +- .../Runtime/RegExpLegacyStaticProperties.cpp | 10 +- .../Runtime/RegExpLegacyStaticProperties.h | 8 +- Libraries/LibJS/Runtime/RegExpPrototype.cpp | 11 +- Libraries/LibJS/Runtime/RegExpPrototype.h | 1 - .../Runtime/RegExpStringIteratorPrototype.cpp | 2 +- Libraries/LibJS/Runtime/StringConstructor.cpp | 20 +- Libraries/LibJS/Runtime/StringObject.cpp | 2 +- Libraries/LibJS/Runtime/StringPrototype.cpp | 21 +- Libraries/LibJS/Runtime/Utf16String.cpp | 157 ------------- Libraries/LibJS/Runtime/Utf16String.h | 197 ---------------- Libraries/LibJS/Runtime/Value.cpp | 8 +- .../LibWeb/SVG/SVGTextContentElement.cpp | 8 +- .../LibWeb/SVG/SVGTextPositioningElement.cpp | 5 - 24 files changed, 172 insertions(+), 526 deletions(-) delete mode 100644 Libraries/LibJS/Runtime/Utf16String.cpp delete mode 100644 Libraries/LibJS/Runtime/Utf16String.h diff --git a/Libraries/LibJS/CMakeLists.txt b/Libraries/LibJS/CMakeLists.txt index d1b613e48f1..076a12cba29 100644 --- a/Libraries/LibJS/CMakeLists.txt +++ b/Libraries/LibJS/CMakeLists.txt @@ -245,7 +245,6 @@ set(SOURCES Runtime/TypedArrayConstructor.cpp Runtime/TypedArrayPrototype.cpp Runtime/Uint8Array.cpp - Runtime/Utf16String.cpp Runtime/Value.cpp Runtime/VM.cpp Runtime/WeakMap.cpp diff --git a/Libraries/LibJS/Forward.h b/Libraries/LibJS/Forward.h index 9a06b2bc512..17ee9c149cf 100644 --- a/Libraries/LibJS/Forward.h +++ b/Libraries/LibJS/Forward.h @@ -219,7 +219,6 @@ struct SourceRange; class SourceTextModule; class Symbol; class Token; -class Utf16String; class VM; class PrototypeChainValidity; class Value; diff --git a/Libraries/LibJS/Print.cpp b/Libraries/LibJS/Print.cpp index 581a79495b6..c43667bc44e 100644 --- a/Libraries/LibJS/Print.cpp +++ b/Libraries/LibJS/Print.cpp @@ -774,11 +774,9 @@ ErrorOr print_intl_segmenter(JS::PrintContext& print_context, JS::Intl::Se ErrorOr print_intl_segments(JS::PrintContext& print_context, JS::Intl::Segments const& segments, HashTable& seen_objects) { - auto segments_string = JS::Utf16String::create(segments.segments_string()); - TRY(print_type(print_context, "Segments"sv)); TRY(js_out(print_context, "\n string: ")); - TRY(print_value(print_context, JS::PrimitiveString::create(segments.vm(), move(segments_string)), seen_objects)); + TRY(print_value(print_context, JS::PrimitiveString::create(segments.vm(), segments.segments_string()), seen_objects)); return {}; } diff --git a/Libraries/LibJS/Runtime/AbstractOperations.cpp b/Libraries/LibJS/Runtime/AbstractOperations.cpp index f40817cd1c7..4fed21faced 100644 --- a/Libraries/LibJS/Runtime/AbstractOperations.cpp +++ b/Libraries/LibJS/Runtime/AbstractOperations.cpp @@ -1284,7 +1284,7 @@ ThrowCompletionOr get_substitution(VM& vm, Utf16View const& matched, Utf // 4. Let templateRemainder be replacementTemplate. auto replace_template_string = TRY(replacement_template.to_utf16_string(vm)); - auto template_remainder = replace_template_string.view(); + Utf16View template_remainder { replace_template_string }; // 5. Repeat, while templateRemainder is not the empty String, while (!template_remainder.is_empty()) { @@ -1387,7 +1387,7 @@ ThrowCompletionOr get_substitution(VM& vm, Utf16View const& matched, Utf else { // a. Let refReplacement be capture. capture_string = TRY(capture.to_utf16_string(vm)); - ref_replacement = capture_string->view(); + ref_replacement = *capture_string; } } // ix. Else, @@ -1434,7 +1434,7 @@ ThrowCompletionOr get_substitution(VM& vm, Utf16View const& matched, Utf else { // a. Let refReplacement be ? ToString(capture). capture_string = TRY(capture.to_utf16_string(vm)); - ref_replacement = capture_string->view(); + ref_replacement = *capture_string; } } } diff --git a/Libraries/LibJS/Runtime/GlobalObject.cpp b/Libraries/LibJS/Runtime/GlobalObject.cpp index 6e4e471fc3a..6cfb243e82b 100644 --- a/Libraries/LibJS/Runtime/GlobalObject.cpp +++ b/Libraries/LibJS/Runtime/GlobalObject.cpp @@ -387,7 +387,7 @@ JS_DEFINE_NATIVE_FUNCTION(GlobalObject::parse_int) // 19.2.6.5 Encode ( string, extraUnescaped ), https://tc39.es/ecma262/#sec-encode static ThrowCompletionOr encode(VM& vm, ByteString const& string, StringView unescaped_set) { - auto utf16_string = Utf16String::create(string); + auto utf16_string = Utf16String::from_utf8(string); // 1. Let strLen be the length of string. auto string_length = utf16_string.length_in_code_units(); @@ -421,7 +421,7 @@ static ThrowCompletionOr encode(VM& vm, ByteString const& string, St // d. Else, else { // i. Let cp be CodePointAt(string, k). - auto code_point = code_point_at(utf16_string.view(), k); + auto code_point = code_point_at(utf16_string, k); // ii. If cp.[[IsUnpairedSurrogate]] is true, throw a URIError exception. if (code_point.is_unpaired_surrogate) return vm.throw_completion(ErrorType::URIMalformed); diff --git a/Libraries/LibJS/Runtime/Intl/Segmenter.cpp b/Libraries/LibJS/Runtime/Intl/Segmenter.cpp index bda7b5e0436..3843f772594 100644 --- a/Libraries/LibJS/Runtime/Intl/Segmenter.cpp +++ b/Libraries/LibJS/Runtime/Intl/Segmenter.cpp @@ -57,13 +57,13 @@ ThrowCompletionOr> create_segment_data_object(VM& vm, Unicode::S auto segment = string.substring_view(start_index, end_index - start_index); // 7. Perform ! CreateDataPropertyOrThrow(result, "segment", segment). - MUST(result->create_data_property_or_throw(vm.names.segment, PrimitiveString::create(vm, Utf16String::create(segment)))); + MUST(result->create_data_property_or_throw(vm.names.segment, PrimitiveString::create(vm, segment))); // 8. Perform ! CreateDataPropertyOrThrow(result, "index", 𝔽(startIndex)). MUST(result->create_data_property_or_throw(vm.names.index, Value(start_index))); // 9. Perform ! CreateDataPropertyOrThrow(result, "input", string). - MUST(result->create_data_property_or_throw(vm.names.input, PrimitiveString::create(vm, Utf16String::create(string)))); + MUST(result->create_data_property_or_throw(vm.names.input, PrimitiveString::create(vm, string))); // 10. Let granularity be segmenter.[[SegmenterGranularity]]. auto granularity = segmenter.segmenter_granularity(); diff --git a/Libraries/LibJS/Runtime/Intl/Segments.cpp b/Libraries/LibJS/Runtime/Intl/Segments.cpp index 800da9905c6..f1e2ca11757 100644 --- a/Libraries/LibJS/Runtime/Intl/Segments.cpp +++ b/Libraries/LibJS/Runtime/Intl/Segments.cpp @@ -29,7 +29,7 @@ Segments::Segments(Realm& realm, Unicode::Segmenter const& segmenter, Utf16Strin , m_segments_segmenter(segmenter.clone()) , m_segments_string(move(string)) { - m_segments_segmenter->set_segmented_text(m_segments_string.view()); + m_segments_segmenter->set_segmented_text(m_segments_string); } } diff --git a/Libraries/LibJS/Runtime/Intl/Segments.h b/Libraries/LibJS/Runtime/Intl/Segments.h index 16c0c8e4313..2cbadcef2a1 100644 --- a/Libraries/LibJS/Runtime/Intl/Segments.h +++ b/Libraries/LibJS/Runtime/Intl/Segments.h @@ -24,7 +24,7 @@ public: Unicode::Segmenter& segments_segmenter() const { return *m_segments_segmenter; } - Utf16View segments_string() const { return m_segments_string.view(); } + Utf16String const& segments_string() const { return m_segments_string; } private: Segments(Realm&, Unicode::Segmenter const&, Utf16String); diff --git a/Libraries/LibJS/Runtime/Intl/SegmentsPrototype.cpp b/Libraries/LibJS/Runtime/Intl/SegmentsPrototype.cpp index 3be7b243856..32a47c5bd66 100644 --- a/Libraries/LibJS/Runtime/Intl/SegmentsPrototype.cpp +++ b/Libraries/LibJS/Runtime/Intl/SegmentsPrototype.cpp @@ -76,7 +76,7 @@ JS_DEFINE_NATIVE_FUNCTION(SegmentsPrototype::symbol_iterator) auto& segmenter = segments->segments_segmenter(); // 4. Let string be segments.[[SegmentsString]]. - auto string = segments->segments_string(); + auto const& string = segments->segments_string(); // 5. Return ! CreateSegmentIterator(segmenter, string). return SegmentIterator::create(realm, segmenter, string, segments); diff --git a/Libraries/LibJS/Runtime/PrimitiveString.cpp b/Libraries/LibJS/Runtime/PrimitiveString.cpp index dad65f03838..176c6acf22f 100644 --- a/Libraries/LibJS/Runtime/PrimitiveString.cpp +++ b/Libraries/LibJS/Runtime/PrimitiveString.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -23,18 +24,80 @@ namespace JS { GC_DEFINE_ALLOCATOR(PrimitiveString); GC_DEFINE_ALLOCATOR(RopeString); -RopeString::RopeString(GC::Ref lhs, GC::Ref rhs) - : PrimitiveString(RopeTag::Rope) - , m_lhs(lhs) - , m_rhs(rhs) +GC::Ref PrimitiveString::create(VM& vm, Utf16String string) { + if (string.is_empty()) + return vm.empty_string(); + + if (string.length_in_code_units() == 1) { + if (auto code_unit = string.code_unit_at(0); is_ascii(code_unit)) + return vm.single_ascii_character_string(static_cast(code_unit)); + } + + auto& string_cache = vm.utf16_string_cache(); + if (auto it = string_cache.find(string); it != string_cache.end()) + return *it->value; + + auto new_string = vm.heap().allocate(string); + string_cache.set(move(string), new_string); + return *new_string; } -RopeString::~RopeString() = default; - -PrimitiveString::PrimitiveString(String string) - : m_utf8_string(move(string)) +GC::Ref PrimitiveString::create(VM& vm, Utf16View const& string) { + return create(vm, Utf16String::from_utf16(string)); +} + +GC::Ref PrimitiveString::create(VM& vm, Utf16FlyString const& string) +{ + return create(vm, string.to_utf16_string()); +} + +GC::Ref PrimitiveString::create(VM& vm, String string) +{ + if (string.is_empty()) + return vm.empty_string(); + + if (auto bytes = string.bytes_as_string_view(); bytes.length() == 1) { + if (auto ch = static_cast(bytes[0]); is_ascii(ch)) + return vm.single_ascii_character_string(ch); + } + + auto& string_cache = vm.string_cache(); + if (auto it = string_cache.find(string); it != string_cache.end()) + return *it->value; + + auto new_string = vm.heap().allocate(string); + string_cache.set(move(string), new_string); + return *new_string; +} + +GC::Ref PrimitiveString::create(VM& vm, StringView string) +{ + return create(vm, String::from_utf8(string).release_value()); +} + +GC::Ref PrimitiveString::create(VM& vm, FlyString const& string) +{ + return create(vm, string.to_string()); +} + +GC::Ref PrimitiveString::create(VM& vm, PrimitiveString& lhs, PrimitiveString& rhs) +{ + // We're here to concatenate two strings into a new rope string. However, if any of them are empty, no rope is required. + bool lhs_empty = lhs.is_empty(); + bool rhs_empty = rhs.is_empty(); + + if (lhs_empty && rhs_empty) + return vm.empty_string(); + + if (lhs_empty) + return rhs; + + if (rhs_empty) + return lhs; + + return vm.heap().allocate(lhs, rhs); } PrimitiveString::PrimitiveString(Utf16String string) @@ -42,19 +105,17 @@ PrimitiveString::PrimitiveString(Utf16String string) { } -PrimitiveString::~PrimitiveString() +PrimitiveString::PrimitiveString(String string) + : m_utf8_string(move(string)) { - if (has_utf8_string()) - vm().string_cache().remove(*m_utf8_string); - if (has_utf16_string()) - vm().utf16_string_cache().remove(*m_utf16_string); } -void RopeString::visit_edges(Cell::Visitor& visitor) +PrimitiveString::~PrimitiveString() { - Base::visit_edges(visitor); - visitor.visit(m_lhs); - visitor.visit(m_rhs); + if (has_utf16_string()) + vm().utf16_string_cache().remove(*m_utf16_string); + if (has_utf8_string()) + vm().string_cache().remove(*m_utf8_string); } bool PrimitiveString::is_empty() const @@ -95,7 +156,7 @@ Utf16String PrimitiveString::utf16_string() const if (!has_utf16_string()) { VERIFY(has_utf8_string()); - m_utf16_string = Utf16String::create(m_utf8_string->bytes_as_string_view()); + m_utf16_string = Utf16String::from_utf8(*m_utf8_string); } return *m_utf16_string; @@ -104,7 +165,7 @@ Utf16String PrimitiveString::utf16_string() const Utf16View PrimitiveString::utf16_string_view() const { (void)utf16_string(); - return m_utf16_string->view(); + return *m_utf16_string; } size_t PrimitiveString::length_in_utf16_code_units() const @@ -119,7 +180,7 @@ bool PrimitiveString::operator==(PrimitiveString const& other) const if (m_utf8_string.has_value() && other.m_utf8_string.has_value()) return m_utf8_string->bytes_as_string_view() == other.m_utf8_string->bytes_as_string_view(); if (m_utf16_string.has_value() && other.m_utf16_string.has_value()) - return m_utf16_string->string() == other.m_utf16_string->string(); + return *m_utf16_string == *other.m_utf16_string; return utf8_string_view() == other.utf8_string_view(); } @@ -127,89 +188,22 @@ ThrowCompletionOr> PrimitiveString::get(VM& vm, PropertyKey cons { if (property_key.is_symbol()) return Optional {}; + if (property_key.is_string()) { if (property_key.as_string() == vm.names.length.as_string()) { return Value(static_cast(length_in_utf16_code_units())); } } + auto index = canonical_numeric_index_string(property_key, CanonicalIndexMode::IgnoreNumericRoundtrip); if (!index.is_index()) return Optional {}; - auto str = utf16_string_view(); - auto length = str.length_in_code_units(); - if (length <= index.as_index()) + + auto string = utf16_string_view(); + if (string.length_in_code_units() <= index.as_index()) return Optional {}; - return create(vm, Utf16String::create(str.substring_view(index.as_index(), 1))); -} -GC::Ref PrimitiveString::create(VM& vm, Utf16String string) -{ - if (string.is_empty()) - return vm.empty_string(); - - if (string.length_in_code_units() == 1) { - u16 code_unit = string.code_unit_at(0); - if (is_ascii(code_unit)) - return vm.single_ascii_character_string(static_cast(code_unit)); - } - - auto& string_cache = vm.utf16_string_cache(); - if (auto it = string_cache.find(string); it != string_cache.end()) - return *it->value; - - auto new_string = vm.heap().allocate(string); - string_cache.set(move(string), new_string); - return *new_string; -} - -GC::Ref PrimitiveString::create(VM& vm, String string) -{ - if (string.is_empty()) - return vm.empty_string(); - - if (auto bytes = string.bytes_as_string_view(); bytes.length() == 1) { - auto ch = static_cast(bytes[0]); - if (is_ascii(ch)) - return vm.single_ascii_character_string(ch); - } - - auto& string_cache = vm.string_cache(); - if (auto it = string_cache.find(string); it != string_cache.end()) - return *it->value; - - auto new_string = vm.heap().allocate(string); - string_cache.set(move(string), new_string); - return *new_string; -} - -GC::Ref PrimitiveString::create(VM& vm, FlyString const& string) -{ - return create(vm, string.to_string()); -} - -GC::Ref PrimitiveString::create(VM& vm, StringView string) -{ - return create(vm, String::from_utf8(string).release_value()); -} - -GC::Ref PrimitiveString::create(VM& vm, PrimitiveString& lhs, PrimitiveString& rhs) -{ - // We're here to concatenate two strings into a new rope string. - // However, if any of them are empty, no rope is required. - - bool lhs_empty = lhs.is_empty(); - bool rhs_empty = rhs.is_empty(); - - if (lhs_empty && rhs_empty) - return vm.empty_string(); - - if (lhs_empty) - return rhs; - - if (rhs_empty) - return lhs; - - return vm.heap().allocate(lhs, rhs); + return create(vm, string.substring_view(index.as_index(), 1)); } void PrimitiveString::resolve_rope_if_needed(EncodingPreference preference) const @@ -218,7 +212,7 @@ void PrimitiveString::resolve_rope_if_needed(EncodingPreference preference) cons return; auto const& rope_string = static_cast(*this); - return rope_string.resolve(preference); + rope_string.resolve(preference); } void RopeString::resolve(EncodingPreference preference) const @@ -251,12 +245,16 @@ void RopeString::resolve(EncodingPreference preference) const if (preference == EncodingPreference::UTF16) { // The caller wants a UTF-16 string, so we can simply concatenate all the pieces // into a UTF-16 code unit buffer and create a Utf16String from it. + StringBuilder builder(StringBuilder::Mode::UTF16); - Utf16Data code_units; - for (auto const* current : pieces) - code_units.extend(current->utf16_string().string()); + for (auto const* current : pieces) { + if (current->has_utf8_string()) + builder.append(current->utf8_string_view()); + else + builder.append(current->utf16_string_view()); + } - m_utf16_string = Utf16String::create(move(code_units)); + m_utf16_string = builder.to_utf16_string_without_validation(); m_is_rope = false; m_lhs = nullptr; m_rhs = nullptr; @@ -331,4 +329,20 @@ void RopeString::resolve(EncodingPreference preference) const m_rhs = nullptr; } +RopeString::RopeString(GC::Ref lhs, GC::Ref rhs) + : PrimitiveString(RopeTag::Rope) + , m_lhs(lhs) + , m_rhs(rhs) +{ +} + +RopeString::~RopeString() = default; + +void RopeString::visit_edges(Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_lhs); + visitor.visit(m_rhs); +} + } diff --git a/Libraries/LibJS/Runtime/PrimitiveString.h b/Libraries/LibJS/Runtime/PrimitiveString.h index d274ed4c356..d33308adac5 100644 --- a/Libraries/LibJS/Runtime/PrimitiveString.h +++ b/Libraries/LibJS/Runtime/PrimitiveString.h @@ -10,11 +10,11 @@ #include #include #include +#include #include #include #include #include -#include #include namespace JS { @@ -25,10 +25,14 @@ class JS_API PrimitiveString : public Cell { public: [[nodiscard]] static GC::Ref create(VM&, Utf16String); + [[nodiscard]] static GC::Ref create(VM&, Utf16View const&); + [[nodiscard]] static GC::Ref create(VM&, Utf16FlyString const&); + [[nodiscard]] static GC::Ref create(VM&, String); - [[nodiscard]] static GC::Ref create(VM&, FlyString const&); - [[nodiscard]] static GC::Ref create(VM&, PrimitiveString&, PrimitiveString&); [[nodiscard]] static GC::Ref create(VM&, StringView); + [[nodiscard]] static GC::Ref create(VM&, FlyString const&); + + [[nodiscard]] static GC::Ref create(VM&, PrimitiveString&, PrimitiveString&); virtual ~PrimitiveString(); @@ -71,8 +75,8 @@ protected: private: friend class RopeString; - explicit PrimitiveString(String); explicit PrimitiveString(Utf16String); + explicit PrimitiveString(String); void resolve_rope_if_needed(EncodingPreference) const; }; diff --git a/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.cpp b/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.cpp index 620ceb33d7d..f18be07e149 100644 --- a/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.cpp +++ b/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.cpp @@ -94,7 +94,7 @@ void update_legacy_regexp_static_properties(RegExpConstructor& constructor, Utf1 legacy_static_properties.set_input(string); // 8. Set the value of C’s [[RegExpLastMatch]] internal slot to a String whose length is endIndex - startIndex and containing the code units from S with indices startIndex through endIndex - 1, in ascending order. - auto last_match = string.view().substring_view(start_index, end_index - start_index); + auto last_match = string.substring_view(start_index, end_index - start_index); legacy_static_properties.set_last_match(last_match); // 9. If n > 0, set the value of C’s [[RegExpLastParen]] internal slot to the last element of capturedValues. @@ -104,22 +104,22 @@ void update_legacy_regexp_static_properties(RegExpConstructor& constructor, Utf1 } // 10. Else, set the value of C’s [[RegExpLastParen]] internal slot to the empty String. else { - legacy_static_properties.set_last_paren(Utf16String::create()); + legacy_static_properties.set_last_paren({}); } // 11. Set the value of C’s [[RegExpLeftContext]] internal slot to a String whose length is startIndex and containing the code units from S with indices 0 through startIndex - 1, in ascending order. - auto left_context = string.view().substring_view(0, start_index); + auto left_context = string.substring_view(0, start_index); legacy_static_properties.set_left_context(left_context); // 12. Set the value of C’s [[RegExpRightContext]] internal slot to a String whose length is len - endIndex and containing the code units from S with indices endIndex through len - 1, in ascending order. - auto right_context = string.view().substring_view(end_index, len - end_index); + auto right_context = string.substring_view(end_index, len - end_index); legacy_static_properties.set_right_context(right_context); // 13. For each integer i such that 1 ≤ i ≤ 9 for (size_t i = 1; i <= 9; i++) { // i. If i ≤ n, set the value of C’s [[RegExpPareni]] internal slot to the ith element of capturedValues. // ii. Else, set the value of C’s [[RegExpPareni]] internal slot to the empty String. - auto value = (i <= group_count) ? captured_values[i - 1] : Utf16String::create(); + auto value = (i <= group_count) ? captured_values[i - 1] : Utf16String {}; if (i == 1) { legacy_static_properties.set_$1(move(value)); diff --git a/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.h b/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.h index eebce857598..0b67c1479b4 100644 --- a/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.h +++ b/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.h @@ -7,8 +7,8 @@ #pragma once #include +#include #include -#include namespace JS { @@ -26,20 +26,20 @@ public: Optional const& last_match() const { if (!m_last_match_string.has_value()) - m_last_match_string = Utf16String::create(m_last_match); + m_last_match_string = Utf16String::from_utf16_without_validation(m_last_match); return m_last_match_string; } Optional const& last_paren() const { return m_last_paren; } Optional const& left_context() const { if (!m_left_context_string.has_value()) - m_left_context_string = Utf16String::create(m_left_context); + m_left_context_string = Utf16String::from_utf16_without_validation(m_left_context); return m_left_context_string; } Optional const& right_context() const { if (!m_right_context_string.has_value()) - m_right_context_string = Utf16String::create(m_right_context); + m_right_context_string = Utf16String::from_utf16_without_validation(m_right_context); return m_right_context_string; } Optional const& $1() const { return m_$1; } diff --git a/Libraries/LibJS/Runtime/RegExpPrototype.cpp b/Libraries/LibJS/Runtime/RegExpPrototype.cpp index fcf2540ba68..7d765c76032 100644 --- a/Libraries/LibJS/Runtime/RegExpPrototype.cpp +++ b/Libraries/LibJS/Runtime/RegExpPrototype.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -280,7 +281,7 @@ static ThrowCompletionOr regexp_builtin_exec(VM& vm, RegExpObject& regexp // 28. Let matchedValue be ! GetMatchString(S, match). // 29. Perform ! CreateDataPropertyOrThrow(A, "0", matchedValue). - MUST(array->create_data_property_or_throw(0, PrimitiveString::create(vm, Utf16String::create(match.view.u16_view())))); + MUST(array->create_data_property_or_throw(0, PrimitiveString::create(vm, match.view.u16_view()))); // 30. If R contains any GroupName, then // a. Let groups be OrdinaryObjectCreate(null). @@ -305,7 +306,7 @@ static ThrowCompletionOr regexp_builtin_exec(VM& vm, RegExpObject& regexp // ii. Append undefined to indices. indices.append({}); // iii. Append capture to indices. - captured_values.append(Utf16String::create()); + captured_values.append({}); } // c. Else, else { @@ -316,7 +317,7 @@ static ThrowCompletionOr regexp_builtin_exec(VM& vm, RegExpObject& regexp // 2. Set captureEnd to ! GetStringIndex(S, Input, captureEnd). // iv. Let capture be the Match { [[StartIndex]]: captureStart, [[EndIndex]: captureEnd }. // v. Let capturedValue be ! GetMatchString(S, capture). - auto capture_as_utf16_string = Utf16String::create(capture.view.u16_view()); + auto capture_as_utf16_string = Utf16String::from_utf16_without_validation(capture.view.u16_view()); captured_value = PrimitiveString::create(vm, capture_as_utf16_string); // vi. Append capture to indices. indices.append(Match::create(capture)); @@ -987,7 +988,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_split) auto substring = string->utf16_string_view().substring_view(last_match_end, next_search_from - last_match_end); // 2. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(lengthA)), T). - MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, Utf16String::create(substring)))); + MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, substring))); // 3. Set lengthA to lengthA + 1. ++array_length; @@ -1033,7 +1034,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_split) auto substring = string->utf16_string_view().substring_view(last_match_end); // 21. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(lengthA)), T). - MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, Utf16String::create(substring)))); + MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, substring))); // 22. Return A. return array; diff --git a/Libraries/LibJS/Runtime/RegExpPrototype.h b/Libraries/LibJS/Runtime/RegExpPrototype.h index aa1c43f3128..dee861dfaed 100644 --- a/Libraries/LibJS/Runtime/RegExpPrototype.h +++ b/Libraries/LibJS/Runtime/RegExpPrototype.h @@ -8,7 +8,6 @@ #include #include -#include namespace JS { diff --git a/Libraries/LibJS/Runtime/RegExpStringIteratorPrototype.cpp b/Libraries/LibJS/Runtime/RegExpStringIteratorPrototype.cpp index 0935f6de131..15ff08b7e24 100644 --- a/Libraries/LibJS/Runtime/RegExpStringIteratorPrototype.cpp +++ b/Libraries/LibJS/Runtime/RegExpStringIteratorPrototype.cpp @@ -4,11 +4,11 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include #include -#include namespace JS { diff --git a/Libraries/LibJS/Runtime/StringConstructor.cpp b/Libraries/LibJS/Runtime/StringConstructor.cpp index e34ce300c6f..9b3de9f42c9 100644 --- a/Libraries/LibJS/Runtime/StringConstructor.cpp +++ b/Libraries/LibJS/Runtime/StringConstructor.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -13,7 +14,6 @@ #include #include #include -#include #include namespace JS { @@ -89,8 +89,7 @@ ThrowCompletionOr> StringConstructor::construct(FunctionObject& JS_DEFINE_NATIVE_FUNCTION(StringConstructor::from_char_code) { // 1. Let result be the empty String. - Utf16Data string; - string.ensure_capacity(vm.argument_count()); + StringBuilder builder(StringBuilder::Mode::UTF16, vm.argument_count()); // 2. For each element next of codeUnits, do for (size_t i = 0; i < vm.argument_count(); ++i) { @@ -98,20 +97,19 @@ JS_DEFINE_NATIVE_FUNCTION(StringConstructor::from_char_code) auto next_code_unit = TRY(vm.argument(i).to_u16(vm)); // b. Set result to the string-concatenation of result and nextCU. - string.append(next_code_unit); + builder.append_code_unit(next_code_unit); } // 3. Return result. - return PrimitiveString::create(vm, Utf16String::create(move(string))); + return PrimitiveString::create(vm, builder.to_utf16_string()); } // 22.1.2.2 String.fromCodePoint ( ...codePoints ), https://tc39.es/ecma262/#sec-string.fromcodepoint JS_DEFINE_NATIVE_FUNCTION(StringConstructor::from_code_point) { // 1. Let result be the empty String. - Utf16Data string; - // This will be an under-estimate if any code point is > 0xffff. - string.ensure_capacity(vm.argument_count()); + // NOTE: This will be an under-estimate if any code point is > 0xffff. + StringBuilder builder(StringBuilder::Mode::UTF16, vm.argument_count()); // 2. For each element next of codePoints, do for (size_t i = 0; i < vm.argument_count(); ++i) { @@ -130,16 +128,16 @@ JS_DEFINE_NATIVE_FUNCTION(StringConstructor::from_code_point) // d. Set result to the string-concatenation of result and UTF16EncodeCodePoint(ℝ(nextCP)). (void)AK::UnicodeUtils::code_point_to_utf16(static_cast(code_point), [&](auto code_unit) { - string.append(code_unit); + builder.append_code_unit(code_unit); }); } // 3. Assert: If codePoints is empty, then result is the empty String. if (!vm.argument_count()) - VERIFY(string.is_empty()); + VERIFY(builder.is_empty()); // 4. Return result. - return PrimitiveString::create(vm, Utf16String::create(move(string))); + return PrimitiveString::create(vm, builder.to_utf16_string()); } // 22.1.2.4 String.raw ( template, ...substitutions ), https://tc39.es/ecma262/#sec-string.raw diff --git a/Libraries/LibJS/Runtime/StringObject.cpp b/Libraries/LibJS/Runtime/StringObject.cpp index 517feb9ae24..e0cb6f5ba3f 100644 --- a/Libraries/LibJS/Runtime/StringObject.cpp +++ b/Libraries/LibJS/Runtime/StringObject.cpp @@ -83,7 +83,7 @@ static ThrowCompletionOr> string_get_own_property(S return Optional {}; // 10. Let resultStr be the substring of str from ℝ(index) to ℝ(index) + 1. - auto result_str = PrimitiveString::create(vm, Utf16String::create(str.substring_view(index.as_index(), 1))); + auto result_str = PrimitiveString::create(vm, str.substring_view(index.as_index(), 1)); // 11. Return the PropertyDescriptor { [[Value]]: resultStr, [[Writable]]: false, [[Enumerable]]: true, [[Configurable]]: false }. return PropertyDescriptor { diff --git a/Libraries/LibJS/Runtime/StringPrototype.cpp b/Libraries/LibJS/Runtime/StringPrototype.cpp index 6ec4f3c905a..13ccb713c46 100644 --- a/Libraries/LibJS/Runtime/StringPrototype.cpp +++ b/Libraries/LibJS/Runtime/StringPrototype.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -259,7 +258,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::at) return js_undefined(); // 7. Return ? Get(O, ! ToString(𝔽(k))). - return PrimitiveString::create(vm, Utf16String::create(string->utf16_string_view().substring_view(index.value(), 1))); + return PrimitiveString::create(vm, string->utf16_string_view().substring_view(index.value(), 1)); } // 22.1.3.2 String.prototype.charAt ( pos ), https://tc39.es/ecma262/#sec-string.prototype.charat @@ -278,7 +277,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::char_at) return PrimitiveString::create(vm, String {}); // 6. Return the substring of S from position to position + 1. - return PrimitiveString::create(vm, Utf16String::create(string->utf16_string_view().substring_view(position, 1))); + return PrimitiveString::create(vm, string->utf16_string_view().substring_view(position, 1)); } // 22.1.3.3 String.prototype.charCodeAt ( pos ), https://tc39.es/ecma262/#sec-string.prototype.charcodeat @@ -686,7 +685,7 @@ static ThrowCompletionOr pad_string(VM& vm, GC::Ref stri return string; // 5. If fillString is undefined, let filler be the String value consisting solely of the code unit 0x0020 (SPACE). - auto filler = Utf16String::create(Utf16Data { 0x20 }); + auto filler = " "_utf16; if (!fill_string.is_undefined()) { // 6. Else, let filler be ? ToString(fillString). filler = TRY(fill_string.to_utf16_string(vm)); @@ -702,7 +701,7 @@ static ThrowCompletionOr pad_string(VM& vm, GC::Ref stri StringBuilder truncated_string_filler_builder; auto fill_code_units = filler.length_in_code_units(); for (size_t i = 0; i < fill_length / fill_code_units; ++i) - truncated_string_filler_builder.append(filler.view()); + truncated_string_filler_builder.append(filler); // 9. Let truncatedStringFiller be the String value consisting of repeated concatenations of filler truncated to length fillLen. truncated_string_filler_builder.append(filler.substring_view(0, fill_length % fill_code_units)); @@ -1046,7 +1045,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::slice) return PrimitiveString::create(vm, String {}); // 13. Return the substring of S from from to to. - return PrimitiveString::create(vm, Utf16String::create(string->utf16_string_view().substring_view(int_start, int_end - int_start))); + return PrimitiveString::create(vm, string->utf16_string_view().substring_view(int_start, int_end - int_start)); } // 22.1.3.23 String.prototype.split ( separator, limit ), https://tc39.es/ecma262/#sec-string.prototype.split @@ -1127,7 +1126,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::split) auto segment = string->utf16_string_view().substring_view(start, position - start); // b. Append T to substrings. - MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, Utf16String::create(segment)))); + MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, segment))); ++array_length; // c. If the number of elements in substrings is lim, return CreateArrayFromList(substrings). @@ -1145,7 +1144,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::split) auto rest = string->utf16_string_view().substring_view(start); // 16. Append T to substrings. - MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, Utf16String::create(rest)))); + MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, rest))); // 17. Return CreateArrayFromList(substrings). return array; @@ -1237,7 +1236,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::substring) size_t to = max(final_start, final_end); // 10. Return the substring of S from from to to. - return PrimitiveString::create(vm, Utf16String::create(string->utf16_string_view().substring_view(from, to - from))); + return PrimitiveString::create(vm, string->utf16_string_view().substring_view(from, to - from)); } enum class TargetCase { @@ -1382,7 +1381,7 @@ String to_well_formed_string(Utf16String const& string) // 6. Repeat, while k < strLen, while (k < length) { // a. Let cp be CodePointAt(S, k). - auto code_point = JS::code_point_at(string.view(), k); + auto code_point = JS::code_point_at(string, k); // b. If cp.[[IsUnpairedSurrogate]] is true, then if (code_point.is_unpaired_surrogate) { @@ -1507,7 +1506,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::substr) return PrimitiveString::create(vm, String {}); // 11. Return the substring of S from intStart to intEnd. - return PrimitiveString::create(vm, Utf16String::create(string->utf16_string_view().substring_view(int_start, int_end - int_start))); + return PrimitiveString::create(vm, string->utf16_string_view().substring_view(int_start, int_end - int_start)); } // B.2.2.2.1 CreateHTML ( string, tag, attribute, value ), https://tc39.es/ecma262/#sec-createhtml diff --git a/Libraries/LibJS/Runtime/Utf16String.cpp b/Libraries/LibJS/Runtime/Utf16String.cpp deleted file mode 100644 index 637ebb151e6..00000000000 --- a/Libraries/LibJS/Runtime/Utf16String.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2021-2023, Tim Flynn - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -namespace JS { -namespace Detail { - -static NonnullRefPtr the_empty_utf16_string() -{ - static NonnullRefPtr empty_string = Utf16StringImpl::create(); - return empty_string; -} - -Utf16StringImpl::Utf16StringImpl(Utf16Data string) - : m_string(move(string)) -{ -} - -NonnullRefPtr Utf16StringImpl::create() -{ - return adopt_ref(*new Utf16StringImpl); -} - -NonnullRefPtr Utf16StringImpl::create(Utf16Data string) -{ - return adopt_ref(*new Utf16StringImpl(move(string))); -} - -NonnullRefPtr Utf16StringImpl::create(StringView string) -{ - auto result = MUST(utf8_to_utf16(string)); - auto impl = create(move(result.data)); - impl->m_cached_view.unsafe_set_code_point_length(result.code_point_count); - return impl; -} - -NonnullRefPtr Utf16StringImpl::create(Utf16View const& view) -{ - Utf16Data string; - string.ensure_capacity(view.length_in_code_units()); - - if (view.has_ascii_storage()) { - for (size_t i = 0; i < view.length_in_code_units(); ++i) - string.unchecked_append(static_cast(view.code_unit_at(i))); - } else { - string.unchecked_append(view.utf16_span().data(), view.length_in_code_units()); - } - - auto impl = create(move(string)); - if (auto length_in_code_points = view.length_in_code_points_if_known(); length_in_code_points.has_value()) - impl->m_cached_view.unsafe_set_code_point_length(*length_in_code_points); - - return impl; -} - -Utf16Data const& Utf16StringImpl::string() const -{ - return m_string; -} - -Utf16View Utf16StringImpl::view() const -{ - return m_cached_view; -} - -u32 Utf16StringImpl::compute_hash() const -{ - if (m_string.is_empty()) - return 0; - return string_hash((char const*)m_string.data(), m_string.size() * sizeof(u16)); -} - -} - -Utf16String Utf16String::create() -{ - return Utf16String { Detail::the_empty_utf16_string() }; -} - -Utf16String Utf16String::create(Utf16Data string) -{ - return Utf16String { Detail::Utf16StringImpl::create(move(string)) }; -} - -Utf16String Utf16String::create(StringView string) -{ - return Utf16String { Detail::Utf16StringImpl::create(string) }; -} - -Utf16String Utf16String::create(Utf16View const& string) -{ - return Utf16String { Detail::Utf16StringImpl::create(string) }; -} - -Utf16String Utf16String::invalid() -{ - static auto invalid = Utf16String {}; - return invalid; -} - -Utf16String::Utf16String(NonnullRefPtr string) - : m_string(move(string)) -{ -} - -Utf16Data const& Utf16String::string() const -{ - return m_string->string(); -} - -Utf16View Utf16String::view() const -{ - return m_string->view(); -} - -Utf16View Utf16String::substring_view(size_t code_unit_offset, size_t code_unit_length) const -{ - return view().substring_view(code_unit_offset, code_unit_length); -} - -Utf16View Utf16String::substring_view(size_t code_unit_offset) const -{ - return view().substring_view(code_unit_offset); -} - -String Utf16String::to_utf8() const -{ - return MUST(view().to_utf8()); -} - -ByteString Utf16String::to_byte_string() const -{ - return MUST(view().to_byte_string()); -} - -u16 Utf16String::code_unit_at(size_t index) const -{ - return view().code_unit_at(index); -} - -size_t Utf16String::length_in_code_units() const -{ - return view().length_in_code_units(); -} - -bool Utf16String::is_empty() const -{ - return view().is_empty(); -} - -} diff --git a/Libraries/LibJS/Runtime/Utf16String.h b/Libraries/LibJS/Runtime/Utf16String.h deleted file mode 100644 index 3dbee3c711f..00000000000 --- a/Libraries/LibJS/Runtime/Utf16String.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2021-2023, Tim Flynn - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace JS { -namespace Detail { - -class JS_API Utf16StringImpl : public RefCounted { -public: - ~Utf16StringImpl() = default; - - [[nodiscard]] static NonnullRefPtr create(); - [[nodiscard]] static NonnullRefPtr create(Utf16Data); - [[nodiscard]] static NonnullRefPtr create(StringView); - [[nodiscard]] static NonnullRefPtr create(Utf16View const&); - - Utf16Data const& string() const; - Utf16View view() const; - - [[nodiscard]] u32 hash() const - { - if (!m_has_hash) { - m_hash = compute_hash(); - m_has_hash = true; - } - return m_hash; - } - [[nodiscard]] bool operator==(Utf16StringImpl const& other) const { return string() == other.string(); } - -private: - Utf16StringImpl() = default; - explicit Utf16StringImpl(Utf16Data string); - - [[nodiscard]] u32 compute_hash() const; - - mutable bool m_has_hash { false }; - mutable u32 m_hash { 0 }; - Utf16Data m_string; - Utf16View m_cached_view { m_string }; -}; - -} - -class JS_API Utf16String { -public: - [[nodiscard]] static Utf16String create(); - [[nodiscard]] static Utf16String create(Utf16Data); - [[nodiscard]] static Utf16String create(StringView); - [[nodiscard]] static Utf16String create(Utf16View const&); - [[nodiscard]] static Utf16String invalid(); - - Utf16Data const& string() const; - Utf16View view() const; - Utf16View substring_view(size_t code_unit_offset, size_t code_unit_length) const; - Utf16View substring_view(size_t code_unit_offset) const; - - [[nodiscard]] String to_utf8() const; - [[nodiscard]] ByteString to_byte_string() const; - u16 code_unit_at(size_t index) const; - - size_t length_in_code_units() const; - bool is_empty() const; - bool is_valid() const { return m_string; } - - [[nodiscard]] u32 hash() const { return m_string->hash(); } - [[nodiscard]] bool operator==(Utf16String const& other) const - { - if (m_string == other.m_string) - return true; - return *m_string == *other.m_string; - } - -private: - Utf16String() = default; - explicit Utf16String(NonnullRefPtr); - - RefPtr m_string; -}; - -} - -namespace AK { - -template<> -struct Traits : public DefaultTraits { - static unsigned hash(JS::Utf16String const& s) { return s.hash(); } -}; - -template<> -class Optional : public OptionalBase { - template - friend class Optional; - -public: - using ValueType = JS::Utf16String; - - Optional() = default; - - template V> - Optional(V) { } - - Optional(Optional const& other) - { - if (other.has_value()) - m_value = other.m_value; - } - - Optional(Optional&& other) - : m_value(other.m_value) - { - } - - template - requires(!IsSame>) - explicit(!IsConvertible) Optional(U&& value) - requires(!IsSame, Optional> && IsConstructible) - : m_value(forward(value)) - { - } - - template V> - Optional& operator=(V) - { - clear(); - return *this; - } - - Optional& operator=(Optional const& other) - { - if (this != &other) { - clear(); - m_value = other.m_value; - } - return *this; - } - - Optional& operator=(Optional&& other) - { - if (this != &other) { - clear(); - m_value = other.m_value; - } - return *this; - } - - void clear() - { - m_value = JS::Utf16String::invalid(); - } - - [[nodiscard]] bool has_value() const - { - return m_value.is_valid(); - } - - [[nodiscard]] JS::Utf16String& value() & - { - VERIFY(has_value()); - return m_value; - } - - [[nodiscard]] JS::Utf16String const& value() const& - { - VERIFY(has_value()); - return m_value; - } - - [[nodiscard]] JS::Utf16String value() && - { - return release_value(); - } - - [[nodiscard]] JS::Utf16String release_value() - { - VERIFY(has_value()); - JS::Utf16String released_value = m_value; - clear(); - return released_value; - } - -private: - JS::Utf16String m_value { JS::Utf16String::invalid() }; -}; - -} diff --git a/Libraries/LibJS/Runtime/Value.cpp b/Libraries/LibJS/Runtime/Value.cpp index 065cfe42b1c..207b2ea6ce6 100644 --- a/Libraries/LibJS/Runtime/Value.cpp +++ b/Libraries/LibJS/Runtime/Value.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -59,12 +59,12 @@ static inline bool same_type_for_equality(Value const& lhs, Value const& rhs) static Crypto::SignedBigInteger const BIGINT_ZERO { 0 }; -ALWAYS_INLINE bool both_number(Value const& lhs, Value const& rhs) +static ALWAYS_INLINE bool both_number(Value const& lhs, Value const& rhs) { return lhs.is_number() && rhs.is_number(); } -ALWAYS_INLINE bool both_bigint(Value const& lhs, Value const& rhs) +static ALWAYS_INLINE bool both_bigint(Value const& lhs, Value const& rhs) { return lhs.is_bigint() && rhs.is_bigint(); } @@ -455,7 +455,7 @@ ThrowCompletionOr Value::to_utf16_string(VM& vm) const return as_string().utf16_string(); auto utf8_string = TRY(to_string(vm)); - return Utf16String::create(utf8_string.bytes_as_string_view()); + return Utf16String::from_utf8(utf8_string); } ThrowCompletionOr Value::to_well_formed_string(VM& vm) const diff --git a/Libraries/LibWeb/SVG/SVGTextContentElement.cpp b/Libraries/LibWeb/SVG/SVGTextContentElement.cpp index 32343bd6f34..2c868316072 100644 --- a/Libraries/LibWeb/SVG/SVGTextContentElement.cpp +++ b/Libraries/LibWeb/SVG/SVGTextContentElement.cpp @@ -5,16 +5,10 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include -#include -#include #include -#include #include -#include -#include +#include #include -#include #include namespace Web::SVG { diff --git a/Libraries/LibWeb/SVG/SVGTextPositioningElement.cpp b/Libraries/LibWeb/SVG/SVGTextPositioningElement.cpp index 842314d1c56..7e23944e651 100644 --- a/Libraries/LibWeb/SVG/SVGTextPositioningElement.cpp +++ b/Libraries/LibWeb/SVG/SVGTextPositioningElement.cpp @@ -5,15 +5,10 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include -#include -#include #include -#include #include #include #include -#include #include namespace Web::SVG {