diff --git a/Libraries/LibUnicode/Segmenter.cpp b/Libraries/LibUnicode/Segmenter.cpp index 113afc5c5a7..254103fb123 100644 --- a/Libraries/LibUnicode/Segmenter.cpp +++ b/Libraries/LibUnicode/Segmenter.cpp @@ -247,7 +247,7 @@ NonnullOwnPtr Segmenter::create(StringView locale, SegmenterGranulari return make(segmenter.release_nonnull(), segmenter_granularity); } -bool Segmenter::should_continue_beyond_word(Utf8View const& word) +bool Segmenter::should_continue_beyond_word(Utf16View const& word) { for (auto code_point : word) { if (!code_point_has_punctuation_general_category(code_point) && !code_point_has_separator_general_category(code_point)) diff --git a/Libraries/LibUnicode/Segmenter.h b/Libraries/LibUnicode/Segmenter.h index d4cb462ca55..6acf13bd483 100644 --- a/Libraries/LibUnicode/Segmenter.h +++ b/Libraries/LibUnicode/Segmenter.h @@ -27,7 +27,7 @@ public: static NonnullOwnPtr create(StringView locale, SegmenterGranularity segmenter_granularity); virtual ~Segmenter() = default; - static bool should_continue_beyond_word(Utf8View const&); + static bool should_continue_beyond_word(Utf16View const&); SegmenterGranularity segmenter_granularity() const { return m_segmenter_granularity; } diff --git a/Libraries/LibWeb/Bindings/OptionConstructor.cpp b/Libraries/LibWeb/Bindings/OptionConstructor.cpp index 7701432ffa5..95542237d1b 100644 --- a/Libraries/LibWeb/Bindings/OptionConstructor.cpp +++ b/Libraries/LibWeb/Bindings/OptionConstructor.cpp @@ -60,9 +60,9 @@ JS::ThrowCompletionOr> OptionConstructor::construct(Function GC::Ref option_element = as(*element); // 3. If text is not the empty string, then append to option a new Text node whose data is text. - auto text = TRY(text_value.to_string(vm)); + auto text = TRY(text_value.to_utf16_string(vm)); if (!text.is_empty()) { - auto new_text_node = realm.create(document, text); + auto new_text_node = realm.create(document, move(text)); MUST(option_element->append_child(*new_text_node)); } diff --git a/Libraries/LibWeb/DOM/AccessibilityTreeNode.cpp b/Libraries/LibWeb/DOM/AccessibilityTreeNode.cpp index d6b9fd035a9..0805a596d91 100644 --- a/Libraries/LibWeb/DOM/AccessibilityTreeNode.cpp +++ b/Libraries/LibWeb/DOM/AccessibilityTreeNode.cpp @@ -51,12 +51,11 @@ void AccessibilityTreeNode::serialize_tree_as_json(JsonObjectSerializeris_text()) { MUST(object.add("type"sv, "text"sv)); auto const* text_node = static_cast(value().ptr()); - MUST(object.add("text"sv, text_node->data())); + MUST(object.add("text"sv, text_node->data().to_utf8())); } if (value()->has_child_nodes()) { diff --git a/Libraries/LibWeb/DOM/CDATASection.cpp b/Libraries/LibWeb/DOM/CDATASection.cpp index baae6304d82..bef14b06d13 100644 --- a/Libraries/LibWeb/DOM/CDATASection.cpp +++ b/Libraries/LibWeb/DOM/CDATASection.cpp @@ -12,8 +12,8 @@ namespace Web::DOM { GC_DEFINE_ALLOCATOR(CDATASection); -CDATASection::CDATASection(Document& document, String const& data) - : Text(document, NodeType::CDATA_SECTION_NODE, data) +CDATASection::CDATASection(Document& document, Utf16String data) + : Text(document, NodeType::CDATA_SECTION_NODE, move(data)) { } diff --git a/Libraries/LibWeb/DOM/CDATASection.h b/Libraries/LibWeb/DOM/CDATASection.h index f0f2099bee6..f4611be1053 100644 --- a/Libraries/LibWeb/DOM/CDATASection.h +++ b/Libraries/LibWeb/DOM/CDATASection.h @@ -22,7 +22,7 @@ public: virtual FlyString node_name() const override { return "#cdata-section"_fly_string; } private: - CDATASection(Document&, String const&); + CDATASection(Document&, Utf16String); virtual void initialize(JS::Realm&) override; }; diff --git a/Libraries/LibWeb/DOM/CharacterData.cpp b/Libraries/LibWeb/DOM/CharacterData.cpp index 6f685fe0424..9c3c5fffec5 100644 --- a/Libraries/LibWeb/DOM/CharacterData.cpp +++ b/Libraries/LibWeb/DOM/CharacterData.cpp @@ -17,9 +17,9 @@ namespace Web::DOM { GC_DEFINE_ALLOCATOR(CharacterData); -CharacterData::CharacterData(Document& document, NodeType type, String const& data) +CharacterData::CharacterData(Document& document, NodeType type, Utf16String data) : Node(document, type) - , m_data(data) + , m_data(move(data)) { } @@ -32,7 +32,7 @@ void CharacterData::initialize(JS::Realm& realm) } // https://dom.spec.whatwg.org/#dom-characterdata-data -void CharacterData::set_data(String const& data) +void CharacterData::set_data(Utf16String const& data) { // [The data] setter must replace data with node this, offset 0, count this’s length, and data new value. // NOTE: Since the offset is 0, it can never be above data's length, so this can never throw. @@ -42,12 +42,10 @@ void CharacterData::set_data(String const& data) } // https://dom.spec.whatwg.org/#concept-cd-substring -WebIDL::ExceptionOr CharacterData::substring_data(size_t offset, size_t count) const +WebIDL::ExceptionOr CharacterData::substring_data(size_t offset, size_t count) const { // 1. Let length be node’s length. - // FIXME: This is very inefficient! - auto utf16_string = Utf16String::from_utf8(m_data); - auto length = utf16_string.length_in_code_units(); + auto length = m_data.length_in_code_units(); // 2. If offset is greater than length, then throw an "IndexSizeError" DOMException. if (offset > length) @@ -56,19 +54,17 @@ WebIDL::ExceptionOr CharacterData::substring_data(size_t offset, size_t // 3. If offset plus count is greater than length, return a string whose value is the code units from the offsetth code unit // to the end of node’s data, and then return. if (offset + count > length) - return MUST(utf16_string.substring_view(offset).to_utf8()); + return Utf16String::from_utf16_without_validation(m_data.substring_view(offset)); // 4. Return a string whose value is the code units from the offsetth code unit to the offset+countth code unit in node’s data. - return MUST(utf16_string.substring_view(offset, count).to_utf8()); + return Utf16String::from_utf16_without_validation(m_data.substring_view(offset, count)); } // https://dom.spec.whatwg.org/#concept-cd-replace -WebIDL::ExceptionOr CharacterData::replace_data(size_t offset, size_t count, String const& data) +WebIDL::ExceptionOr CharacterData::replace_data(size_t offset, size_t count, Utf16View const& data) { // 1. Let length be node’s length. - // FIXME: This is very inefficient! - auto utf16_string = Utf16String::from_utf8(m_data); - auto length = utf16_string.length_in_code_units(); + auto length = m_data.length_in_code_units(); // 2. If offset is greater than length, then throw an "IndexSizeError" DOMException. if (offset > length) @@ -81,27 +77,20 @@ WebIDL::ExceptionOr CharacterData::replace_data(size_t offset, size_t coun // 5. Insert data into node’s data after offset code units. // 6. Let delete offset be offset + data’s length. // 7. Starting from delete offset code units, remove count code units from node’s data. - auto before_data = utf16_string.substring_view(0, offset); - auto inserted_data = Utf16String::from_utf8(data); - auto after_data = utf16_string.substring_view(offset + count); + auto before_data = m_data.substring_view(0, offset); + auto after_data = m_data.substring_view(offset + count); - StringBuilder full_data(StringBuilder::Mode::UTF16, before_data.length_in_code_units() + inserted_data.length_in_code_units() + after_data.length_in_code_units()); + StringBuilder full_data(StringBuilder::Mode::UTF16, before_data.length_in_code_units() + data.length_in_code_units() + after_data.length_in_code_units()); full_data.append(before_data); - full_data.append(inserted_data); + full_data.append(data); full_data.append(after_data); - auto full_view = full_data.utf16_string_view(); - bool characters_are_the_same = utf16_string == full_view; auto old_data = m_data; - - // OPTIMIZATION: Skip UTF-8 encoding if the characters are the same. - if (!characters_are_the_same) { - m_data = MUST(full_view.to_utf8()); - } + m_data = full_data.to_utf16_string(); // 4. Queue a mutation record of "characterData" for node with null, null, node’s data, « », « », null, and null. // NOTE: We do this later so that the mutation observer may notify UI clients of this node's new value. - queue_mutation_record(MutationType::characterData, {}, {}, old_data, {}, {}, nullptr, nullptr); + queue_mutation_record(MutationType::characterData, {}, {}, old_data.to_utf8_but_should_be_ported_to_utf16(), {}, {}, nullptr, nullptr); // 8. For each live range whose start node is node and start offset is greater than offset but less than or equal to // offset plus count, set its start offset to offset. @@ -121,14 +110,14 @@ WebIDL::ExceptionOr CharacterData::replace_data(size_t offset, size_t coun // start offset by data’s length and decrease it by count. for (auto* range : Range::live_ranges()) { if (range->start_container() == this && range->start_offset() > (offset + count)) - range->set_start_offset(range->start_offset() + inserted_data.length_in_code_units() - count); + range->set_start_offset(range->start_offset() + data.length_in_code_units() - count); } // 11. For each live range whose end node is node and end offset is greater than offset plus count, increase its end // offset by data’s length and decrease it by count. for (auto* range : Range::live_ranges()) { if (range->end_container() == this && range->end_offset() > (offset + count)) - range->set_end_offset(range->end_offset() + inserted_data.length_in_code_units() - count); + range->set_end_offset(range->end_offset() + data.length_in_code_units() - count); } // 12. If node’s parent is non-null, then run the children changed steps for node’s parent. @@ -136,7 +125,7 @@ WebIDL::ExceptionOr CharacterData::replace_data(size_t offset, size_t coun parent()->children_changed(nullptr); // OPTIMIZATION: If the characters are the same, we can skip the remainder of this function. - if (characters_are_the_same) + if (m_data == old_data) return {}; if (auto* layout_node = this->layout_node(); layout_node && layout_node->is_text_node()) { @@ -160,14 +149,14 @@ WebIDL::ExceptionOr CharacterData::replace_data(size_t offset, size_t coun } // https://dom.spec.whatwg.org/#dom-characterdata-appenddata -WebIDL::ExceptionOr CharacterData::append_data(String const& data) +WebIDL::ExceptionOr CharacterData::append_data(Utf16View const& data) { // The appendData(data) method steps are to replace data with node this, offset this’s length, count 0, and data data. return replace_data(this->length_in_utf16_code_units(), 0, data); } // https://dom.spec.whatwg.org/#dom-characterdata-insertdata -WebIDL::ExceptionOr CharacterData::insert_data(size_t offset, String const& data) +WebIDL::ExceptionOr CharacterData::insert_data(size_t offset, Utf16View const& data) { // The insertData(offset, data) method steps are to replace data with node this, offset offset, count 0, and data data. return replace_data(offset, 0, data); @@ -177,7 +166,7 @@ WebIDL::ExceptionOr CharacterData::insert_data(size_t offset, String const WebIDL::ExceptionOr CharacterData::delete_data(size_t offset, size_t count) { // The deleteData(offset, count) method steps are to replace data with node this, offset offset, count count, and data the empty string. - return replace_data(offset, count, String {}); + return replace_data(offset, count, {}); } Unicode::Segmenter& CharacterData::grapheme_segmenter() const diff --git a/Libraries/LibWeb/DOM/CharacterData.h b/Libraries/LibWeb/DOM/CharacterData.h index 630f82abe84..37978634d4c 100644 --- a/Libraries/LibWeb/DOM/CharacterData.h +++ b/Libraries/LibWeb/DOM/CharacterData.h @@ -6,7 +6,7 @@ #pragma once -#include +#include #include #include #include @@ -26,30 +26,27 @@ class CharacterData public: virtual ~CharacterData() override; - String const& data() const { return m_data; } - void set_data(String const&); + Utf16String const& data() const { return m_data; } + void set_data(Utf16String const&); - unsigned length_in_utf16_code_units() const - { - return AK::utf16_code_unit_length_from_utf8(m_data); - } + unsigned length_in_utf16_code_units() const { return m_data.length_in_code_units(); } - WebIDL::ExceptionOr substring_data(size_t offset_in_utf16_code_units, size_t count_in_utf16_code_units) const; - WebIDL::ExceptionOr append_data(String const&); - WebIDL::ExceptionOr insert_data(size_t offset_in_utf16_code_units, String const&); + WebIDL::ExceptionOr substring_data(size_t offset_in_utf16_code_units, size_t count_in_utf16_code_units) const; + WebIDL::ExceptionOr append_data(Utf16View const&); + WebIDL::ExceptionOr insert_data(size_t offset_in_utf16_code_units, Utf16View const&); WebIDL::ExceptionOr delete_data(size_t offset_in_utf16_code_units, size_t count_in_utf16_code_units); - WebIDL::ExceptionOr replace_data(size_t offset_in_utf16_code_units, size_t count_in_utf16_code_units, String const&); + WebIDL::ExceptionOr replace_data(size_t offset_in_utf16_code_units, size_t count_in_utf16_code_units, Utf16View const&); Unicode::Segmenter& grapheme_segmenter() const; Unicode::Segmenter& word_segmenter() const; protected: - CharacterData(Document&, NodeType, String const&); + CharacterData(Document&, NodeType, Utf16String); virtual void initialize(JS::Realm&) override; private: - String m_data; + Utf16String m_data; mutable OwnPtr m_grapheme_segmenter; mutable OwnPtr m_word_segmenter; diff --git a/Libraries/LibWeb/DOM/CharacterData.idl b/Libraries/LibWeb/DOM/CharacterData.idl index 5213fdb8556..dd4a8198bfb 100644 --- a/Libraries/LibWeb/DOM/CharacterData.idl +++ b/Libraries/LibWeb/DOM/CharacterData.idl @@ -5,14 +5,14 @@ // https://dom.spec.whatwg.org/#characterdata [Exposed=Window] interface CharacterData : Node { - [LegacyNullToEmptyString] attribute DOMString data; + [LegacyNullToEmptyString] attribute Utf16DOMString data; [ImplementedAs=length_in_utf16_code_units] readonly attribute unsigned long length; - DOMString substringData(unsigned long offset, unsigned long count); - undefined appendData(DOMString data); - undefined insertData(unsigned long offset, DOMString data); + Utf16DOMString substringData(unsigned long offset, unsigned long count); + undefined appendData(Utf16DOMString data); + undefined insertData(unsigned long offset, Utf16DOMString data); undefined deleteData(unsigned long offset, unsigned long count); - undefined replaceData(unsigned long offset, unsigned long count, DOMString data); + undefined replaceData(unsigned long offset, unsigned long count, Utf16DOMString data); // https://dom.spec.whatwg.org/#interface-nondocumenttypechildnode readonly attribute Element? previousElementSibling; diff --git a/Libraries/LibWeb/DOM/ChildNode.h b/Libraries/LibWeb/DOM/ChildNode.h index 2440c88c211..e36673c54b7 100644 --- a/Libraries/LibWeb/DOM/ChildNode.h +++ b/Libraries/LibWeb/DOM/ChildNode.h @@ -16,7 +16,7 @@ template class ChildNode { public: // https://dom.spec.whatwg.org/#dom-childnode-before - WebIDL::ExceptionOr before(Vector, String>> const& nodes) + WebIDL::ExceptionOr before(Vector, Utf16String>> const& nodes) { auto* node = static_cast(this); @@ -46,7 +46,7 @@ public: } // https://dom.spec.whatwg.org/#dom-childnode-after - WebIDL::ExceptionOr after(Vector, String>> const& nodes) + WebIDL::ExceptionOr after(Vector, Utf16String>> const& nodes) { auto* node = static_cast(this); @@ -70,7 +70,7 @@ public: } // https://dom.spec.whatwg.org/#dom-childnode-replacewith - WebIDL::ExceptionOr replace_with(Vector, String>> const& nodes) + WebIDL::ExceptionOr replace_with(Vector, Utf16String>> const& nodes) { auto* node = static_cast(this); @@ -117,7 +117,7 @@ protected: ChildNode() = default; private: - GC::Ptr viable_previous_sibling_for_insertion(Vector, String>> const& nodes) + GC::Ptr viable_previous_sibling_for_insertion(Vector, Utf16String>> const& nodes) { auto* node = static_cast(this); @@ -142,7 +142,7 @@ private: return nullptr; } - GC::Ptr viable_next_sibling_for_insertion(Vector, String>> const& nodes) + GC::Ptr viable_next_sibling_for_insertion(Vector, Utf16String>> const& nodes) { auto* node = static_cast(this); diff --git a/Libraries/LibWeb/DOM/ChildNode.idl b/Libraries/LibWeb/DOM/ChildNode.idl index 575a251f6cc..57e5c8835d0 100644 --- a/Libraries/LibWeb/DOM/ChildNode.idl +++ b/Libraries/LibWeb/DOM/ChildNode.idl @@ -3,8 +3,8 @@ // https://dom.spec.whatwg.org/#childnode interface mixin ChildNode { - [CEReactions, Unscopable] undefined before((Node or DOMString)... nodes); - [CEReactions, Unscopable] undefined after((Node or DOMString)... nodes); - [CEReactions, Unscopable] undefined replaceWith((Node or DOMString)... nodes); + [CEReactions, Unscopable] undefined before((Node or Utf16DOMString)... nodes); + [CEReactions, Unscopable] undefined after((Node or Utf16DOMString)... nodes); + [CEReactions, Unscopable] undefined replaceWith((Node or Utf16DOMString)... nodes); [CEReactions, Unscopable, ImplementedAs=remove_binding] undefined remove(); }; diff --git a/Libraries/LibWeb/DOM/Comment.cpp b/Libraries/LibWeb/DOM/Comment.cpp index 79c2a13e0e2..3a94d4f483c 100644 --- a/Libraries/LibWeb/DOM/Comment.cpp +++ b/Libraries/LibWeb/DOM/Comment.cpp @@ -13,16 +13,16 @@ namespace Web::DOM { GC_DEFINE_ALLOCATOR(Comment); -Comment::Comment(Document& document, String const& data) - : CharacterData(document, NodeType::COMMENT_NODE, data) +Comment::Comment(Document& document, Utf16String data) + : CharacterData(document, NodeType::COMMENT_NODE, move(data)) { } // https://dom.spec.whatwg.org/#dom-comment-comment -WebIDL::ExceptionOr> Comment::construct_impl(JS::Realm& realm, String const& data) +WebIDL::ExceptionOr> Comment::construct_impl(JS::Realm& realm, Utf16String data) { auto& window = as(realm.global_object()); - return realm.create(window.associated_document(), data); + return realm.create(window.associated_document(), move(data)); } void Comment::initialize(JS::Realm& realm) diff --git a/Libraries/LibWeb/DOM/Comment.h b/Libraries/LibWeb/DOM/Comment.h index 0dfe6a04a4a..4fa3c2f87ae 100644 --- a/Libraries/LibWeb/DOM/Comment.h +++ b/Libraries/LibWeb/DOM/Comment.h @@ -15,13 +15,13 @@ class Comment final : public CharacterData { GC_DECLARE_ALLOCATOR(Comment); public: - static WebIDL::ExceptionOr> construct_impl(JS::Realm&, String const& data); + static WebIDL::ExceptionOr> construct_impl(JS::Realm&, Utf16String data); virtual ~Comment() override = default; virtual FlyString node_name() const override { return "#comment"_fly_string; } private: - Comment(Document&, String const&); + Comment(Document&, Utf16String); virtual void initialize(JS::Realm&) override; }; diff --git a/Libraries/LibWeb/DOM/Comment.idl b/Libraries/LibWeb/DOM/Comment.idl index bb3728dbf38..49cfcc1cb6a 100644 --- a/Libraries/LibWeb/DOM/Comment.idl +++ b/Libraries/LibWeb/DOM/Comment.idl @@ -3,5 +3,5 @@ // https://dom.spec.whatwg.org/#comment [Exposed=Window] interface Comment : CharacterData { - constructor(optional DOMString data = ""); + constructor(optional Utf16DOMString data = ""); }; diff --git a/Libraries/LibWeb/DOM/DOMImplementation.cpp b/Libraries/LibWeb/DOM/DOMImplementation.cpp index dd22a104473..a668f6c92f5 100644 --- a/Libraries/LibWeb/DOM/DOMImplementation.cpp +++ b/Libraries/LibWeb/DOM/DOMImplementation.cpp @@ -90,7 +90,7 @@ WebIDL::ExceptionOr> DOMImplementation::create_document(Opt } // https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument -GC::Ref DOMImplementation::create_html_document(Optional const& title) const +GC::Ref DOMImplementation::create_html_document(Optional const& title) const { // 1. Let doc be a new document that is an HTML document. auto html_document = HTML::HTMLDocument::create(realm()); diff --git a/Libraries/LibWeb/DOM/DOMImplementation.h b/Libraries/LibWeb/DOM/DOMImplementation.h index 85d8fbac08c..de17274d631 100644 --- a/Libraries/LibWeb/DOM/DOMImplementation.h +++ b/Libraries/LibWeb/DOM/DOMImplementation.h @@ -22,7 +22,7 @@ public: virtual ~DOMImplementation(); WebIDL::ExceptionOr> create_document(Optional const&, String const&, GC::Ptr) const; - GC::Ref create_html_document(Optional const& title) const; + GC::Ref create_html_document(Optional const& title) const; WebIDL::ExceptionOr> create_document_type(String const& name, String const& public_id, String const& system_id); // https://dom.spec.whatwg.org/#dom-domimplementation-hasfeature diff --git a/Libraries/LibWeb/DOM/DOMImplementation.idl b/Libraries/LibWeb/DOM/DOMImplementation.idl index 28fe6392402..92770329cbf 100644 --- a/Libraries/LibWeb/DOM/DOMImplementation.idl +++ b/Libraries/LibWeb/DOM/DOMImplementation.idl @@ -6,7 +6,7 @@ interface DOMImplementation { [NewObject] DocumentType createDocumentType(DOMString qualifiedName, DOMString publicId, DOMString systemId); [NewObject] XMLDocument createDocument([FlyString] DOMString? namespace, [LegacyNullToEmptyString] DOMString qualifiedName, optional DocumentType? doctype = null); - [NewObject] Document createHTMLDocument(optional DOMString title); + [NewObject] Document createHTMLDocument(optional Utf16DOMString title); boolean hasFeature(); // useless; always returns true }; diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index 2adcaf167fb..6cda70dfdc8 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -2122,13 +2122,13 @@ GC::Ref Document::create_document_fragment() return realm().create(*this); } -GC::Ref Document::create_text_node(String const& data) +GC::Ref Document::create_text_node(Utf16String data) { - return realm().create(*this, data); + return realm().create(*this, move(data)); } // https://dom.spec.whatwg.org/#dom-document-createcdatasection -WebIDL::ExceptionOr> Document::create_cdata_section(String const& data) +WebIDL::ExceptionOr> Document::create_cdata_section(Utf16String data) { // 1. If this is an HTML document, then throw a "NotSupportedError" DOMException. if (is_html_document()) @@ -2139,16 +2139,16 @@ WebIDL::ExceptionOr> Document::create_cdata_section(String return WebIDL::InvalidCharacterError::create(realm(), "String may not contain ']]>'"_string); // 3. Return a new CDATASection node with its data set to data and node document set to this. - return realm().create(*this, data); + return realm().create(*this, move(data)); } -GC::Ref Document::create_comment(String const& data) +GC::Ref Document::create_comment(Utf16String data) { - return realm().create(*this, data); + return realm().create(*this, move(data)); } // https://dom.spec.whatwg.org/#dom-document-createprocessinginstruction -WebIDL::ExceptionOr> Document::create_processing_instruction(String const& target, String const& data) +WebIDL::ExceptionOr> Document::create_processing_instruction(String const& target, Utf16String data) { // 1. If target does not match the Name production, then throw an "InvalidCharacterError" DOMException. if (!is_valid_name(target)) @@ -2159,7 +2159,7 @@ WebIDL::ExceptionOr> Document::create_processing_ return WebIDL::InvalidCharacterError::create(realm(), "String may not contain '?>'"_string); // 3. Return a new ProcessingInstruction node, with target set to target, data set to data, and node document set to this. - return realm().create(*this, data, target); + return realm().create(*this, move(data), target); } GC::Ref Document::create_range() diff --git a/Libraries/LibWeb/DOM/Document.h b/Libraries/LibWeb/DOM/Document.h index 0393f76c211..27b67787354 100644 --- a/Libraries/LibWeb/DOM/Document.h +++ b/Libraries/LibWeb/DOM/Document.h @@ -377,10 +377,10 @@ public: WebIDL::ExceptionOr> create_element(String const& local_name, Variant const& options); WebIDL::ExceptionOr> create_element_ns(Optional const& namespace_, String const& qualified_name, Variant const& options); GC::Ref create_document_fragment(); - GC::Ref create_text_node(String const& data); - WebIDL::ExceptionOr> create_cdata_section(String const& data); - GC::Ref create_comment(String const& data); - WebIDL::ExceptionOr> create_processing_instruction(String const& target, String const& data); + GC::Ref create_text_node(Utf16String data); + WebIDL::ExceptionOr> create_cdata_section(Utf16String data); + GC::Ref create_comment(Utf16String data); + WebIDL::ExceptionOr> create_processing_instruction(String const& target, Utf16String data); WebIDL::ExceptionOr> create_attribute(String const& local_name); WebIDL::ExceptionOr> create_attribute_ns(Optional const& namespace_, String const& qualified_name); diff --git a/Libraries/LibWeb/DOM/Document.idl b/Libraries/LibWeb/DOM/Document.idl index ff99584ccc7..2ae2ebf650f 100644 --- a/Libraries/LibWeb/DOM/Document.idl +++ b/Libraries/LibWeb/DOM/Document.idl @@ -98,10 +98,10 @@ interface Document : Node { [CEReactions, NewObject] Element createElement(DOMString tagName, optional (DOMString or ElementCreationOptions) options = {}); [CEReactions, NewObject] Element createElementNS([FlyString] DOMString? namespace, DOMString qualifiedName, optional (DOMString or ElementCreationOptions) options = {}); DocumentFragment createDocumentFragment(); - Text createTextNode(DOMString data); - [NewObject] CDATASection createCDATASection(DOMString data); - Comment createComment(DOMString data); - [NewObject] ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data); + Text createTextNode(Utf16DOMString data); + [NewObject] CDATASection createCDATASection(Utf16DOMString data); + Comment createComment(Utf16DOMString data); + [NewObject] ProcessingInstruction createProcessingInstruction(DOMString target, Utf16DOMString data); [NewObject] Attr createAttribute(DOMString localName); [NewObject] Attr createAttributeNS([FlyString] DOMString? namespace, DOMString qualifiedName); diff --git a/Libraries/LibWeb/DOM/DocumentLoading.cpp b/Libraries/LibWeb/DOM/DocumentLoading.cpp index 9c3567b887c..0ca2acfd854 100644 --- a/Libraries/LibWeb/DOM/DocumentLoading.cpp +++ b/Libraries/LibWeb/DOM/DocumentLoading.cpp @@ -26,12 +26,12 @@ namespace Web { // Replaces a document's content with a simple error message. -static void convert_to_xml_error_document(DOM::Document& document, String error_string) +static void convert_to_xml_error_document(DOM::Document& document, Utf16String error_string) { auto html_element = MUST(DOM::create_element(document, HTML::TagNames::html, Namespace::HTML)); auto body_element = MUST(DOM::create_element(document, HTML::TagNames::body, Namespace::HTML)); MUST(html_element->append_child(body_element)); - MUST(body_element->append_child(document.realm().create(document, error_string))); + MUST(body_element->append_child(document.realm().create(document, move(error_string)))); document.remove_all_children(); MUST(document.append_child(html_element)); } @@ -50,7 +50,7 @@ bool build_xml_document(DOM::Document& document, ByteBuffer const& data, Optiona VERIFY(decoder.has_value()); // Well-formed XML documents contain only properly encoded characters if (!decoder->validate(data)) { - convert_to_xml_error_document(document, "XML Document contains improperly-encoded characters"_string); + convert_to_xml_error_document(document, "XML Document contains improperly-encoded characters"_utf16); return false; } auto source = decoder->to_utf8(data).release_value_but_fixme_should_propagate_errors(); @@ -162,7 +162,7 @@ static WebIDL::ExceptionOr> load_xml_document(HTML::Navig if (!decoder->validate(data)) { // FIXME: Insert error message into the document. dbgln("XML Document contains improperly-encoded characters"); - convert_to_xml_error_document(document, "XML Document contains improperly-encoded characters"_string); + convert_to_xml_error_document(document, "XML Document contains improperly-encoded characters"_utf16); // NOTE: This ensures that the `load` event gets fired for the frame loading this document. document->completely_finish_loading(); @@ -172,7 +172,7 @@ static WebIDL::ExceptionOr> load_xml_document(HTML::Navig if (source.is_error()) { // FIXME: Insert error message into the document. dbgln("Failed to decode XML document: {}", source.error()); - convert_to_xml_error_document(document, MUST(String::formatted("Failed to decode XML document: {}", source.error()))); + convert_to_xml_error_document(document, Utf16String::formatted("Failed to decode XML document: {}", source.error())); // NOTE: This ensures that the `load` event gets fired for the frame loading this document. document->completely_finish_loading(); @@ -184,7 +184,7 @@ static WebIDL::ExceptionOr> load_xml_document(HTML::Navig if (result.is_error()) { // FIXME: Insert error message into the document. dbgln("Failed to parse XML document: {}", result.error()); - convert_to_xml_error_document(document, MUST(String::formatted("Failed to parse XML document: {}", result.error()))); + convert_to_xml_error_document(document, Utf16String::formatted("Failed to parse XML document: {}", result.error())); // NOTE: XMLDocumentBuilder ensures that the `load` event gets fired. We don't need to do anything else here. } @@ -246,10 +246,10 @@ static WebIDL::ExceptionOr> load_text_document(HTML::Navi // 5. User agents may add content to the head element of document, e.g., linking to a style sheet, providing // script, or giving the document a title. - auto title = MUST(String::from_byte_string(LexicalPath::basename(url.to_byte_string()))); + auto title = Utf16String::from_utf8_with_replacement_character(LexicalPath::basename(url.to_byte_string())); auto title_element = MUST(DOM::create_element(document, HTML::TagNames::title, Namespace::HTML)); MUST(document->head()->append_child(title_element)); - auto title_text = document->realm().create(document, title); + auto title_text = document->realm().create(document, move(title)); MUST(title_element->append_child(*title_text)); }); @@ -283,11 +283,13 @@ static WebIDL::ExceptionOr> load_media_document(HTML::Nav // video, or audio resource. // 6. User agents may add content to the head element of document, or attributes to host element, e.g., to link // to a style sheet, to provide a script, to give the document a title, or to make the media autoplay. - auto insert_title = [](auto& document, auto title) -> WebIDL::ExceptionOr { + auto insert_title = [](auto& document, auto const& document_url) -> WebIDL::ExceptionOr { + auto title = Utf16String::from_utf8_with_replacement_character(LexicalPath::basename(document_url.to_byte_string())); + auto title_element = TRY(DOM::create_element(document, HTML::TagNames::title, Namespace::HTML)); TRY(document->head()->append_child(title_element)); - auto title_text = document->realm().template create(document, title); + auto title_text = document->realm().template create(document, move(title)); TRY(title_element->append_child(*title_text)); return {}; }; @@ -315,7 +317,7 @@ static WebIDL::ExceptionOr> load_media_document(HTML::Nav auto img_element = TRY(DOM::create_element(document, HTML::TagNames::img, Namespace::HTML)); TRY(img_element->set_attribute(HTML::AttributeNames::src, url_string)); TRY(document->body()->append_child(img_element)); - TRY(insert_title(document, MUST(String::from_byte_string(LexicalPath::basename(url_string.to_byte_string()))))); + TRY(insert_title(document, url_string)); } else if (type.type() == "video"sv) { auto video_element = TRY(DOM::create_element(document, HTML::TagNames::video, Namespace::HTML)); @@ -323,7 +325,7 @@ static WebIDL::ExceptionOr> load_media_document(HTML::Nav TRY(video_element->set_attribute(HTML::AttributeNames::autoplay, String {})); TRY(video_element->set_attribute(HTML::AttributeNames::controls, String {})); TRY(document->body()->append_child(video_element)); - TRY(insert_title(document, MUST(String::from_byte_string(LexicalPath::basename(url_string.to_byte_string()))))); + TRY(insert_title(document, url_string)); } else if (type.type() == "audio"sv) { auto audio_element = TRY(DOM::create_element(document, HTML::TagNames::audio, Namespace::HTML)); @@ -331,7 +333,7 @@ static WebIDL::ExceptionOr> load_media_document(HTML::Nav TRY(audio_element->set_attribute(HTML::AttributeNames::autoplay, String {})); TRY(audio_element->set_attribute(HTML::AttributeNames::controls, String {})); TRY(document->body()->append_child(audio_element)); - TRY(insert_title(document, MUST(String::from_byte_string(LexicalPath::basename(url_string.to_byte_string()))))); + TRY(insert_title(document, url_string)); } else { // FIXME: According to https://mimesniff.spec.whatwg.org/#audio-or-video-mime-type we might have to deal with diff --git a/Libraries/LibWeb/DOM/Element.cpp b/Libraries/LibWeb/DOM/Element.cpp index 9557d992a28..72212e9b169 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -2200,7 +2200,7 @@ WebIDL::ExceptionOr> Element::insert_adjacent_element(String co } // https://dom.spec.whatwg.org/#dom-element-insertadjacenttext -WebIDL::ExceptionOr Element::insert_adjacent_text(String const& where, String const& data) +WebIDL::ExceptionOr Element::insert_adjacent_text(String const& where, Utf16String const& data) { // 1. Let text be a new Text node whose data is data and node document is this’s node document. auto text = realm().create(document(), data); diff --git a/Libraries/LibWeb/DOM/Element.h b/Libraries/LibWeb/DOM/Element.h index bbf446f768f..acd39a46591 100644 --- a/Libraries/LibWeb/DOM/Element.h +++ b/Libraries/LibWeb/DOM/Element.h @@ -306,7 +306,7 @@ public: bool is_actually_disabled() const; WebIDL::ExceptionOr> insert_adjacent_element(String const& where, GC::Ref element); - WebIDL::ExceptionOr insert_adjacent_text(String const& where, String const& data); + WebIDL::ExceptionOr insert_adjacent_text(String const& where, Utf16String const& data); // https://w3c.github.io/csswg-drafts/cssom-view-1/#dom-element-scrollintoview ErrorOr scroll_into_view(Optional> = {}); diff --git a/Libraries/LibWeb/DOM/Element.idl b/Libraries/LibWeb/DOM/Element.idl index ae41cbc42ed..b94a50213f7 100644 --- a/Libraries/LibWeb/DOM/Element.idl +++ b/Libraries/LibWeb/DOM/Element.idl @@ -77,7 +77,7 @@ interface Element : Node { HTMLCollection getElementsByClassName(DOMString className); [CEReactions] Element? insertAdjacentElement(DOMString where, Element element); // legacy - undefined insertAdjacentText(DOMString where, DOMString data); // legacy + undefined insertAdjacentText(DOMString where, Utf16DOMString data); // legacy // https://dom.spec.whatwg.org/#interface-nondocumenttypechildnode readonly attribute Element? nextElementSibling; diff --git a/Libraries/LibWeb/DOM/Node.cpp b/Libraries/LibWeb/DOM/Node.cpp index c333e985d49..2ee9da8dacb 100644 --- a/Libraries/LibWeb/DOM/Node.cpp +++ b/Libraries/LibWeb/DOM/Node.cpp @@ -186,7 +186,7 @@ Optional Node::text_content() const // If CharacterData, return this’s data. if (is(this)) - return static_cast(*this).data(); + return static_cast(*this).data().to_utf8_but_should_be_ported_to_utf16(); // If Attr node, return this's value. if (is(*this)) @@ -214,9 +214,8 @@ void Node::set_text_content(Optional const& maybe_content) // If CharacterData, replace data with node this, offset 0, count this’s length, and data the given value. else if (is(this)) { - auto* character_data_node = as(this); - character_data_node->set_data(content); + character_data_node->set_data(Utf16String::from_utf8(content)); // FIXME: CharacterData::set_data is not spec compliant. Make this match the spec when set_data becomes spec compliant. // Do note that this will make this function able to throw an exception. @@ -288,12 +287,12 @@ WebIDL::ExceptionOr Node::normalize() } // 3. Let data be the concatenation of the data of node’s contiguous exclusive Text nodes (excluding itself), in tree order. - StringBuilder data; + StringBuilder data(StringBuilder::Mode::UTF16); for (auto const& text_node : contiguous_exclusive_text_nodes_excluding_self(node)) data.append(text_node->data()); // 4. Replace data with node node, offset length, count 0, and data data. - TRY(character_data.replace_data(length, 0, MUST(data.to_string()))); + TRY(character_data.replace_data(length, 0, data.to_utf16_string())); // 5. Let currentNode be node’s next sibling. auto* current_node = node.next_sibling(); @@ -363,7 +362,7 @@ Optional Node::node_value() const // If CharacterData, return this’s data. if (is(this)) { - return as(this)->data(); + return as(this)->data().to_utf8_but_should_be_ported_to_utf16(); } // Otherwise, return null. @@ -382,7 +381,7 @@ void Node::set_node_value(Optional const& maybe_value) as(this)->set_value(move(value)); } else if (is(this)) { // If CharacterData, replace data with node this, offset 0, count this’s length, and data the given value. - as(this)->set_data(value); + as(this)->set_data(Utf16String::from_utf8(value)); } // Otherwise, do nothing. @@ -1870,7 +1869,7 @@ bool Node::is_uninteresting_whitespace_node() const { if (!is(*this)) return false; - if (!static_cast(*this).data().bytes_as_string_view().is_whitespace()) + if (!static_cast(*this).data().is_ascii_whitespace()) return false; if (!layout_node()) return true; @@ -1936,10 +1935,10 @@ void Node::serialize_tree_as_json(JsonObjectSerializer& object) c MUST(object.add("type"sv, "text")); auto text_node = static_cast(this); - MUST(object.add("text"sv, text_node->data())); + MUST(object.add("text"sv, text_node->data().to_utf8())); } else if (is_comment()) { MUST(object.add("type"sv, "comment"sv)); - MUST(object.add("data"sv, static_cast(*this).data())); + MUST(object.add("data"sv, static_cast(*this).data().to_utf8())); } else if (is_shadow_root()) { MUST(object.add("type"sv, "shadow-root")); MUST(object.add("mode"sv, static_cast(*this).mode() == Bindings::ShadowRootMode::Open ? "open"sv : "closed"sv)); @@ -2053,7 +2052,7 @@ void Node::string_replace_all(String const& string) // 2. If string is not the empty string, then set node to a new Text node whose data is string and node document is parent’s node document. if (!string.is_empty()) - node = realm().create(document(), string); + node = realm().create(document(), Utf16String::from_utf8(string)); // 3. Replace all with node within parent. replace_all(node); diff --git a/Libraries/LibWeb/DOM/NodeOperations.cpp b/Libraries/LibWeb/DOM/NodeOperations.cpp index b6299660b2f..3427f2ef1c1 100644 --- a/Libraries/LibWeb/DOM/NodeOperations.cpp +++ b/Libraries/LibWeb/DOM/NodeOperations.cpp @@ -5,7 +5,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include #include @@ -15,7 +15,7 @@ namespace Web::DOM { // https://dom.spec.whatwg.org/#converting-nodes-into-a-node -WebIDL::ExceptionOr> convert_nodes_to_single_node(Vector, String>> const& nodes, DOM::Document& document) +WebIDL::ExceptionOr> convert_nodes_to_single_node(Vector, Utf16String>> const& nodes, DOM::Document& document) { // 1. Let node be null. // 2. Replace each string in nodes with a new Text node whose data is the string and node document is document. @@ -23,11 +23,11 @@ WebIDL::ExceptionOr> convert_nodes_to_single_node(Vector, String> const& node) -> GC::Ref { + auto potentially_convert_string_to_text_node = [&document](Variant, Utf16String> const& node) -> GC::Ref { if (node.has>()) return *node.get>(); - return document.realm().create(document, node.get()); + return document.realm().create(document, node.get()); }; if (nodes.size() == 1) diff --git a/Libraries/LibWeb/DOM/NodeOperations.h b/Libraries/LibWeb/DOM/NodeOperations.h index b493e4b09b6..e45a8b57a7a 100644 --- a/Libraries/LibWeb/DOM/NodeOperations.h +++ b/Libraries/LibWeb/DOM/NodeOperations.h @@ -13,6 +13,6 @@ namespace Web::DOM { -WebIDL::ExceptionOr> convert_nodes_to_single_node(Vector, String>> const& nodes, DOM::Document& document); +WebIDL::ExceptionOr> convert_nodes_to_single_node(Vector, Utf16String>> const& nodes, DOM::Document& document); } diff --git a/Libraries/LibWeb/DOM/ParentNode.cpp b/Libraries/LibWeb/DOM/ParentNode.cpp index ae0c2e8cc1f..530866d67e9 100644 --- a/Libraries/LibWeb/DOM/ParentNode.cpp +++ b/Libraries/LibWeb/DOM/ParentNode.cpp @@ -209,7 +209,7 @@ GC::Ref ParentNode::get_elements_by_tag_name_ns(Optional ParentNode::prepend(Vector, String>> const& nodes) +WebIDL::ExceptionOr ParentNode::prepend(Vector, Utf16String>> const& nodes) { // 1. Let node be the result of converting nodes into a node given nodes and this’s node document. auto node = TRY(convert_nodes_to_single_node(nodes, document())); @@ -220,7 +220,7 @@ WebIDL::ExceptionOr ParentNode::prepend(Vector, Str return {}; } -WebIDL::ExceptionOr ParentNode::append(Vector, String>> const& nodes) +WebIDL::ExceptionOr ParentNode::append(Vector, Utf16String>> const& nodes) { // 1. Let node be the result of converting nodes into a node given nodes and this’s node document. auto node = TRY(convert_nodes_to_single_node(nodes, document())); @@ -231,7 +231,7 @@ WebIDL::ExceptionOr ParentNode::append(Vector, Stri return {}; } -WebIDL::ExceptionOr ParentNode::replace_children(Vector, String>> const& nodes) +WebIDL::ExceptionOr ParentNode::replace_children(Vector, Utf16String>> const& nodes) { // 1. Let node be the result of converting nodes into a node given nodes and this’s node document. auto node = TRY(convert_nodes_to_single_node(nodes, document())); diff --git a/Libraries/LibWeb/DOM/ParentNode.h b/Libraries/LibWeb/DOM/ParentNode.h index 1076567897f..6d44751e96a 100644 --- a/Libraries/LibWeb/DOM/ParentNode.h +++ b/Libraries/LibWeb/DOM/ParentNode.h @@ -32,9 +32,9 @@ public: GC::Ref get_elements_by_tag_name(FlyString const&); GC::Ref get_elements_by_tag_name_ns(Optional, FlyString const&); - WebIDL::ExceptionOr prepend(Vector, String>> const& nodes); - WebIDL::ExceptionOr append(Vector, String>> const& nodes); - WebIDL::ExceptionOr replace_children(Vector, String>> const& nodes); + WebIDL::ExceptionOr prepend(Vector, Utf16String>> const& nodes); + WebIDL::ExceptionOr append(Vector, Utf16String>> const& nodes); + WebIDL::ExceptionOr replace_children(Vector, Utf16String>> const& nodes); WebIDL::ExceptionOr move_before(GC::Ref node, GC::Ptr child); GC::Ref get_elements_by_class_name(StringView); diff --git a/Libraries/LibWeb/DOM/ParentNode.idl b/Libraries/LibWeb/DOM/ParentNode.idl index f17f4a1b3ce..e2915cf1c8e 100644 --- a/Libraries/LibWeb/DOM/ParentNode.idl +++ b/Libraries/LibWeb/DOM/ParentNode.idl @@ -8,9 +8,9 @@ interface mixin ParentNode { readonly attribute Element? lastElementChild; readonly attribute unsigned long childElementCount; - [CEReactions, Unscopable] undefined prepend((Node or DOMString)... nodes); - [CEReactions, Unscopable] undefined append((Node or DOMString)... nodes); - [CEReactions, Unscopable] undefined replaceChildren((Node or DOMString)... nodes); + [CEReactions, Unscopable] undefined prepend((Node or Utf16DOMString)... nodes); + [CEReactions, Unscopable] undefined append((Node or Utf16DOMString)... nodes); + [CEReactions, Unscopable] undefined replaceChildren((Node or Utf16DOMString)... nodes); [CEReactions] undefined moveBefore(Node node, Node? child); diff --git a/Libraries/LibWeb/DOM/ProcessingInstruction.cpp b/Libraries/LibWeb/DOM/ProcessingInstruction.cpp index feeb6e7dd11..1b1c46e1dfd 100644 --- a/Libraries/LibWeb/DOM/ProcessingInstruction.cpp +++ b/Libraries/LibWeb/DOM/ProcessingInstruction.cpp @@ -14,8 +14,8 @@ namespace Web::DOM { GC_DEFINE_ALLOCATOR(ProcessingInstruction); -ProcessingInstruction::ProcessingInstruction(Document& document, String const& data, String const& target) - : CharacterData(document, NodeType::PROCESSING_INSTRUCTION_NODE, data) +ProcessingInstruction::ProcessingInstruction(Document& document, Utf16String data, String const& target) + : CharacterData(document, NodeType::PROCESSING_INSTRUCTION_NODE, move(data)) , m_target(target) { } diff --git a/Libraries/LibWeb/DOM/ProcessingInstruction.h b/Libraries/LibWeb/DOM/ProcessingInstruction.h index f559c0ac186..4e06ca17408 100644 --- a/Libraries/LibWeb/DOM/ProcessingInstruction.h +++ b/Libraries/LibWeb/DOM/ProcessingInstruction.h @@ -22,7 +22,7 @@ public: String const& target() const { return m_target; } private: - ProcessingInstruction(Document&, String const& data, String const& target); + ProcessingInstruction(Document&, Utf16String data, String const& target); virtual void initialize(JS::Realm&) override; diff --git a/Libraries/LibWeb/DOM/Range.cpp b/Libraries/LibWeb/DOM/Range.cpp index a57e0c0b490..f2da2dc1687 100644 --- a/Libraries/LibWeb/DOM/Range.cpp +++ b/Libraries/LibWeb/DOM/Range.cpp @@ -558,7 +558,7 @@ String Range::to_string() const // then return the substring of that Text node’s data beginning at this’s start offset and ending at this’s end offset. if (start_container() == end_container() && is(*start_container())) { auto const& text = static_cast(*start_container()); - return MUST(text.substring_data(start_offset(), end_offset() - start_offset())); + return MUST(text.substring_data(start_offset(), end_offset() - start_offset())).to_utf8_but_should_be_ported_to_utf16(); } // 3. If this’s start node is a Text node, then append the substring of that node’s data from this’s start offset until the end to s. @@ -621,7 +621,7 @@ WebIDL::ExceptionOr> Range::extract() TRY(fragment->append_child(clone)); // 4. Replace data with node original start node, offset original start offset, count original end offset minus original start offset, and data the empty string. - TRY(static_cast(*original_start_node).replace_data(original_start_offset, original_end_offset - original_start_offset, String {})); + TRY(static_cast(*original_start_node).replace_data(original_start_offset, original_end_offset - original_start_offset, {})); // 5. Return fragment. return fragment; @@ -711,7 +711,7 @@ WebIDL::ExceptionOr> Range::extract() TRY(fragment->append_child(clone)); // 4. Replace data with node original start node, offset original start offset, count original start node’s length minus original start offset, and data the empty string. - TRY(static_cast(*original_start_node).replace_data(original_start_offset, original_start_node->length() - original_start_offset, String {})); + TRY(static_cast(*original_start_node).replace_data(original_start_offset, original_start_node->length() - original_start_offset, {})); } // 16. Otherwise, if first partially contained child is not null: else if (first_partially_contained_child) { @@ -749,7 +749,7 @@ WebIDL::ExceptionOr> Range::extract() TRY(fragment->append_child(clone)); // 4. Replace data with node original end node, offset 0, count original end offset, and data the empty string. - TRY(as(*original_end_node).replace_data(0, original_end_offset, String {})); + TRY(as(*original_end_node).replace_data(0, original_end_offset, {})); } // 19. Otherwise, if last partially contained child is not null: else if (last_partially_contained_child) { @@ -1088,7 +1088,7 @@ WebIDL::ExceptionOr Range::delete_contents() // 3. If original start node is original end node and it is a CharacterData node, then replace data with node original start node, offset original start offset, // count original end offset minus original start offset, and data the empty string, and then return. if (original_start_node.ptr() == original_end_node.ptr() && is(*original_start_node)) { - TRY(static_cast(*original_start_node).replace_data(original_start_offset, original_end_offset - original_start_offset, String {})); + TRY(static_cast(*original_start_node).replace_data(original_start_offset, original_end_offset - original_start_offset, {})); return {}; } @@ -1123,7 +1123,7 @@ WebIDL::ExceptionOr Range::delete_contents() // 7. If original start node is a CharacterData node, then replace data with node original start node, offset original start offset, count original start node’s length minus original start offset, data the empty string. if (is(*original_start_node)) - TRY(static_cast(*original_start_node).replace_data(original_start_offset, original_start_node->length() - original_start_offset, String {})); + TRY(static_cast(*original_start_node).replace_data(original_start_offset, original_start_node->length() - original_start_offset, {})); // 8. For each node in nodes to remove, in tree order, remove node. for (auto& node : nodes_to_remove) @@ -1131,7 +1131,7 @@ WebIDL::ExceptionOr Range::delete_contents() // 9. If original end node is a CharacterData node, then replace data with node original end node, offset 0, count original end offset and data the empty string. if (is(*original_end_node)) - TRY(static_cast(*original_end_node).replace_data(0, original_end_offset, String {})); + TRY(static_cast(*original_end_node).replace_data(0, original_end_offset, {})); // 10. Set start and end to (new node, new offset). TRY(set_start(*new_node, new_offset)); diff --git a/Libraries/LibWeb/DOM/Text.cpp b/Libraries/LibWeb/DOM/Text.cpp index b09164da6d1..284ba43a43b 100644 --- a/Libraries/LibWeb/DOM/Text.cpp +++ b/Libraries/LibWeb/DOM/Text.cpp @@ -18,13 +18,13 @@ namespace Web::DOM { GC_DEFINE_ALLOCATOR(Text); -Text::Text(Document& document, String const& data) - : CharacterData(document, NodeType::TEXT_NODE, data) +Text::Text(Document& document, Utf16String data) + : CharacterData(document, NodeType::TEXT_NODE, move(data)) { } -Text::Text(Document& document, NodeType type, String const& data) - : CharacterData(document, type, data) +Text::Text(Document& document, NodeType type, Utf16String data) + : CharacterData(document, type, move(data)) { } @@ -41,11 +41,11 @@ void Text::visit_edges(Cell::Visitor& visitor) } // https://dom.spec.whatwg.org/#dom-text-text -WebIDL::ExceptionOr> Text::construct_impl(JS::Realm& realm, String const& data) +WebIDL::ExceptionOr> Text::construct_impl(JS::Realm& realm, Utf16String data) { // The new Text(data) constructor steps are to set this’s data to data and this’s node document to current global object’s associated Document. auto& window = as(HTML::current_principal_global_object()); - return realm.create(window.associated_document(), data); + return realm.create(window.associated_document(), move(data)); } // https://dom.spec.whatwg.org/#dom-text-splittext @@ -110,14 +110,14 @@ WebIDL::ExceptionOr> Text::split_text(size_t offset) } // 8. Replace data with node node, offset offset, count count, and data the empty string. - TRY(replace_data(offset, count, String {})); + TRY(replace_data(offset, count, {})); // 9. Return new node. return new_node; } // https://dom.spec.whatwg.org/#dom-text-wholetext -String Text::whole_text() +Utf16String Text::whole_text() { // https://dom.spec.whatwg.org/#contiguous-text-nodes // The contiguous Text nodes of a node node are node, node’s previous sibling Text node, if any, and its contiguous @@ -141,11 +141,11 @@ String Text::whole_text() current_node = current_node->next_sibling(); } - StringBuilder builder; + StringBuilder builder(StringBuilder::Mode::UTF16); for (auto const& text_node : nodes) builder.append(text_node->data()); - return MUST(builder.to_string()); + return builder.to_utf16_string(); } // https://html.spec.whatwg.org/multipage/dom.html#text-node-directionality @@ -154,7 +154,7 @@ Optional Text::directionality() const // 1. If text's data does not contain a code point whose bidirectional character type is L, AL, or R, then return null. // 2. Let codePoint be the first code point in text's data whose bidirectional character type is L, AL, or R. Optional found_character_bidi_class; - for (auto code_point : Utf8View(data())) { + for (auto code_point : data()) { auto bidi_class = Unicode::bidirectional_class(code_point); if (first_is_one_of(bidi_class, Unicode::BidiClass::LeftToRight, Unicode::BidiClass::RightToLeftArabic, Unicode::BidiClass::RightToLeft)) { found_character_bidi_class = bidi_class; diff --git a/Libraries/LibWeb/DOM/Text.h b/Libraries/LibWeb/DOM/Text.h index 5639f912560..2bd7ab719f3 100644 --- a/Libraries/LibWeb/DOM/Text.h +++ b/Libraries/LibWeb/DOM/Text.h @@ -22,7 +22,7 @@ class Text public: virtual ~Text() override = default; - static WebIDL::ExceptionOr> construct_impl(JS::Realm& realm, String const& data); + static WebIDL::ExceptionOr> construct_impl(JS::Realm& realm, Utf16String data); // ^Node virtual FlyString node_name() const override { return "#text"_fly_string; } @@ -31,7 +31,7 @@ public: void set_max_length(Optional max_length) { m_max_length = move(max_length); } WebIDL::ExceptionOr> split_text(size_t offset); - String whole_text(); + Utf16String whole_text(); bool is_password_input() const { return m_is_password_input; } void set_is_password_input(Badge, bool b) { m_is_password_input = b; } @@ -39,8 +39,8 @@ public: Optional directionality() const; protected: - Text(Document&, String const&); - Text(Document&, NodeType, String const&); + Text(Document&, Utf16String); + Text(Document&, NodeType, Utf16String); virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; diff --git a/Libraries/LibWeb/DOM/Text.idl b/Libraries/LibWeb/DOM/Text.idl index 059dcdf7fe7..02bd894f5c9 100644 --- a/Libraries/LibWeb/DOM/Text.idl +++ b/Libraries/LibWeb/DOM/Text.idl @@ -5,10 +5,10 @@ // https://dom.spec.whatwg.org/#text [Exposed=Window] interface Text : CharacterData { - constructor(optional DOMString data = ""); + constructor(optional Utf16DOMString data = ""); [NewObject] Text splitText(unsigned long offset); - readonly attribute DOMString wholeText; + readonly attribute Utf16DOMString wholeText; }; Text includes Slottable; diff --git a/Libraries/LibWeb/Editing/Commands.cpp b/Libraries/LibWeb/Editing/Commands.cpp index da51abe991b..ef232961ab0 100644 --- a/Libraries/LibWeb/Editing/Commands.cpp +++ b/Libraries/LibWeb/Editing/Commands.cpp @@ -1367,10 +1367,10 @@ bool command_insert_linebreak_action(DOM::Document& document, Utf16View const&) if (auto* text_node = as_if(*start_node); text_node) { auto resolved_white_space_collapse = resolved_keyword(*start_node, CSS::PropertyID::WhiteSpaceCollapse); if (resolved_white_space_collapse.has_value() && first_is_one_of(resolved_white_space_collapse.value(), CSS::Keyword::Preserve, CSS::Keyword::PreserveBreaks)) { - MUST(text_node->insert_data(active_range.start_offset(), "\n"_string)); + MUST(text_node->insert_data(active_range.start_offset(), "\n"_utf16)); MUST(selection.collapse(start_node, active_range.start_offset() + 1)); if (selection.range()->start_offset() == start_node->length()) - MUST(text_node->insert_data(active_range.start_offset(), "\n"_string)); + MUST(text_node->insert_data(active_range.start_offset(), "\n"_utf16)); return true; } } @@ -1796,7 +1796,7 @@ bool command_insert_text_action(DOM::Document& document, Utf16View const& value) // 13. If node is a Text node: if (is(*node)) { // 1. Call insertData(offset, value) on node. - MUST(static_cast(*node).insert_data(offset, value.to_utf8_but_should_be_ported_to_utf16())); + MUST(static_cast(*node).insert_data(offset, value)); // 2. Call collapse(node, offset) on the context object's selection. MUST(selection.collapse(node, offset)); @@ -1812,7 +1812,7 @@ bool command_insert_text_action(DOM::Document& document, Utf16View const& value) node->first_child()->remove(); // 2. Let text be the result of calling createTextNode(value) on the context object. - auto text = document.create_text_node(value.to_utf8_but_should_be_ported_to_utf16()); + auto text = document.create_text_node(Utf16String::from_utf16_without_validation(value)); // 3. Call insertNode(text) on the active range. MUST(active_range(document)->insert_node(text)); diff --git a/Libraries/LibWeb/Editing/Internal/Algorithms.cpp b/Libraries/LibWeb/Editing/Internal/Algorithms.cpp index 6eb829144f4..eef836125eb 100644 --- a/Libraries/LibWeb/Editing/Internal/Algorithms.cpp +++ b/Libraries/LibWeb/Editing/Internal/Algorithms.cpp @@ -566,7 +566,7 @@ void canonicalize_whitespace(DOM::BoundaryPoint boundary, bool fix_collapsed_spa if (element != start_node_code_point) { // 1. Call insertData(start offset, element) on start node. auto& start_node_character_data = static_cast(*start_node); - MUST(start_node_character_data.insert_data(start_offset, String::from_code_point(element))); + MUST(start_node_character_data.insert_data(start_offset, Utf16String::from_code_point(element))); // 2. Call deleteData(start offset + 1, 1) on start node. MUST(start_node_character_data.delete_data(start_offset + 1, 1)); @@ -2615,8 +2615,7 @@ bool is_whitespace_node(GC::Ref node) auto is_tab_lf_cr_or_space = [](u32 codepoint) { return codepoint == '\t' || codepoint == '\n' || codepoint == '\r' || codepoint == ' '; }; - auto code_points = character_data.data().code_points(); - if (all_of(code_points, is_tab_lf_cr_or_space) && (white_space_collapse == CSS::Keyword::Collapse)) + if (all_of(character_data.data(), is_tab_lf_cr_or_space) && (white_space_collapse == CSS::Keyword::Collapse)) return true; // or a Text node whose data consists only of one or more tabs (0x0009), carriage returns @@ -2626,7 +2625,7 @@ bool is_whitespace_node(GC::Ref node) auto is_tab_cr_or_space = [](u32 codepoint) { return codepoint == '\t' || codepoint == '\r' || codepoint == ' '; }; - if (all_of(code_points, is_tab_cr_or_space) && white_space_collapse == CSS::Keyword::PreserveBreaks) + if (all_of(character_data.data(), is_tab_cr_or_space) && white_space_collapse == CSS::Keyword::PreserveBreaks) return true; return false; diff --git a/Libraries/LibWeb/HTML/FormAssociatedElement.cpp b/Libraries/LibWeb/HTML/FormAssociatedElement.cpp index 7ef9f01302f..9a2d7739883 100644 --- a/Libraries/LibWeb/HTML/FormAssociatedElement.cpp +++ b/Libraries/LibWeb/HTML/FormAssociatedElement.cpp @@ -806,7 +806,7 @@ void FormAssociatedTextControlElement::handle_insert(String const& data) String data_for_insertion = data; // FIXME: Cut by UTF-16 code units instead of raw bytes if (auto max_length = text_node->max_length(); max_length.has_value()) { - auto remaining_length = *max_length - text_node->data().code_points().length(); + auto remaining_length = *max_length - text_node->data().length_in_code_points(); if (remaining_length < data.code_points().length()) { data_for_insertion = MUST(data.substring_from_byte_offset(0, remaining_length)); } @@ -832,7 +832,7 @@ void FormAssociatedTextControlElement::handle_delete(DeleteDirection direction) MUST(set_range_text(String {}, selection_start - 1, selection_end, Bindings::SelectionMode::End)); } } else { - if (selection_start < text_node->data().code_points().length()) { + if (selection_start < text_node->data().length_in_code_points()) { MUST(set_range_text(String {}, selection_start, selection_end + 1, Bindings::SelectionMode::End)); } } @@ -982,7 +982,7 @@ void FormAssociatedTextControlElement::increment_cursor_position_to_next_word(Co while (true) { if (auto offset = text_node->word_segmenter().next_boundary(m_selection_end); offset.has_value()) { - auto word = text_node->data().code_points().substring_view(m_selection_end, *offset - m_selection_end); + auto word = text_node->data().substring_view(m_selection_end, *offset - m_selection_end); if (collapse == CollapseSelection::Yes) { collapse_selection_to_offset(*offset); } else { @@ -1005,7 +1005,7 @@ void FormAssociatedTextControlElement::decrement_cursor_position_to_previous_wor while (true) { if (auto offset = text_node->word_segmenter().previous_boundary(m_selection_end); offset.has_value()) { - auto word = text_node->data().code_points().substring_view(*offset, m_selection_end - *offset); + auto word = text_node->data().substring_view(*offset, m_selection_end - *offset); if (collapse == CollapseSelection::Yes) { collapse_selection_to_offset(*offset); } else { diff --git a/Libraries/LibWeb/HTML/HTMLElement.cpp b/Libraries/LibWeb/HTML/HTMLElement.cpp index 281f6719451..b907c35b5e5 100644 --- a/Libraries/LibWeb/HTML/HTMLElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLElement.cpp @@ -240,7 +240,7 @@ WebIDL::ExceptionOr HTMLElement::set_outer_text(String const& value) // 5. If fragment has no children, then append a new Text node whose data is the empty string and node document is this's node document to fragment. if (!fragment->has_children()) - MUST(fragment->append_child(document().create_text_node(String {}))); + MUST(fragment->append_child(document().create_text_node({}))); // 6. Replace this with fragment within this's parent. MUST(parent()->replace_child(fragment, *this)); @@ -276,7 +276,7 @@ GC::Ref HTMLElement::rendered_text_fragment(StringView in // 2. If text is not the empty string, then append a new Text node whose data is text and node document is document to fragment. if (!text.is_empty()) { - MUST(fragment->append_child(document().create_text_node(MUST(String::from_utf8(text))))); + MUST(fragment->append_child(document().create_text_node(Utf16String::from_utf8(text)))); } // 3. While position is not past the end of input, and the code point at position is either U+000A LF or U+000D CR: diff --git a/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Libraries/LibWeb/HTML/HTMLInputElement.cpp index 89d7785a42c..c56e6a5db8e 100644 --- a/Libraries/LibWeb/HTML/HTMLInputElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLInputElement.cpp @@ -530,7 +530,7 @@ void HTMLInputElement::did_edit_text_node() { // An input element's dirty value flag must be set to true whenever the user interacts with the control in a way that changes the value. auto old_value = move(m_value); - m_value = value_sanitization_algorithm(m_text_node->data()); + m_value = value_sanitization_algorithm(m_text_node->data().to_utf8_but_should_be_ported_to_utf16()); m_dirty_value = true; m_has_uncommitted_changes = true; @@ -700,7 +700,7 @@ WebIDL::ExceptionOr HTMLInputElement::set_value(String const& value) relevant_value_was_changed(); if (m_text_node) { - m_text_node->set_data(m_value); + m_text_node->set_data(Utf16String::from_utf8(m_value)); update_placeholder_visibility(); set_the_selection_range(m_text_node->length(), m_text_node->length()); @@ -819,7 +819,7 @@ void HTMLInputElement::update_button_input_shadow_tree() } } - m_text_node->set_data(label.value()); + m_text_node->set_data(Utf16String::from_utf8(label.value())); update_placeholder_visibility(); } } @@ -827,7 +827,7 @@ void HTMLInputElement::update_button_input_shadow_tree() void HTMLInputElement::update_text_input_shadow_tree() { if (m_text_node) { - m_text_node->set_data(m_value); + m_text_node->set_data(Utf16String::from_utf8(m_value)); update_placeholder_visibility(); } } @@ -1018,7 +1018,7 @@ void HTMLInputElement::create_button_input_shadow_tree() label = value(); } } - m_text_node = realm().create(document(), label.value()); + m_text_node = realm().create(document(), Utf16String::from_utf8(label.value())); MUST(text_container->append_child(*m_text_node)); MUST(shadow_root->append_child(*text_container)); } @@ -1053,8 +1053,7 @@ void HTMLInputElement::create_text_input_shadow_tree() MUST(element->append_child(*m_placeholder_element)); - m_placeholder_text_node = realm().create(document(), String {}); - m_placeholder_text_node->set_data(placeholder()); + m_placeholder_text_node = realm().create(document(), Utf16String::from_utf8(placeholder())); MUST(m_placeholder_element->append_child(*m_placeholder_text_node)); // https://www.w3.org/TR/css-ui-4/#input-rules @@ -1075,7 +1074,7 @@ void HTMLInputElement::create_text_input_shadow_tree() } MUST(element->append_child(*m_inner_text_element)); - m_text_node = realm().create(document(), move(initial_value)); + m_text_node = realm().create(document(), Utf16String::from_utf8(initial_value)); handle_readonly_attribute(attribute(HTML::AttributeNames::readonly)); if (type_state() == TypeAttributeState::Password) m_text_node->set_is_password_input({}, true); @@ -1421,7 +1420,7 @@ void HTMLInputElement::form_associated_element_attribute_changed(FlyString const } } else if (name == HTML::AttributeNames::placeholder) { if (m_placeholder_text_node) { - m_placeholder_text_node->set_data(placeholder()); + m_placeholder_text_node->set_data(Utf16String::from_utf8(placeholder())); update_placeholder_visibility(); } } else if (name == HTML::AttributeNames::readonly) { @@ -1771,7 +1770,7 @@ void HTMLInputElement::reset_algorithm() relevant_value_was_changed(); if (m_text_node) { - m_text_node->set_data(m_value); + m_text_node->set_data(Utf16String::from_utf8(m_value)); update_placeholder_visibility(); } @@ -1807,7 +1806,7 @@ void HTMLInputElement::clear_algorithm() relevant_value_was_changed(); if (m_text_node) { - m_text_node->set_data(m_value); + m_text_node->set_data(Utf16String::from_utf8(m_value)); update_placeholder_visibility(); } diff --git a/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp b/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp index 1a6f3d2ad48..1e94bb65fbb 100644 --- a/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp @@ -191,7 +191,7 @@ void HTMLTextAreaElement::set_value(String const& value) // the text control, unselecting any selected text and resetting the selection direction to "none". if (api_value() != old_api_value) { if (m_text_node) { - m_text_node->set_data(m_raw_value); + m_text_node->set_data(Utf16String::from_utf8(m_raw_value)); update_placeholder_visibility(); set_the_selection_range(m_text_node->length(), m_text_node->length()); @@ -369,14 +369,13 @@ void HTMLTextAreaElement::create_shadow_tree_if_needed() m_placeholder_element->set_use_pseudo_element(CSS::PseudoElement::Placeholder); MUST(element->append_child(*m_placeholder_element)); - m_placeholder_text_node = realm().create(document(), String {}); - m_placeholder_text_node->set_data(get_attribute_value(HTML::AttributeNames::placeholder)); + m_placeholder_text_node = realm().create(document(), Utf16String::from_utf8(get_attribute_value(HTML::AttributeNames::placeholder))); MUST(m_placeholder_element->append_child(*m_placeholder_text_node)); m_inner_text_element = MUST(DOM::create_element(document(), HTML::TagNames::div, Namespace::HTML)); MUST(element->append_child(*m_inner_text_element)); - m_text_node = realm().create(document(), String {}); + m_text_node = realm().create(document(), Utf16String {}); handle_readonly_attribute(attribute(HTML::AttributeNames::readonly)); // NOTE: If `children_changed()` was called before now, `m_raw_value` will hold the text content. // Otherwise, it will get filled in whenever that does get called. @@ -442,7 +441,7 @@ void HTMLTextAreaElement::form_associated_element_attribute_changed(FlyString co { if (name == HTML::AttributeNames::placeholder) { if (m_placeholder_text_node) - m_placeholder_text_node->set_data(value.value_or(String {})); + m_placeholder_text_node->set_data(Utf16String::from_utf8(value.value_or(String {}))); } else if (name == HTML::AttributeNames::readonly) { handle_readonly_attribute(value); } else if (name == HTML::AttributeNames::maxlength) { @@ -453,7 +452,7 @@ void HTMLTextAreaElement::form_associated_element_attribute_changed(FlyString co void HTMLTextAreaElement::did_edit_text_node() { VERIFY(m_text_node); - set_raw_value(m_text_node->data()); + set_raw_value(m_text_node->data().to_utf8_but_should_be_ported_to_utf16()); // Any time the user causes the element's raw value to change, the user agent must queue an element task on the user // interaction task source given the textarea element to fire an event named input at the textarea element, with the diff --git a/Libraries/LibWeb/HTML/Navigable.cpp b/Libraries/LibWeb/HTML/Navigable.cpp index 838a602c651..d1081c8ea32 100644 --- a/Libraries/LibWeb/HTML/Navigable.cpp +++ b/Libraries/LibWeb/HTML/Navigable.cpp @@ -2483,11 +2483,11 @@ static String visible_text_in_range(DOM::Range const& range) if (range.start_container() == range.end_container() && is(*range.start_container())) { if (!range.start_container()->layout_node()) return String {}; - return MUST(static_cast(*range.start_container()).data().substring_from_byte_offset(range.start_offset(), range.end_offset() - range.start_offset())); + return static_cast(*range.start_container()).data().substring_view(range.start_offset(), range.end_offset() - range.start_offset()).to_utf8_but_should_be_ported_to_utf16(); } if (is(*range.start_container()) && range.start_container()->layout_node()) - builder.append(static_cast(*range.start_container()).data().bytes_as_string_view().substring_view(range.start_offset())); + builder.append(static_cast(*range.start_container()).data().substring_view(range.start_offset())); range.for_each_contained([&](GC::Ref node) { if (is(*node) && node->layout_node()) @@ -2496,7 +2496,7 @@ static String visible_text_in_range(DOM::Range const& range) }); if (is(*range.end_container()) && range.end_container()->layout_node()) - builder.append(static_cast(*range.end_container()).data().bytes_as_string_view().substring_view(0, range.end_offset())); + builder.append(static_cast(*range.end_container()).data().substring_view(0, range.end_offset())); return MUST(builder.to_string()); } diff --git a/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp b/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp index a1db3c6252c..2f4914a3b17 100644 --- a/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp +++ b/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp @@ -576,7 +576,7 @@ void HTMLParser::handle_initial(HTMLToken& token) // -> A comment token if (token.is_comment()) { // Insert a comment as the last child of the Document object. - auto comment = realm().create(document(), token.comment()); + auto comment = realm().create(document(), Utf16String::from_utf8(token.comment())); MUST(document().append_child(*comment)); return; } @@ -632,7 +632,7 @@ void HTMLParser::handle_before_html(HTMLToken& token) // -> A comment token if (token.is_comment()) { // Insert a comment as the last child of the Document object. - auto comment = realm().create(document(), token.comment()); + auto comment = realm().create(document(), Utf16String::from_utf8(token.comment())); MUST(document().append_child(*comment)); return; } @@ -985,7 +985,7 @@ void HTMLParser::handle_before_head(HTMLToken& token) void HTMLParser::insert_comment(HTMLToken& token) { auto adjusted_insertion_location = find_appropriate_place_for_inserting_node(); - adjusted_insertion_location.parent->insert_before(realm().create(document(), token.comment()), adjusted_insertion_location.insert_before_sibling); + adjusted_insertion_location.parent->insert_before(realm().create(document(), Utf16String::from_utf8(token.comment())), adjusted_insertion_location.insert_before_sibling); } // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inhead @@ -1392,7 +1392,7 @@ DOM::Text* HTMLParser::find_character_insertion_node() if (adjusted_insertion_location.insert_before_sibling) { if (is_text_node(adjusted_insertion_location.insert_before_sibling->previous_sibling())) return static_cast(adjusted_insertion_location.insert_before_sibling->previous_sibling()); - auto new_text_node = realm().create(document(), String {}); + auto new_text_node = realm().create(document(), Utf16String {}); adjusted_insertion_location.parent->insert_before(*new_text_node, *adjusted_insertion_location.insert_before_sibling); return new_text_node; } @@ -1400,7 +1400,7 @@ DOM::Text* HTMLParser::find_character_insertion_node() return nullptr; if (is_text_node(adjusted_insertion_location.parent->last_child())) return static_cast(adjusted_insertion_location.parent->last_child()); - auto new_text_node = realm().create(document(), String {}); + auto new_text_node = realm().create(document(), Utf16String {}); MUST(adjusted_insertion_location.parent->append_child(*new_text_node)); return new_text_node; } @@ -1410,9 +1410,9 @@ void HTMLParser::flush_character_insertions() if (m_character_insertion_builder.is_empty()) return; if (m_character_insertion_node->data().is_empty()) - m_character_insertion_node->set_data(MUST(m_character_insertion_builder.to_string())); + m_character_insertion_node->set_data(m_character_insertion_builder.to_utf16_string()); else - (void)m_character_insertion_node->append_data(MUST(m_character_insertion_builder.to_string())); + (void)m_character_insertion_node->append_data(m_character_insertion_builder.to_utf16_string()); m_character_insertion_builder.clear(); } @@ -1579,7 +1579,7 @@ void HTMLParser::handle_after_body(HTMLToken& token) if (token.is_comment()) { // Insert a comment as the last child of the first element in the stack of open elements (the html element). auto& insertion_location = m_stack_of_open_elements.first(); - MUST(insertion_location.append_child(realm().create(document(), token.comment()))); + MUST(insertion_location.append_child(realm().create(document(), Utf16String::from_utf8(token.comment())))); return; } @@ -1631,7 +1631,7 @@ void HTMLParser::handle_after_after_body(HTMLToken& token) // -> A comment token if (token.is_comment()) { // Insert a comment as the last child of the Document object. - auto comment = realm().create(document(), token.comment()); + auto comment = realm().create(document(), Utf16String::from_utf8(token.comment())); MUST(document().append_child(*comment)); return; } @@ -4626,7 +4626,7 @@ void HTMLParser::handle_after_after_frameset(HTMLToken& token) // -> A comment token if (token.is_comment()) { // Insert a comment as the last child of the Document object. - auto comment = document().realm().create(document(), token.comment()); + auto comment = document().realm().create(document(), Utf16String::from_utf8(token.comment())); MUST(document().append_child(comment)); return; } @@ -5123,11 +5123,12 @@ enum class AttributeMode { Yes, }; -static String escape_string(StringView string, AttributeMode attribute_mode) +template ViewType> +static String escape_string(ViewType const& string, AttributeMode attribute_mode) { // https://html.spec.whatwg.org/multipage/parsing.html#escapingString StringBuilder builder; - for (auto code_point : Utf8View { string }) { + for (auto code_point : string) { // 1. Replace any occurrence of the "&" character by the string "&". if (code_point == '&') builder.append("&"sv); @@ -5179,7 +5180,7 @@ String HTMLParser::serialize_html_fragment(DOM::Node const& node, SerializableSh // followed by a U+0022 QUOTATION MARK character ("). if (element.is_value().has_value() && !element.has_attribute(AttributeNames::is)) { builder.append(" is=\""sv); - builder.append(escape_string(element.is_value().value(), AttributeMode::Yes)); + builder.append(escape_string(element.is_value().value().code_points(), AttributeMode::Yes)); builder.append('"'); } @@ -5212,7 +5213,7 @@ String HTMLParser::serialize_html_fragment(DOM::Node const& node, SerializableSh builder.append(attribute.name()); builder.append("=\""sv); - builder.append(escape_string(attribute.value(), AttributeMode::Yes)); + builder.append(escape_string(attribute.value().code_points(), AttributeMode::Yes)); builder.append('"'); }); @@ -5335,7 +5336,7 @@ String HTMLParser::serialize_html_fragment(DOM::Node const& node, SerializableSh } // Otherwise, append the value of current node's data IDL attribute, escaped as described below. - builder.append(escape_string(text_node.data(), AttributeMode::No)); + builder.append(escape_string(text_node.data().utf16_view(), AttributeMode::No)); } if (is(current_node)) { diff --git a/Libraries/LibWeb/HTML/Parser/HTMLParser.h b/Libraries/LibWeb/HTML/Parser/HTMLParser.h index a76c153f9cb..40d081007d6 100644 --- a/Libraries/LibWeb/HTML/Parser/HTMLParser.h +++ b/Libraries/LibWeb/HTML/Parser/HTMLParser.h @@ -228,7 +228,7 @@ private: Vector m_pending_table_character_tokens; GC::Ptr m_character_insertion_node; - StringBuilder m_character_insertion_builder; + StringBuilder m_character_insertion_builder { StringBuilder::Mode::UTF16 }; } SWIFT_UNSAFE_REFERENCE; RefPtr parse_dimension_value(StringView); diff --git a/Libraries/LibWeb/HTML/XMLSerializer.cpp b/Libraries/LibWeb/HTML/XMLSerializer.cpp index 93b0f41d8a6..86f666f1f83 100644 --- a/Libraries/LibWeb/HTML/XMLSerializer.cpp +++ b/Libraries/LibWeb/HTML/XMLSerializer.cpp @@ -754,7 +754,7 @@ static WebIDL::ExceptionOr serialize_comment(DOM::Comment const& comment if (comment.data().contains("--"sv)) return WebIDL::InvalidStateError::create(comment.realm(), "Comment data contains two adjacent hyphens"_string); - if (comment.data().ends_with('-')) + if (comment.data().ends_with("-"sv)) return WebIDL::InvalidStateError::create(comment.realm(), "Comment data ends with a hyphen"_string); } @@ -776,7 +776,7 @@ static WebIDL::ExceptionOr serialize_text(DOM::Text const& text, Require // 1. If the require well-formed flag is set (its value is true), and node's data contains characters that are not matched by the XML Char production, // then throw an exception; the serialization of this node's data would not be well-formed. if (require_well_formed == RequireWellFormed::Yes) { - for (u32 code_point : text.data().code_points()) { + for (u32 code_point : text.data()) { if (!is_valid_xml_char(code_point)) return WebIDL::InvalidStateError::create(text.realm(), "Text contains characters not allowed in XML"_string); } @@ -786,16 +786,16 @@ static WebIDL::ExceptionOr serialize_text(DOM::Text const& text, Require auto markup = text.data(); // 3. Replace any occurrences of "&" in markup by "&". - markup = MUST(markup.replace("&"sv, "&"sv, ReplaceMode::All)); + markup = markup.replace("&"sv, "&"sv, ReplaceMode::All); // 4. Replace any occurrences of "<" in markup by "<". - markup = MUST(markup.replace("<"sv, "<"sv, ReplaceMode::All)); + markup = markup.replace("<"sv, "<"sv, ReplaceMode::All); // 5. Replace any occurrences of ">" in markup by ">". - markup = MUST(markup.replace(">"sv, ">"sv, ReplaceMode::All)); + markup = markup.replace(">"sv, ">"sv, ReplaceMode::All); // 6. Return the value of markup. - return markup; + return markup.to_utf8_but_should_be_ported_to_utf16(); } // https://w3c.github.io/DOM-Parsing/#xml-serializing-a-documentfragment-node diff --git a/Libraries/LibWeb/Layout/FormattingContext.cpp b/Libraries/LibWeb/Layout/FormattingContext.cpp index 221102d1fba..e40cb6e2577 100644 --- a/Libraries/LibWeb/Layout/FormattingContext.cpp +++ b/Libraries/LibWeb/Layout/FormattingContext.cpp @@ -1756,7 +1756,7 @@ bool FormattingContext::can_skip_is_anonymous_text_run(Box& box) if (box.is_anonymous() && !box.is_generated() && !box.first_child_of_type()) { bool contains_only_white_space = true; box.for_each_in_subtree([&](auto const& node) { - if (!is(node) || !static_cast(node).dom_node().data().bytes_as_string_view().is_whitespace()) { + if (!is(node) || !static_cast(node).dom_node().data().is_ascii_whitespace()) { contains_only_white_space = false; return TraversalDecision::Break; } diff --git a/Libraries/LibWeb/Layout/TextNode.cpp b/Libraries/LibWeb/Layout/TextNode.cpp index 83b9c459087..6d92f7dded9 100644 --- a/Libraries/LibWeb/Layout/TextNode.cpp +++ b/Libraries/LibWeb/Layout/TextNode.cpp @@ -322,7 +322,7 @@ String const& TextNode::text_for_rendering() const void TextNode::compute_text_for_rendering() { if (dom_node().is_password_input()) { - m_text_for_rendering = MUST(String::repeated('*', dom_node().data().code_points().length())); + m_text_for_rendering = MUST(String::repeated('*', dom_node().data().length_in_code_points())); return; } @@ -332,7 +332,7 @@ void TextNode::compute_text_for_rendering() auto const maybe_lang = parent_element ? parent_element->lang() : Optional {}; auto const lang = maybe_lang.has_value() ? maybe_lang.value() : Optional {}; - auto data = apply_text_transform(dom_node().data(), computed_values().text_transform(), lang).release_value_but_fixme_should_propagate_errors(); + auto data = apply_text_transform(dom_node().data().to_utf8_but_should_be_ported_to_utf16(), computed_values().text_transform(), lang).release_value_but_fixme_should_propagate_errors(); auto data_view = data.bytes_as_string_view(); diff --git a/Libraries/LibWeb/Layout/TreeBuilder.cpp b/Libraries/LibWeb/Layout/TreeBuilder.cpp index 82041dfc443..0afb3d09b5c 100644 --- a/Libraries/LibWeb/Layout/TreeBuilder.cpp +++ b/Libraries/LibWeb/Layout/TreeBuilder.cpp @@ -242,7 +242,7 @@ void TreeBuilder::create_pseudo_element_if_needed(DOM::Element& element, CSS::Ps // FIXME: Handle images, and multiple values if (new_content.type == CSS::ContentData::Type::String) { - auto text = document.realm().create(document, new_content.data); + auto text = document.realm().create(document, Utf16String::from_utf8(new_content.data)); auto text_node = document.heap().allocate(document, *text); text_node->set_generated_for(pseudo_element, element); diff --git a/Libraries/LibWeb/Selection/Selection.cpp b/Libraries/LibWeb/Selection/Selection.cpp index b431444c399..e693f43dc59 100644 --- a/Libraries/LibWeb/Selection/Selection.cpp +++ b/Libraries/LibWeb/Selection/Selection.cpp @@ -599,12 +599,12 @@ void Selection::move_offset_to_next_word(bool collapse_selection) auto& text_node = static_cast(*anchor_node); while (true) { auto focus_offset = this->focus_offset(); - if (focus_offset == text_node.data().bytes_as_string_view().length()) { + if (focus_offset == text_node.data().length_in_code_units()) { return; } if (auto offset = text_node.word_segmenter().next_boundary(focus_offset); offset.has_value()) { - auto word = text_node.data().code_points().substring_view(focus_offset, *offset - focus_offset); + auto word = text_node.data().substring_view(focus_offset, *offset - focus_offset); if (collapse_selection) { MUST(collapse(anchor_node, *offset)); m_document->reset_cursor_blink_cycle(); @@ -629,7 +629,7 @@ void Selection::move_offset_to_previous_word(bool collapse_selection) while (true) { auto focus_offset = this->focus_offset(); if (auto offset = text_node.word_segmenter().previous_boundary(focus_offset); offset.has_value()) { - auto word = text_node.data().code_points().unicode_substring_view(*offset, focus_offset - *offset); + auto word = text_node.data().substring_view(*offset, focus_offset - *offset); if (collapse_selection) { MUST(collapse(anchor_node, *offset)); m_document->reset_cursor_blink_cycle(); diff --git a/Libraries/LibWeb/WebIDL/AbstractOperations.cpp b/Libraries/LibWeb/WebIDL/AbstractOperations.cpp index 9c96fb03ecb..6afd7d9bc16 100644 --- a/Libraries/LibWeb/WebIDL/AbstractOperations.cpp +++ b/Libraries/LibWeb/WebIDL/AbstractOperations.cpp @@ -234,6 +234,11 @@ JS::ThrowCompletionOr to_string(JS::VM& vm, JS::Value value) return value.to_string(vm); } +JS::ThrowCompletionOr to_utf16_string(JS::VM& vm, JS::Value value) +{ + return value.to_utf16_string(vm); +} + JS::ThrowCompletionOr to_usv_string(JS::VM& vm, JS::Value value) { return value.to_well_formed_string(vm); diff --git a/Libraries/LibWeb/WebIDL/AbstractOperations.h b/Libraries/LibWeb/WebIDL/AbstractOperations.h index a883f8278e3..d08a968993d 100644 --- a/Libraries/LibWeb/WebIDL/AbstractOperations.h +++ b/Libraries/LibWeb/WebIDL/AbstractOperations.h @@ -23,6 +23,7 @@ ErrorOr get_buffer_source_copy(JS::Object const& buffer_source); JS::Completion call_user_object_operation(CallbackType& callback, String const& operation_name, Optional this_argument, ReadonlySpan args); JS::ThrowCompletionOr to_string(JS::VM&, JS::Value); +JS::ThrowCompletionOr to_utf16_string(JS::VM&, JS::Value); JS::ThrowCompletionOr to_usv_string(JS::VM&, JS::Value); JS::ThrowCompletionOr to_byte_string(JS::VM&, JS::Value); diff --git a/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp b/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp index fbfb0d25d42..1add993223b 100644 --- a/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp +++ b/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp @@ -245,18 +245,16 @@ void XMLDocumentBuilder::text(StringView data) { if (m_has_error) return; - auto last = m_current_node->last_child(); - if (last && last->is_text()) { + + if (auto* last = m_current_node->last_child(); last && last->is_text()) { auto& text_node = static_cast(*last); - text_builder.append(text_node.data()); - text_builder.append(data); - text_node.set_data(MUST(text_builder.to_string())); - text_builder.clear(); - } else { - if (!data.is_empty()) { - auto node = m_document->create_text_node(MUST(String::from_utf8(data))); - MUST(m_current_node->append_child(node)); - } + m_text_builder.append(text_node.data()); + m_text_builder.append(data); + text_node.set_data(m_text_builder.to_utf16_string()); + m_text_builder.clear(); + } else if (!data.is_empty()) { + auto node = m_document->create_text_node(Utf16String::from_utf8(data)); + MUST(m_current_node->append_child(node)); } } @@ -265,7 +263,7 @@ void XMLDocumentBuilder::comment(StringView data) if (m_has_error || !m_current_node) return; - MUST(m_current_node->append_child(m_document->create_comment(MUST(String::from_utf8(data))))); + MUST(m_current_node->append_child(m_document->create_comment(Utf16String::from_utf8(data)))); } void XMLDocumentBuilder::cdata_section(StringView data) @@ -273,7 +271,7 @@ void XMLDocumentBuilder::cdata_section(StringView data) if (m_has_error || !m_current_node) return; - auto section = MUST(m_document->create_cdata_section(MUST(String::from_utf8(data)))); + auto section = MUST(m_document->create_cdata_section(Utf16String::from_utf8(data))); MUST(m_current_node->append_child(section)); } @@ -282,7 +280,7 @@ void XMLDocumentBuilder::processing_instruction(StringView target, StringView da if (m_has_error || !m_current_node) return; - auto processing_instruction = MUST(m_document->create_processing_instruction(MUST(String::from_utf8(target)), MUST(String::from_utf8(data)))); + auto processing_instruction = MUST(m_document->create_processing_instruction(MUST(String::from_utf8(target)), Utf16String::from_utf8(data))); MUST(m_current_node->append_child(processing_instruction)); } diff --git a/Libraries/LibWeb/XML/XMLDocumentBuilder.h b/Libraries/LibWeb/XML/XMLDocumentBuilder.h index 60899a7e932..77653d0bdaf 100644 --- a/Libraries/LibWeb/XML/XMLDocumentBuilder.h +++ b/Libraries/LibWeb/XML/XMLDocumentBuilder.h @@ -47,7 +47,7 @@ private: GC::Ptr m_current_node; XMLScriptingSupport m_scripting_support { XMLScriptingSupport::Enabled }; bool m_has_error { false }; - StringBuilder text_builder; + StringBuilder m_text_builder { StringBuilder::Mode::UTF16 }; struct NamespaceAndPrefix { FlyString ns; diff --git a/Services/WebContent/ConnectionFromClient.cpp b/Services/WebContent/ConnectionFromClient.cpp index 5cadb9dd767..fb41343ee73 100644 --- a/Services/WebContent/ConnectionFromClient.cpp +++ b/Services/WebContent/ConnectionFromClient.cpp @@ -650,7 +650,7 @@ void ConnectionFromClient::get_dom_node_inner_html(u64 page_id, Web::UniqueNodeI html = element.inner_html().release_value_but_fixme_should_propagate_errors(); } else if (dom_node->is_text() || dom_node->is_comment()) { auto const& character_data = static_cast(*dom_node); - html = character_data.data(); + html = character_data.data().to_utf8_but_should_be_ported_to_utf16(); } else { return; } @@ -671,7 +671,7 @@ void ConnectionFromClient::get_dom_node_outer_html(u64 page_id, Web::UniqueNodeI html = element.outer_html().release_value_but_fixme_should_propagate_errors(); } else if (dom_node->is_text() || dom_node->is_comment()) { auto const& character_data = static_cast(*dom_node); - html = character_data.data(); + html = character_data.data().to_utf8_but_should_be_ported_to_utf16(); } else { return; } @@ -692,7 +692,7 @@ void ConnectionFromClient::set_dom_node_outer_html(u64 page_id, Web::UniqueNodeI element.set_outer_html(html).release_value_but_fixme_should_propagate_errors(); } else if (dom_node->is_text() || dom_node->is_comment()) { auto& character_data = static_cast(*dom_node); - character_data.set_data(html); + character_data.set_data(Utf16String::from_utf8(html)); } else { async_did_finish_editing_dom_node(page_id, {}); return; @@ -710,7 +710,7 @@ void ConnectionFromClient::set_dom_node_text(u64 page_id, Web::UniqueNodeID node } auto& character_data = static_cast(*dom_node); - character_data.set_data(text); + character_data.set_data(Utf16String::from_utf8(text)); async_did_finish_editing_dom_node(page_id, character_data.unique_id()); } @@ -804,7 +804,7 @@ void ConnectionFromClient::create_child_text_node(u64 page_id, Web::UniqueNodeID return; } - auto text_node = dom_node->realm().create(dom_node->document(), "text"_string); + auto text_node = dom_node->realm().create(dom_node->document(), "text"_utf16); dom_node->append_child(text_node).release_value_but_fixme_should_propagate_errors(); async_did_finish_editing_dom_node(page_id, text_node->unique_id()); diff --git a/Services/WebContent/PageClient.cpp b/Services/WebContent/PageClient.cpp index 1d7c6deb7ee..f6975a70cf6 100644 --- a/Services/WebContent/PageClient.cpp +++ b/Services/WebContent/PageClient.cpp @@ -667,7 +667,7 @@ void PageClient::page_did_mutate_dom(FlyString const& type, Web::DOM::Node const mutation = WebView::AttributeMutation { *attribute_name, element.attribute(*attribute_name) }; } else if (type == Web::DOM::MutationType::characterData) { auto const& character_data = as(target); - mutation = WebView::CharacterDataMutation { character_data.data() }; + mutation = WebView::CharacterDataMutation { character_data.data().to_utf8_but_should_be_ported_to_utf16() }; } else if (type == Web::DOM::MutationType::childList) { Vector added; added.ensure_capacity(added_nodes.length());