1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 22:57:44 +00:00

LibWeb: Port CharacterData from DeprecatedString to String

The existing implementation has some pre-existing issues where it is
incorrectly assumes that byte offsets are given through the IDL instead
of UTF-16 code units. While making these changes, leave some FIXMEs for
that.
This commit is contained in:
Shannon Booth 2023-09-07 21:36:05 +12:00 committed by Andreas Kling
parent 3b12a13f17
commit b603e860af
18 changed files with 87 additions and 81 deletions

View file

@ -14,7 +14,7 @@
namespace Web::DOM { namespace Web::DOM {
CharacterData::CharacterData(Document& document, NodeType type, DeprecatedString const& data) CharacterData::CharacterData(Document& document, NodeType type, String const& data)
: Node(document, type) : Node(document, type)
, m_data(data) , m_data(data)
{ {
@ -27,7 +27,7 @@ void CharacterData::initialize(JS::Realm& realm)
} }
// https://dom.spec.whatwg.org/#dom-characterdata-data // https://dom.spec.whatwg.org/#dom-characterdata-data
void CharacterData::set_data(DeprecatedString data) void CharacterData::set_data(String const& data)
{ {
// [The data] setter must replace data with node this, offset 0, count thiss length, and data new value. // [The data] setter must replace data with node this, offset 0, count thiss length, and data new value.
// NOTE: Since the offset is 0, it can never be above data's length, so this can never throw. // NOTE: Since the offset is 0, it can never be above data's length, so this can never throw.
@ -37,7 +37,7 @@ void CharacterData::set_data(DeprecatedString data)
} }
// https://dom.spec.whatwg.org/#concept-cd-substring // https://dom.spec.whatwg.org/#concept-cd-substring
WebIDL::ExceptionOr<DeprecatedString> CharacterData::substring_data(size_t offset, size_t count) const WebIDL::ExceptionOr<String> CharacterData::substring_data(size_t offset, size_t count) const
{ {
// 1. Let length be nodes length. // 1. Let length be nodes length.
auto length = this->length(); auto length = this->length();
@ -46,18 +46,22 @@ WebIDL::ExceptionOr<DeprecatedString> CharacterData::substring_data(size_t offse
if (offset > length) if (offset > length)
return WebIDL::IndexSizeError::create(realm(), "Substring offset out of range."_fly_string); return WebIDL::IndexSizeError::create(realm(), "Substring offset out of range."_fly_string);
// FIXME: The offset and count we are given here is in UTF-16 code units, but we are incorrectly assuming it is a byte offset.
// 3. If offset plus count is greater than length, return a string whose value is the code units from the offsetth code unit // 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 nodes data, and then return. // to the end of nodes data, and then return.
if (offset + count > length) if (offset + count > length)
return m_data.substring(offset); return MUST(m_data.substring_from_byte_offset(offset));
// 4. Return a string whose value is the code units from the offsetth code unit to the offset+countth code unit in nodes data. // 4. Return a string whose value is the code units from the offsetth code unit to the offset+countth code unit in nodes data.
return m_data.substring(offset, count); return MUST(m_data.substring_from_byte_offset(offset, count));
} }
// https://dom.spec.whatwg.org/#concept-cd-replace // https://dom.spec.whatwg.org/#concept-cd-replace
WebIDL::ExceptionOr<void> CharacterData::replace_data(size_t offset, size_t count, DeprecatedString const& data) WebIDL::ExceptionOr<void> CharacterData::replace_data(size_t offset, size_t count, String const& data)
{ {
// FIXME: The offset and count we are given here is in UTF-16 code units, but we are incorrectly assuming it is a byte offset.
// 1. Let length be nodes length. // 1. Let length be nodes length.
auto length = this->length(); auto length = this->length();
@ -70,16 +74,16 @@ WebIDL::ExceptionOr<void> CharacterData::replace_data(size_t offset, size_t coun
count = length - offset; count = length - offset;
// 4. Queue a mutation record of "characterData" for node with null, null, nodes data, « », « », null, and null. // 4. Queue a mutation record of "characterData" for node with null, null, nodes data, « », « », null, and null.
queue_mutation_record(MutationType::characterData, {}, {}, m_data, {}, {}, nullptr, nullptr); queue_mutation_record(MutationType::characterData, {}, {}, m_data.to_deprecated_string(), {}, {}, nullptr, nullptr);
// 5. Insert data into nodes data after offset code units. // 5. Insert data into nodes data after offset code units.
// 6. Let delete offset be offset + datas length. // 6. Let delete offset be offset + datas length.
// 7. Starting from delete offset code units, remove count code units from nodes data. // 7. Starting from delete offset code units, remove count code units from nodes data.
StringBuilder builder; StringBuilder builder;
builder.append(this->data().substring_view(0, offset)); builder.append(this->data().bytes_as_string_view().substring_view(0, offset));
builder.append(data); builder.append(data);
builder.append(this->data().substring_view(offset + count)); builder.append(this->data().bytes_as_string_view().substring_view(offset + count));
m_data = builder.to_deprecated_string(); m_data = MUST(builder.to_string());
// 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. // 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.
for (auto& range : Range::live_ranges()) { for (auto& range : Range::live_ranges()) {
@ -96,13 +100,13 @@ WebIDL::ExceptionOr<void> CharacterData::replace_data(size_t offset, size_t coun
// 10. For each live range whose start node is node and start offset is greater than offset plus count, increase its start offset by datas length and decrease it by count. // 10. For each live range whose start node is node and start offset is greater than offset plus count, increase its start offset by datas length and decrease it by count.
for (auto& range : Range::live_ranges()) { for (auto& range : Range::live_ranges()) {
if (range->start_container() == this && range->start_offset() > (offset + count)) if (range->start_container() == this && range->start_offset() > (offset + count))
TRY(range->set_start(*range->start_container(), range->start_offset() + data.length() - count)); TRY(range->set_start(*range->start_container(), range->start_offset() + data.bytes().size() - 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 datas length and decrease it by 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 datas length and decrease it by count.
for (auto& range : Range::live_ranges()) { for (auto& range : Range::live_ranges()) {
if (range->end_container() == this && range->end_offset() > (offset + count)) if (range->end_container() == this && range->end_offset() > (offset + count))
TRY(range->set_end(*range->end_container(), range->end_offset() + data.length() - count)); TRY(range->set_end(*range->end_container(), range->end_offset() + data.bytes().size() - count));
} }
// 12. If nodes parent is non-null, then run the children changed steps for nodes parent. // 12. If nodes parent is non-null, then run the children changed steps for nodes parent.
@ -121,14 +125,14 @@ WebIDL::ExceptionOr<void> CharacterData::replace_data(size_t offset, size_t coun
} }
// https://dom.spec.whatwg.org/#dom-characterdata-appenddata // https://dom.spec.whatwg.org/#dom-characterdata-appenddata
WebIDL::ExceptionOr<void> CharacterData::append_data(DeprecatedString const& data) WebIDL::ExceptionOr<void> CharacterData::append_data(String const& data)
{ {
// The appendData(data) method steps are to replace data with node this, offset thiss length, count 0, and data data. // The appendData(data) method steps are to replace data with node this, offset thiss length, count 0, and data data.
return replace_data(this->length(), 0, data); return replace_data(this->length(), 0, data);
} }
// https://dom.spec.whatwg.org/#dom-characterdata-insertdata // https://dom.spec.whatwg.org/#dom-characterdata-insertdata
WebIDL::ExceptionOr<void> CharacterData::insert_data(size_t offset, DeprecatedString const& data) WebIDL::ExceptionOr<void> CharacterData::insert_data(size_t offset, String const& data)
{ {
// The insertData(offset, data) method steps are to replace data with node this, offset offset, count 0, and data 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); return replace_data(offset, 0, data);
@ -138,7 +142,7 @@ WebIDL::ExceptionOr<void> CharacterData::insert_data(size_t offset, DeprecatedSt
WebIDL::ExceptionOr<void> CharacterData::delete_data(size_t offset, size_t count) WebIDL::ExceptionOr<void> 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. // 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, DeprecatedString::empty()); return replace_data(offset, count, String {});
} }
} }

View file

@ -6,7 +6,7 @@
#pragma once #pragma once
#include <AK/DeprecatedString.h> #include <AK/String.h>
#include <LibWeb/DOM/ChildNode.h> #include <LibWeb/DOM/ChildNode.h>
#include <LibWeb/DOM/Node.h> #include <LibWeb/DOM/Node.h>
#include <LibWeb/DOM/NonDocumentTypeChildNode.h> #include <LibWeb/DOM/NonDocumentTypeChildNode.h>
@ -22,24 +22,25 @@ class CharacterData
public: public:
virtual ~CharacterData() override = default; virtual ~CharacterData() override = default;
DeprecatedString const& data() const { return m_data; } String const& data() const { return m_data; }
void set_data(DeprecatedString); void set_data(String const&);
unsigned length() const { return m_data.length(); } // FIXME: This should be in UTF-16 code units, not byte size.
unsigned length() const { return m_data.bytes().size(); }
WebIDL::ExceptionOr<DeprecatedString> substring_data(size_t offset, size_t count) const; WebIDL::ExceptionOr<String> substring_data(size_t offset, size_t count) const;
WebIDL::ExceptionOr<void> append_data(DeprecatedString const&); WebIDL::ExceptionOr<void> append_data(String const&);
WebIDL::ExceptionOr<void> insert_data(size_t offset, DeprecatedString const&); WebIDL::ExceptionOr<void> insert_data(size_t offset, String const&);
WebIDL::ExceptionOr<void> delete_data(size_t offset, size_t count); WebIDL::ExceptionOr<void> delete_data(size_t offset, size_t count);
WebIDL::ExceptionOr<void> replace_data(size_t offset, size_t count, DeprecatedString const&); WebIDL::ExceptionOr<void> replace_data(size_t offset, size_t count, String const&);
protected: protected:
CharacterData(Document&, NodeType, DeprecatedString const&); CharacterData(Document&, NodeType, String const&);
virtual void initialize(JS::Realm&) override; virtual void initialize(JS::Realm&) override;
private: private:
DeprecatedString m_data; String m_data;
}; };
} }

View file

@ -3,7 +3,7 @@
#import <DOM/Node.idl> #import <DOM/Node.idl>
// https://dom.spec.whatwg.org/#characterdata // https://dom.spec.whatwg.org/#characterdata
[Exposed=Window, UseDeprecatedAKString] [Exposed=Window]
interface CharacterData : Node { interface CharacterData : Node {
[LegacyNullToEmptyString] attribute DOMString data; [LegacyNullToEmptyString] attribute DOMString data;
readonly attribute unsigned long length; readonly attribute unsigned long length;

View file

@ -12,7 +12,7 @@
namespace Web::DOM { namespace Web::DOM {
Comment::Comment(Document& document, String const& data) Comment::Comment(Document& document, String const& data)
: CharacterData(document, NodeType::COMMENT_NODE, data.to_deprecated_string()) : CharacterData(document, NodeType::COMMENT_NODE, data)
{ {
} }

View file

@ -162,7 +162,7 @@ Optional<String> Node::text_content() const
// If CharacterData, return thiss data. // If CharacterData, return thiss data.
if (is<CharacterData>(this)) if (is<CharacterData>(this))
return MUST(String::from_deprecated_string(static_cast<CharacterData const&>(*this).data())); return static_cast<CharacterData const&>(*this).data();
// If Attr node, return this's value. // If Attr node, return this's value.
if (is<Attr>(*this)) if (is<Attr>(*this))
@ -188,7 +188,7 @@ void Node::set_text_content(Optional<String> const& maybe_content)
else if (is<CharacterData>(this)) { else if (is<CharacterData>(this)) {
auto* character_data_node = verify_cast<CharacterData>(this); auto* character_data_node = verify_cast<CharacterData>(this);
character_data_node->set_data(content); character_data_node->set_data(MUST(String::from_deprecated_string(content)));
// FIXME: CharacterData::set_data is not spec compliant. Make this match the spec when set_data becomes spec compliant. // 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. // Do note that this will make this function able to throw an exception.
@ -217,7 +217,7 @@ Optional<String> Node::node_value() const
// If CharacterData, return thiss data. // If CharacterData, return thiss data.
if (is<CharacterData>(this)) { if (is<CharacterData>(this)) {
return MUST(String::from_deprecated_string(verify_cast<CharacterData>(this)->data())); return verify_cast<CharacterData>(this)->data();
} }
// Otherwise, return null. // Otherwise, return null.
@ -236,7 +236,7 @@ void Node::set_node_value(Optional<String> const& maybe_value)
verify_cast<Attr>(this)->set_value(value.to_deprecated_string()); verify_cast<Attr>(this)->set_value(value.to_deprecated_string());
} else if (is<CharacterData>(this)) { } else if (is<CharacterData>(this)) {
// If CharacterData, replace data with node this, offset 0, count thiss length, and data the given value. // If CharacterData, replace data with node this, offset 0, count thiss length, and data the given value.
verify_cast<CharacterData>(this)->set_data(value.to_deprecated_string()); verify_cast<CharacterData>(this)->set_data(value);
} }
// Otherwise, do nothing. // Otherwise, do nothing.
@ -854,21 +854,21 @@ JS::NonnullGCPtr<Node> Node::clone_node(Document* document, bool clone_children)
auto text = verify_cast<Text>(this); auto text = verify_cast<Text>(this);
// Set copys data to that of node. // Set copys data to that of node.
auto text_copy = heap().allocate<Text>(realm(), *document, MUST(String::from_deprecated_string(text->data()))); auto text_copy = heap().allocate<Text>(realm(), *document, text->data());
copy = move(text_copy); copy = move(text_copy);
} else if (is<Comment>(this)) { } else if (is<Comment>(this)) {
// Comment // Comment
auto comment = verify_cast<Comment>(this); auto comment = verify_cast<Comment>(this);
// Set copys data to that of node. // Set copys data to that of node.
auto comment_copy = heap().allocate<Comment>(realm(), *document, MUST(String::from_deprecated_string(comment->data()))); auto comment_copy = heap().allocate<Comment>(realm(), *document, comment->data());
copy = move(comment_copy); copy = move(comment_copy);
} else if (is<ProcessingInstruction>(this)) { } else if (is<ProcessingInstruction>(this)) {
// ProcessingInstruction // ProcessingInstruction
auto processing_instruction = verify_cast<ProcessingInstruction>(this); auto processing_instruction = verify_cast<ProcessingInstruction>(this);
// Set copys target and data to those of node. // Set copys target and data to those of node.
auto processing_instruction_copy = heap().allocate<ProcessingInstruction>(realm(), *document, processing_instruction->data(), processing_instruction->target()); auto processing_instruction_copy = heap().allocate<ProcessingInstruction>(realm(), *document, processing_instruction->data().to_deprecated_string(), processing_instruction->target());
copy = processing_instruction_copy; copy = processing_instruction_copy;
} }
// Otherwise, Do nothing. // Otherwise, Do nothing.
@ -1143,7 +1143,7 @@ bool Node::is_uninteresting_whitespace_node() const
{ {
if (!is<Text>(*this)) if (!is<Text>(*this))
return false; return false;
if (!static_cast<Text const&>(*this).data().is_whitespace()) if (!static_cast<Text const&>(*this).data().bytes_as_string_view().is_whitespace())
return false; return false;
if (!layout_node()) if (!layout_node())
return true; return true;
@ -1491,7 +1491,8 @@ size_t Node::length() const
// 2. If node is a CharacterData node, then return nodes datas length. // 2. If node is a CharacterData node, then return nodes datas length.
if (is_character_data()) { if (is_character_data()) {
auto* character_data_node = verify_cast<CharacterData>(this); auto* character_data_node = verify_cast<CharacterData>(this);
return character_data_node->data().length(); // FIXME: This should be in UTF-16 code units, not byte size.
return character_data_node->data().bytes().size();
} }
// 3. Return the number of nodes children. // 3. Return the number of nodes children.
@ -1874,7 +1875,7 @@ ErrorOr<String> Node::name_or_description(NameOrDescription target, Document con
// G. Otherwise, if the current node is a Text node, return its textual contents. // G. Otherwise, if the current node is a Text node, return its textual contents.
if (is_text()) { if (is_text()) {
auto const* text_node = static_cast<DOM::Text const*>(this); auto const* text_node = static_cast<DOM::Text const*>(this);
return String::from_deprecated_string(text_node->data()); return text_node->data();
} }
// TODO: H. Otherwise, if the current node is a descendant of an element whose Accessible Name or Accessible Description is being computed, and contains descendants, proceed to 2F.i. // TODO: H. Otherwise, if the current node is a descendant of an element whose Accessible Name or Accessible Description is being computed, and contains descendants, proceed to 2F.i.

View file

@ -67,7 +67,7 @@ bool Position::offset_is_at_end_of_node() const
auto& node = verify_cast<DOM::Text>(*m_node); auto& node = verify_cast<DOM::Text>(*m_node);
auto text = node.data(); auto text = node.data();
return m_offset == text.length(); return m_offset == text.bytes_as_string_view().length();
} }
} }

View file

@ -12,7 +12,7 @@
namespace Web::DOM { namespace Web::DOM {
ProcessingInstruction::ProcessingInstruction(Document& document, DeprecatedString const& data, DeprecatedString const& target) ProcessingInstruction::ProcessingInstruction(Document& document, DeprecatedString const& data, DeprecatedString const& target)
: CharacterData(document, NodeType::PROCESSING_INSTRUCTION_NODE, data) : CharacterData(document, NodeType::PROCESSING_INSTRUCTION_NODE, MUST(String::from_deprecated_string(data)))
, m_target(target) , m_target(target)
{ {
} }

View file

@ -559,11 +559,11 @@ String Range::to_string() const
// 2. If thiss start node is thiss end node and it is a Text node, // 2. If thiss start node is thiss end node and it is a Text node,
// then return the substring of that Text nodes data beginning at thiss start offset and ending at thiss end offset. // then return the substring of that Text nodes data beginning at thiss start offset and ending at thiss end offset.
if (start_container() == end_container() && is<Text>(*start_container())) if (start_container() == end_container() && is<Text>(*start_container()))
return String::from_deprecated_string(static_cast<Text const&>(*start_container()).data().substring(start_offset(), end_offset() - start_offset())).release_value(); return MUST(static_cast<Text const&>(*start_container()).data().substring_from_byte_offset(start_offset(), end_offset() - start_offset()));
// 3. If thiss start node is a Text node, then append the substring of that nodes data from thiss start offset until the end to s. // 3. If thiss start node is a Text node, then append the substring of that nodes data from thiss start offset until the end to s.
if (is<Text>(*start_container())) if (is<Text>(*start_container()))
builder.append(static_cast<Text const&>(*start_container()).data().substring_view(start_offset())); builder.append(static_cast<Text const&>(*start_container()).data().bytes_as_string_view().substring_view(start_offset()));
// 4. Append the concatenation of the data of all Text nodes that are contained in this, in tree order, to s. // 4. Append the concatenation of the data of all Text nodes that are contained in this, in tree order, to s.
for (Node const* node = start_container(); node != end_container()->next_sibling(); node = node->next_in_pre_order()) { for (Node const* node = start_container(); node != end_container()->next_sibling(); node = node->next_in_pre_order()) {
@ -573,7 +573,7 @@ String Range::to_string() const
// 5. If thiss end node is a Text node, then append the substring of that nodes data from its start until thiss end offset to s. // 5. If thiss end node is a Text node, then append the substring of that nodes data from its start until thiss end offset to s.
if (is<Text>(*end_container())) if (is<Text>(*end_container()))
builder.append(static_cast<Text const&>(*end_container()).data().substring_view(0, end_offset())); builder.append(static_cast<Text const&>(*end_container()).data().bytes_as_string_view().substring_view(0, end_offset()));
// 6. Return s. // 6. Return s.
return MUST(builder.to_string()); return MUST(builder.to_string());
@ -616,7 +616,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<DocumentFragment>> Range::extract()
TRY(fragment->append_child(clone)); 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. // 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<CharacterData&>(*original_start_node).replace_data(original_start_offset, original_end_offset - original_start_offset, "")); TRY(static_cast<CharacterData&>(*original_start_node).replace_data(original_start_offset, original_end_offset - original_start_offset, String {}));
// 5. Return fragment. // 5. Return fragment.
return fragment; return fragment;
@ -706,7 +706,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<DocumentFragment>> Range::extract()
TRY(fragment->append_child(clone)); TRY(fragment->append_child(clone));
// 4. Replace data with node original start node, offset original start offset, count original start nodes length minus original start offset, and data the empty string. // 4. Replace data with node original start node, offset original start offset, count original start nodes length minus original start offset, and data the empty string.
TRY(static_cast<CharacterData&>(*original_start_node).replace_data(original_start_offset, original_start_node->length() - original_start_offset, "")); TRY(static_cast<CharacterData&>(*original_start_node).replace_data(original_start_offset, original_start_node->length() - original_start_offset, String {}));
} }
// 16. Otherwise, if first partially contained child is not null: // 16. Otherwise, if first partially contained child is not null:
else if (first_partially_contained_child) { else if (first_partially_contained_child) {
@ -744,7 +744,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<DocumentFragment>> Range::extract()
TRY(fragment->append_child(clone)); TRY(fragment->append_child(clone));
// 4. Replace data with node original end node, offset 0, count original end offset, and data the empty string. // 4. Replace data with node original end node, offset 0, count original end offset, and data the empty string.
TRY(verify_cast<CharacterData>(*original_end_node).replace_data(0, original_end_offset, "")); TRY(verify_cast<CharacterData>(*original_end_node).replace_data(0, original_end_offset, String {}));
} }
// 19. Otherwise, if last partially contained child is not null: // 19. Otherwise, if last partially contained child is not null:
else if (last_partially_contained_child) { else if (last_partially_contained_child) {
@ -1086,7 +1086,7 @@ WebIDL::ExceptionOr<void> 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, // 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. // 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<CharacterData>(*original_start_node)) { if (original_start_node.ptr() == original_end_node.ptr() && is<CharacterData>(*original_start_node)) {
TRY(static_cast<CharacterData&>(*original_start_node).replace_data(original_start_offset, original_end_offset - original_start_offset, "")); TRY(static_cast<CharacterData&>(*original_start_node).replace_data(original_start_offset, original_end_offset - original_start_offset, String {}));
return {}; return {};
} }
@ -1121,7 +1121,7 @@ WebIDL::ExceptionOr<void> 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 nodes length minus original start offset, data the empty string. // 7. If original start node is a CharacterData node, then replace data with node original start node, offset original start offset, count original start nodes length minus original start offset, data the empty string.
if (is<CharacterData>(*original_start_node)) if (is<CharacterData>(*original_start_node))
TRY(static_cast<CharacterData&>(*original_start_node).replace_data(original_start_offset, original_start_node->length() - original_start_offset, "")); TRY(static_cast<CharacterData&>(*original_start_node).replace_data(original_start_offset, original_start_node->length() - original_start_offset, String {}));
// 8. For each node in nodes to remove, in tree order, remove node. // 8. For each node in nodes to remove, in tree order, remove node.
for (auto& node : nodes_to_remove) for (auto& node : nodes_to_remove)
@ -1129,7 +1129,7 @@ WebIDL::ExceptionOr<void> 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. // 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<CharacterData>(*original_end_node)) if (is<CharacterData>(*original_end_node))
TRY(static_cast<CharacterData&>(*original_end_node).replace_data(0, original_end_offset, "")); TRY(static_cast<CharacterData&>(*original_end_node).replace_data(0, original_end_offset, String {}));
// 10. Set start and end to (new node, new offset). // 10. Set start and end to (new node, new offset).
TRY(set_start(*new_node, new_offset)); TRY(set_start(*new_node, new_offset));

View file

@ -14,12 +14,12 @@
namespace Web::DOM { namespace Web::DOM {
Text::Text(Document& document, String const& data) Text::Text(Document& document, String const& data)
: CharacterData(document, NodeType::TEXT_NODE, data.to_deprecated_string()) : CharacterData(document, NodeType::TEXT_NODE, data)
{ {
} }
Text::Text(Document& document, NodeType type, String const& data) Text::Text(Document& document, NodeType type, String const& data)
: CharacterData(document, type, data.to_deprecated_string()) : CharacterData(document, type, data)
{ {
} }
@ -63,7 +63,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Text>> Text::split_text(size_t offset)
auto new_data = TRY(substring_data(offset, count)); auto new_data = TRY(substring_data(offset, count));
// 5. Let new node be a new Text node, with the same node document as node. Set new nodes data to new data. // 5. Let new node be a new Text node, with the same node document as node. Set new nodes data to new data.
auto new_node = heap().allocate<Text>(realm(), document(), MUST(String::from_deprecated_string(new_data))); auto new_node = heap().allocate<Text>(realm(), document(), new_data);
// 6. Let parent be nodes parent. // 6. Let parent be nodes parent.
JS::GCPtr<Node> parent = this->parent(); JS::GCPtr<Node> parent = this->parent();
@ -100,7 +100,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Text>> Text::split_text(size_t offset)
} }
// 8. Replace data with node node, offset offset, count count, and data the empty string. // 8. Replace data with node node, offset offset, count count, and data the empty string.
TRY(replace_data(offset, count, "")); TRY(replace_data(offset, count, String {}));
// 9. Return new node. // 9. Return new node.
return new_node; return new_node;

View file

@ -755,16 +755,16 @@ static WebIDL::ExceptionOr<DeprecatedString> serialize_text(DOM::Text const& tex
// then throw an exception; the serialization of this node's data would not be well-formed. // then throw an exception; the serialization of this node's data would not be well-formed.
// 2. Let markup be the value of node's data. // 2. Let markup be the value of node's data.
DeprecatedString markup = text.data(); auto markup = text.data();
// 3. Replace any occurrences of "&" in markup by "&amp;". // 3. Replace any occurrences of "&" in markup by "&amp;".
markup = markup.replace("&"sv, "&amp;"sv, ReplaceMode::All); markup = MUST(markup.replace("&"sv, "&amp;"sv, ReplaceMode::All));
// 4. Replace any occurrences of "<" in markup by "&lt;". // 4. Replace any occurrences of "<" in markup by "&lt;".
markup = markup.replace("<"sv, "&lt;"sv, ReplaceMode::All); markup = MUST(markup.replace("<"sv, "&lt;"sv, ReplaceMode::All));
// 5. Replace any occurrences of ">" in markup by "&gt;". // 5. Replace any occurrences of ">" in markup by "&gt;".
markup = markup.replace(">"sv, "&gt;"sv, ReplaceMode::All); markup = MUST(markup.replace(">"sv, "&gt;"sv, ReplaceMode::All));
// 6. Return the value of markup. // 6. Return the value of markup.
return markup; return markup;

View file

@ -447,11 +447,11 @@ static DeprecatedString visible_text_in_range(DOM::Range const& range)
if (range.start_container() == range.end_container() && is<DOM::Text>(*range.start_container())) { if (range.start_container() == range.end_container() && is<DOM::Text>(*range.start_container())) {
if (!range.start_container()->layout_node()) if (!range.start_container()->layout_node())
return ""sv; return ""sv;
return static_cast<DOM::Text const&>(*range.start_container()).data().substring(range.start_offset(), range.end_offset() - range.start_offset()); return MUST(static_cast<DOM::Text const&>(*range.start_container()).data().substring_from_byte_offset(range.start_offset(), range.end_offset() - range.start_offset())).to_deprecated_string();
} }
if (is<DOM::Text>(*range.start_container()) && range.start_container()->layout_node()) if (is<DOM::Text>(*range.start_container()) && range.start_container()->layout_node())
builder.append(static_cast<DOM::Text const&>(*range.start_container()).data().substring_view(range.start_offset())); builder.append(static_cast<DOM::Text const&>(*range.start_container()).data().bytes_as_string_view().substring_view(range.start_offset()));
for (DOM::Node const* node = range.start_container(); node != range.end_container()->next_sibling(); node = node->next_in_pre_order()) { for (DOM::Node const* node = range.start_container(); node != range.end_container()->next_sibling(); node = node->next_in_pre_order()) {
if (is<DOM::Text>(*node) && range.contains_node(*node) && node->layout_node()) if (is<DOM::Text>(*node) && range.contains_node(*node) && node->layout_node())
@ -459,7 +459,7 @@ static DeprecatedString visible_text_in_range(DOM::Range const& range)
} }
if (is<DOM::Text>(*range.end_container()) && range.end_container()->layout_node()) if (is<DOM::Text>(*range.end_container()) && range.end_container()->layout_node())
builder.append(static_cast<DOM::Text const&>(*range.end_container()).data().substring_view(0, range.end_offset())); builder.append(static_cast<DOM::Text const&>(*range.end_container()).data().bytes_as_string_view().substring_view(0, range.end_offset()));
return builder.to_deprecated_string(); return builder.to_deprecated_string();
} }

View file

@ -287,7 +287,7 @@ WebIDL::ExceptionOr<void> HTMLInputElement::run_input_activation_behavior()
void HTMLInputElement::did_edit_text_node(Badge<BrowsingContext>) void HTMLInputElement::did_edit_text_node(Badge<BrowsingContext>)
{ {
// 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. // 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.
m_value = value_sanitization_algorithm(m_text_node->data()); m_value = value_sanitization_algorithm(m_text_node->data().to_deprecated_string());
m_dirty_value = true; m_dirty_value = true;
update_placeholder_visibility(); update_placeholder_visibility();
@ -363,7 +363,7 @@ WebIDL::ExceptionOr<void> HTMLInputElement::set_value(String const& value)
// and the element has a text entry cursor position, move the text entry cursor position to the end of the // and the element has a text entry cursor position, move the text entry cursor position to the end of the
// text control, unselecting any selected text and resetting the selection direction to "none". // text control, unselecting any selected text and resetting the selection direction to "none".
if (m_text_node && (m_value != old_value)) { if (m_text_node && (m_value != old_value)) {
m_text_node->set_data(m_value); m_text_node->set_data(MUST(String::from_deprecated_string(m_value)));
update_placeholder_visibility(); update_placeholder_visibility();
} }
@ -502,7 +502,7 @@ void HTMLInputElement::create_shadow_tree_if_needed()
MUST(m_placeholder_element->style_for_bindings()->set_property(CSS::PropertyID::Height, "1lh"sv)); MUST(m_placeholder_element->style_for_bindings()->set_property(CSS::PropertyID::Height, "1lh"sv));
m_placeholder_text_node = heap().allocate<DOM::Text>(realm(), document(), MUST(String::from_deprecated_string(initial_value))); m_placeholder_text_node = heap().allocate<DOM::Text>(realm(), document(), MUST(String::from_deprecated_string(initial_value)));
m_placeholder_text_node->set_data(deprecated_attribute(HTML::AttributeNames::placeholder)); m_placeholder_text_node->set_data(attribute(HTML::AttributeNames::placeholder).value_or(String {}));
m_placeholder_text_node->set_editable_text_node_owner(Badge<HTMLInputElement> {}, *this); m_placeholder_text_node->set_editable_text_node_owner(Badge<HTMLInputElement> {}, *this);
MUST(m_placeholder_element->append_child(*m_placeholder_text_node)); MUST(m_placeholder_element->append_child(*m_placeholder_text_node));
MUST(element->append_child(*m_placeholder_element)); MUST(element->append_child(*m_placeholder_element));
@ -581,7 +581,7 @@ void HTMLInputElement::attribute_changed(DeprecatedFlyString const& name, Deprec
} }
} else if (name == HTML::AttributeNames::placeholder) { } else if (name == HTML::AttributeNames::placeholder) {
if (m_placeholder_text_node) if (m_placeholder_text_node)
m_placeholder_text_node->set_data(value); m_placeholder_text_node->set_data(MUST(String::from_deprecated_string(value)));
} else if (name == HTML::AttributeNames::readonly) { } else if (name == HTML::AttributeNames::readonly) {
handle_readonly_attribute(value); handle_readonly_attribute(value);
} }
@ -909,7 +909,7 @@ void HTMLInputElement::reset_algorithm()
// and then invoke the value sanitization algorithm, if the type attribute's current state defines one. // and then invoke the value sanitization algorithm, if the type attribute's current state defines one.
m_value = value_sanitization_algorithm(m_value); m_value = value_sanitization_algorithm(m_value);
if (m_text_node) { if (m_text_node) {
m_text_node->set_data(m_value); m_text_node->set_data(MUST(String::from_deprecated_string(m_value)));
update_placeholder_visibility(); update_placeholder_visibility();
} }
} }

View file

@ -1026,7 +1026,7 @@ void HTMLParser::flush_character_insertions()
{ {
if (m_character_insertion_builder.is_empty()) if (m_character_insertion_builder.is_empty())
return; return;
m_character_insertion_node->set_data(m_character_insertion_builder.to_deprecated_string()); m_character_insertion_node->set_data(MUST(m_character_insertion_builder.to_string()));
m_character_insertion_builder.clear(); m_character_insertion_builder.clear();
} }

View file

@ -1654,7 +1654,7 @@ bool FormattingContext::can_skip_is_anonymous_text_run(Box& box)
if (box.is_anonymous() && !box.is_generated() && !box.first_child_of_type<BlockContainer>()) { if (box.is_anonymous() && !box.is_generated() && !box.first_child_of_type<BlockContainer>()) {
bool contains_only_white_space = true; bool contains_only_white_space = true;
box.for_each_in_subtree([&](auto const& node) { box.for_each_in_subtree([&](auto const& node) {
if (!is<TextNode>(node) || !static_cast<TextNode const&>(node).dom_node().data().is_whitespace()) { if (!is<TextNode>(node) || !static_cast<TextNode const&>(node).dom_node().data().bytes_as_string_view().is_whitespace()) {
contains_only_white_space = false; contains_only_white_space = false;
return IterationDecision::Break; return IterationDecision::Break;
} }

View file

@ -328,7 +328,7 @@ void TextNode::compute_text_for_rendering()
if (dom_node().is_editable() && !dom_node().is_uninteresting_whitespace_node()) if (dom_node().is_editable() && !dom_node().is_uninteresting_whitespace_node())
collapse = false; collapse = false;
auto data = apply_text_transform(dom_node().data(), computed_values().text_transform()).release_value_but_fixme_should_propagate_errors(); auto data = apply_text_transform(dom_node().data().to_deprecated_string(), computed_values().text_transform()).release_value_but_fixme_should_propagate_errors();
if (dom_node().is_password_input()) { if (dom_node().is_password_input()) {
m_text_for_rendering = DeprecatedString::repeated('*', data.length()); m_text_for_rendering = DeprecatedString::repeated('*', data.length());

View file

@ -29,9 +29,9 @@ void EditEventHandler::handle_delete_character_after(DOM::Position const& cursor
} }
StringBuilder builder; StringBuilder builder;
builder.append(text.substring_view(0, cursor_position.offset())); builder.append(text.bytes_as_string_view().substring_view(0, cursor_position.offset()));
builder.append(text.substring_view(*next_grapheme_offset)); builder.append(text.bytes_as_string_view().substring_view(*next_grapheme_offset));
node.set_data(builder.to_deprecated_string()); node.set_data(MUST(builder.to_string()));
// FIXME: When nodes are removed from the DOM, the associated layout nodes become stale and still // FIXME: When nodes are removed from the DOM, the associated layout nodes become stale and still
// remain in the layout tree. This has to be fixed, this just causes everything to be recomputed // remain in the layout tree. This has to be fixed, this just causes everything to be recomputed
@ -49,10 +49,10 @@ void EditEventHandler::handle_delete(DOM::Range& range)
if (start == end) { if (start == end) {
StringBuilder builder; StringBuilder builder;
builder.append(start->data().substring_view(0, range.start_offset())); builder.append(start->data().bytes_as_string_view().substring_view(0, range.start_offset()));
builder.append(end->data().substring_view(range.end_offset())); builder.append(end->data().bytes_as_string_view().substring_view(range.end_offset()));
start->set_data(builder.to_deprecated_string()); start->set_data(MUST(builder.to_string()));
} else { } else {
// Remove all the nodes that are fully enclosed in the range. // Remove all the nodes that are fully enclosed in the range.
HashTable<DOM::Node*> queued_for_deletion; HashTable<DOM::Node*> queued_for_deletion;
@ -87,10 +87,10 @@ void EditEventHandler::handle_delete(DOM::Range& range)
// Join the start and end nodes. // Join the start and end nodes.
StringBuilder builder; StringBuilder builder;
builder.append(start->data().substring_view(0, range.start_offset())); builder.append(start->data().bytes_as_string_view().substring_view(0, range.start_offset()));
builder.append(end->data().substring_view(range.end_offset())); builder.append(end->data().bytes_as_string_view().substring_view(range.end_offset()));
start->set_data(builder.to_deprecated_string()); start->set_data(MUST(builder.to_string()));
end->remove(); end->remove();
} }
@ -108,10 +108,10 @@ void EditEventHandler::handle_insert(DOM::Position position, u32 code_point)
auto& node = verify_cast<DOM::Text>(*position.node()); auto& node = verify_cast<DOM::Text>(*position.node());
StringBuilder builder; StringBuilder builder;
builder.append(node.data().substring_view(0, position.offset())); builder.append(node.data().bytes_as_string_view().substring_view(0, position.offset()));
builder.append_code_point(code_point); builder.append_code_point(code_point);
builder.append(node.data().substring_view(position.offset())); builder.append(node.data().bytes_as_string_view().substring_view(position.offset()));
node.set_data(builder.to_deprecated_string()); node.set_data(MUST(builder.to_string()));
node.invalidate_style(); node.invalidate_style();
} }

View file

@ -772,7 +772,7 @@ bool EventHandler::handle_keydown(KeyCode key, unsigned modifiers, u32 code_poin
} }
if (key == KeyCode::Key_End) { if (key == KeyCode::Key_End) {
auto& node = *static_cast<DOM::Text*>(const_cast<DOM::Node*>(m_browsing_context->cursor_position().node())); auto& node = *static_cast<DOM::Text*>(const_cast<DOM::Node*>(m_browsing_context->cursor_position().node()));
m_browsing_context->set_cursor_position(DOM::Position { node, (unsigned)node.data().length() }); m_browsing_context->set_cursor_position(DOM::Position { node, (unsigned)node.data().bytes().size() });
return true; return true;
} }
if (!should_ignore_keydown_event(code_point)) { if (!should_ignore_keydown_event(code_point)) {

View file

@ -140,7 +140,7 @@ void XMLDocumentBuilder::text(StringView data)
auto& text_node = static_cast<DOM::Text&>(*last); auto& text_node = static_cast<DOM::Text&>(*last);
text_builder.append(text_node.data()); text_builder.append(text_node.data());
text_builder.append(data); text_builder.append(data);
text_node.set_data(text_builder.to_deprecated_string()); text_node.set_data(MUST(text_builder.to_string()));
text_builder.clear(); text_builder.clear();
} else { } else {
auto string = DeprecatedString::empty(); auto string = DeprecatedString::empty();