diff --git a/Libraries/LibWeb/DOM/EditingHostManager.cpp b/Libraries/LibWeb/DOM/EditingHostManager.cpp index 85aed1adea0..450204f836a 100644 --- a/Libraries/LibWeb/DOM/EditingHostManager.cpp +++ b/Libraries/LibWeb/DOM/EditingHostManager.cpp @@ -34,7 +34,7 @@ void EditingHostManager::visit_edges(Cell::Visitor& visitor) visitor.visit(m_active_contenteditable_element); } -void EditingHostManager::handle_insert(String const& value) +void EditingHostManager::handle_insert(Utf16String const& value) { // https://w3c.github.io/editing/docs/execCommand/#additional-requirements // When the user instructs the user agent to insert text inside an editing host, such as by typing on the keyboard @@ -43,7 +43,7 @@ void EditingHostManager::handle_insert(String const& value) // once or in quick succession, this specification does not define whether it is treated as one insertion or several // consecutive insertions. - auto editing_result = m_document->exec_command(Editing::CommandNames::insertText, false, value); + auto editing_result = m_document->exec_command(Editing::CommandNames::insertText, false, value.to_utf8_but_should_be_ported_to_utf16()); if (editing_result.is_exception()) dbgln("handle_insert(): editing resulted in exception: {}", editing_result.exception()); } diff --git a/Libraries/LibWeb/DOM/EditingHostManager.h b/Libraries/LibWeb/DOM/EditingHostManager.h index a460f6bf6b1..dad6225c096 100644 --- a/Libraries/LibWeb/DOM/EditingHostManager.h +++ b/Libraries/LibWeb/DOM/EditingHostManager.h @@ -23,7 +23,7 @@ class EditingHostManager public: [[nodiscard]] static GC::Ref create(JS::Realm&, GC::Ref); - virtual void handle_insert(String const&) override; + virtual void handle_insert(Utf16String const&) override; virtual void handle_delete(DeleteDirection) override; virtual EventResult handle_return_key(FlyString const& ui_input_type) override; virtual void select_all() override; diff --git a/Libraries/LibWeb/DOM/InputEventsTarget.h b/Libraries/LibWeb/DOM/InputEventsTarget.h index 5eefa8d2567..0b8610303a7 100644 --- a/Libraries/LibWeb/DOM/InputEventsTarget.h +++ b/Libraries/LibWeb/DOM/InputEventsTarget.h @@ -18,7 +18,7 @@ public: virtual GC::Ref as_cell() = 0; - virtual void handle_insert(String const&) = 0; + virtual void handle_insert(Utf16String const&) = 0; virtual EventResult handle_return_key(FlyString const& ui_input_type) = 0; enum class DeleteDirection { diff --git a/Libraries/LibWeb/HTML/FormAssociatedElement.cpp b/Libraries/LibWeb/HTML/FormAssociatedElement.cpp index 9a2d7739883..f17f65cba13 100644 --- a/Libraries/LibWeb/HTML/FormAssociatedElement.cpp +++ b/Libraries/LibWeb/HTML/FormAssociatedElement.cpp @@ -397,7 +397,7 @@ bool FormAssociatedElement::suffering_from_a_custom_error() const void FormAssociatedTextControlElement::relevant_value_was_changed() { auto the_relevant_value = relevant_value(); - auto relevant_value_length = the_relevant_value.code_points().length(); + auto relevant_value_length = the_relevant_value.length_in_code_units(); // 1. If the element has a selection: if (m_selection_start < m_selection_end) { @@ -592,13 +592,13 @@ WebIDL::ExceptionOr FormAssociatedTextControlElement::set_selection_direct } // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-setrangetext -WebIDL::ExceptionOr FormAssociatedTextControlElement::set_range_text_binding(String const& replacement) +WebIDL::ExceptionOr FormAssociatedTextControlElement::set_range_text_binding(Utf16String const& replacement) { return set_range_text_binding(replacement, m_selection_start, m_selection_end); } // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-setrangetext -WebIDL::ExceptionOr FormAssociatedTextControlElement::set_range_text_binding(String const& replacement, WebIDL::UnsignedLong start, WebIDL::UnsignedLong end, Bindings::SelectionMode selection_mode) +WebIDL::ExceptionOr FormAssociatedTextControlElement::set_range_text_binding(Utf16String const& replacement, WebIDL::UnsignedLong start, WebIDL::UnsignedLong end, Bindings::SelectionMode selection_mode) { auto& html_element = form_associated_element_to_html_element(); @@ -611,7 +611,7 @@ WebIDL::ExceptionOr FormAssociatedTextControlElement::set_range_text_bindi } // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-setrangetext -WebIDL::ExceptionOr FormAssociatedTextControlElement::set_range_text(String const& replacement, WebIDL::UnsignedLong start, WebIDL::UnsignedLong end, Bindings::SelectionMode selection_mode) +WebIDL::ExceptionOr FormAssociatedTextControlElement::set_range_text(Utf16String const& replacement, WebIDL::UnsignedLong start, WebIDL::UnsignedLong end, Bindings::SelectionMode selection_mode) { auto& html_element = form_associated_element_to_html_element(); @@ -628,7 +628,7 @@ WebIDL::ExceptionOr FormAssociatedTextControlElement::set_range_text(Strin // 5. If start is greater than the length of the relevant value of the text control, then set it to the length of the relevant value of the text control. auto the_relevant_value = relevant_value(); - auto relevant_value_length = the_relevant_value.code_points().length(); + auto relevant_value_length = the_relevant_value.length_in_code_units(); if (start > relevant_value_length) start = relevant_value_length; @@ -645,26 +645,24 @@ WebIDL::ExceptionOr FormAssociatedTextControlElement::set_range_text(Strin // 9. If start is less than end, delete the sequence of code units within the element's relevant value starting with // the code unit at the startth position and ending with the code unit at the (end-1)th position. if (start < end) { - StringBuilder builder; - auto before_removal_point_view = the_relevant_value.code_points().unicode_substring_view(0, start); - builder.append(before_removal_point_view.as_string()); - auto after_removal_point_view = the_relevant_value.code_points().unicode_substring_view(end); - builder.append(after_removal_point_view.as_string()); - the_relevant_value = MUST(builder.to_string()); + StringBuilder builder(StringBuilder::Mode::UTF16, the_relevant_value.length_in_code_units() - (end - start)); + builder.append(the_relevant_value.substring_view(0, start)); + builder.append(the_relevant_value.substring_view(end)); + + the_relevant_value = builder.to_utf16_string(); } // 10. Insert the value of the first argument into the text of the relevant value of the text control, immediately before the startth code unit. - StringBuilder builder; - auto before_insertion_point_view = the_relevant_value.code_points().unicode_substring_view(0, start); - builder.append(before_insertion_point_view.as_string()); + StringBuilder builder(StringBuilder::Mode::UTF16, the_relevant_value.length_in_code_units() + replacement.length_in_code_units()); + builder.append(the_relevant_value.substring_view(0, start)); builder.append(replacement); - auto after_insertion_point_view = the_relevant_value.code_points().unicode_substring_view(start); - builder.append(after_insertion_point_view.as_string()); - the_relevant_value = MUST(builder.to_string()); + builder.append(the_relevant_value.substring_view(start)); + + the_relevant_value = builder.to_utf16_string(); TRY(set_relevant_value(the_relevant_value)); // 11. Let new length be the length of the value of the first argument. - i64 new_length = replacement.code_points().length(); + auto new_length = replacement.length_in_code_units(); // 12. Let new end be the sum of start and new length. auto new_end = start + new_length; @@ -755,7 +753,8 @@ void FormAssociatedTextControlElement::set_the_selection_range(Optionalmax_length(); max_length.has_value()) { - 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)); - } + auto remaining_length = *max_length - text_node->length_in_utf16_code_units(); + if (remaining_length < data.length_in_code_units()) + data_for_insertion = Utf16String::from_utf16_without_validation(data.substring_view(0, remaining_length)); } + auto selection_start = this->selection_start(); auto selection_end = this->selection_end(); MUST(set_range_text(data_for_insertion, selection_start, selection_end, Bindings::SelectionMode::End)); @@ -824,21 +823,22 @@ void FormAssociatedTextControlElement::handle_delete(DeleteDirection direction) auto text_node = form_associated_element_to_text_node(); if (!text_node || !is_mutable()) return; + auto selection_start = this->selection_start(); auto selection_end = this->selection_end(); + if (selection_start == selection_end) { if (direction == DeleteDirection::Backward) { - if (selection_start > 0) { - MUST(set_range_text(String {}, selection_start - 1, selection_end, Bindings::SelectionMode::End)); - } + if (selection_start > 0) + MUST(set_range_text({}, selection_start - 1, selection_end, Bindings::SelectionMode::End)); } else { - if (selection_start < text_node->data().length_in_code_points()) { - MUST(set_range_text(String {}, selection_start, selection_end + 1, Bindings::SelectionMode::End)); - } + if (selection_start < text_node->length_in_utf16_code_units()) + MUST(set_range_text({}, selection_start, selection_end + 1, Bindings::SelectionMode::End)); } return; } - MUST(set_range_text(String {}, selection_start, selection_end, Bindings::SelectionMode::End)); + + MUST(set_range_text({}, selection_start, selection_end, Bindings::SelectionMode::End)); } EventResult FormAssociatedTextControlElement::handle_return_key(FlyString const&) diff --git a/Libraries/LibWeb/HTML/FormAssociatedElement.h b/Libraries/LibWeb/HTML/FormAssociatedElement.h index 31fafa8a920..ffee6a1e534 100644 --- a/Libraries/LibWeb/HTML/FormAssociatedElement.h +++ b/Libraries/LibWeb/HTML/FormAssociatedElement.h @@ -181,8 +181,8 @@ class FormAssociatedTextControlElement , public InputEventsTarget { public: // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-textarea/input-relevant-value - virtual String relevant_value() = 0; - virtual WebIDL::ExceptionOr set_relevant_value(String const&) = 0; + virtual Utf16String relevant_value() = 0; + virtual WebIDL::ExceptionOr set_relevant_value(Utf16String const&) = 0; virtual void set_dirty_value_flag(bool flag) = 0; @@ -206,9 +206,9 @@ public: SelectionDirection selection_direction_state() const { return m_selection_direction; } // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-setrangetext - WebIDL::ExceptionOr set_range_text_binding(String const& replacement); - WebIDL::ExceptionOr set_range_text_binding(String const& replacement, WebIDL::UnsignedLong start, WebIDL::UnsignedLong end, Bindings::SelectionMode = Bindings::SelectionMode::Preserve); - WebIDL::ExceptionOr set_range_text(String const& replacement, WebIDL::UnsignedLong start, WebIDL::UnsignedLong end, Bindings::SelectionMode = Bindings::SelectionMode::Preserve); + WebIDL::ExceptionOr set_range_text_binding(Utf16String const& replacement); + WebIDL::ExceptionOr set_range_text_binding(Utf16String const& replacement, WebIDL::UnsignedLong start, WebIDL::UnsignedLong end, Bindings::SelectionMode = Bindings::SelectionMode::Preserve); + WebIDL::ExceptionOr set_range_text(Utf16String const& replacement, WebIDL::UnsignedLong start, WebIDL::UnsignedLong end, Bindings::SelectionMode = Bindings::SelectionMode::Preserve); // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-setselectionrange void set_the_selection_range(Optional start, Optional end, SelectionDirection direction = SelectionDirection::None, SelectionSource source = SelectionSource::DOM); @@ -228,7 +228,7 @@ public: virtual GC::Ptr form_associated_element_to_text_node() = 0; virtual GC::Ptr form_associated_element_to_text_node() const { return const_cast(*this).form_associated_element_to_text_node(); } - virtual void handle_insert(String const&) override; + virtual void handle_insert(Utf16String const&) override; virtual void handle_delete(DeleteDirection) override; virtual EventResult handle_return_key(FlyString const& ui_input_type) override; virtual void select_all() override; diff --git a/Libraries/LibWeb/HTML/HTMLInputElement.h b/Libraries/LibWeb/HTML/HTMLInputElement.h index d735845ab7f..e70ba394a2a 100644 --- a/Libraries/LibWeb/HTML/HTMLInputElement.h +++ b/Libraries/LibWeb/HTML/HTMLInputElement.h @@ -84,8 +84,8 @@ public: WebIDL::ExceptionOr set_value(String const&); // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-textarea/input-relevant-value - virtual String relevant_value() override { return value(); } - WebIDL::ExceptionOr set_relevant_value(String const& value) override { return set_value(value); } + virtual Utf16String relevant_value() override { return Utf16String::from_utf8(value()); } + WebIDL::ExceptionOr set_relevant_value(Utf16String const& value) override { return set_value(value.to_utf8_but_should_be_ported_to_utf16()); } virtual void set_dirty_value_flag(bool flag) override { m_dirty_value = flag; } diff --git a/Libraries/LibWeb/HTML/HTMLInputElement.idl b/Libraries/LibWeb/HTML/HTMLInputElement.idl index 10339da9ca6..58e321433e3 100644 --- a/Libraries/LibWeb/HTML/HTMLInputElement.idl +++ b/Libraries/LibWeb/HTML/HTMLInputElement.idl @@ -65,8 +65,8 @@ interface HTMLInputElement : HTMLElement { [ImplementedAs=selection_start_binding] attribute unsigned long? selectionStart; [ImplementedAs=selection_end_binding] attribute unsigned long? selectionEnd; [ImplementedAs=selection_direction_binding] attribute DOMString? selectionDirection; - [ImplementedAs=set_range_text_binding] undefined setRangeText(DOMString replacement); - [ImplementedAs=set_range_text_binding] undefined setRangeText(DOMString replacement, unsigned long start, unsigned long end, optional SelectionMode selectionMode = "preserve"); + [ImplementedAs=set_range_text_binding] undefined setRangeText(Utf16DOMString replacement); + [ImplementedAs=set_range_text_binding] undefined setRangeText(Utf16DOMString replacement, unsigned long start, unsigned long end, optional SelectionMode selectionMode = "preserve"); undefined setSelectionRange(unsigned long start, unsigned long end, optional DOMString direction); undefined showPicker(); diff --git a/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp b/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp index 1e94bb65fbb..fbd5da1530a 100644 --- a/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp @@ -219,9 +219,9 @@ String HTMLTextAreaElement::api_value() const } // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-textarea/input-relevant-value -WebIDL::ExceptionOr HTMLTextAreaElement::set_relevant_value(String const& value) +WebIDL::ExceptionOr HTMLTextAreaElement::set_relevant_value(Utf16String const& value) { - set_value(value); + set_value(value.to_utf8_but_should_be_ported_to_utf16()); return {}; } diff --git a/Libraries/LibWeb/HTML/HTMLTextAreaElement.h b/Libraries/LibWeb/HTML/HTMLTextAreaElement.h index 491849821f9..ab2dea28fd2 100644 --- a/Libraries/LibWeb/HTML/HTMLTextAreaElement.h +++ b/Libraries/LibWeb/HTML/HTMLTextAreaElement.h @@ -87,8 +87,8 @@ public: String api_value() const; // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-textarea/input-relevant-value - virtual String relevant_value() override { return api_value(); } - virtual WebIDL::ExceptionOr set_relevant_value(String const& value) override; + virtual Utf16String relevant_value() override { return Utf16String::from_utf8(api_value()); } + virtual WebIDL::ExceptionOr set_relevant_value(Utf16String const& value) override; virtual void set_dirty_value_flag(bool flag) override { m_dirty_value = flag; } diff --git a/Libraries/LibWeb/HTML/HTMLTextAreaElement.idl b/Libraries/LibWeb/HTML/HTMLTextAreaElement.idl index e8fd4c386f6..786ed392d35 100644 --- a/Libraries/LibWeb/HTML/HTMLTextAreaElement.idl +++ b/Libraries/LibWeb/HTML/HTMLTextAreaElement.idl @@ -39,7 +39,7 @@ interface HTMLTextAreaElement : HTMLElement { [ImplementedAs=selection_start_binding] attribute unsigned long selectionStart; [ImplementedAs=selection_end_binding] attribute unsigned long selectionEnd; [ImplementedAs=selection_direction_binding] attribute DOMString selectionDirection; - [ImplementedAs=set_range_text_binding] undefined setRangeText(DOMString replacement); - [ImplementedAs=set_range_text_binding] undefined setRangeText(DOMString replacement, unsigned long start, unsigned long end, optional SelectionMode selectionMode = "preserve"); + [ImplementedAs=set_range_text_binding] undefined setRangeText(Utf16DOMString replacement); + [ImplementedAs=set_range_text_binding] undefined setRangeText(Utf16DOMString replacement, unsigned long start, unsigned long end, optional SelectionMode selectionMode = "preserve"); undefined setSelectionRange(unsigned long start, unsigned long end, optional DOMString direction); }; diff --git a/Libraries/LibWeb/Page/EventHandler.cpp b/Libraries/LibWeb/Page/EventHandler.cpp index 69b6f74196a..681593390ce 100644 --- a/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Libraries/LibWeb/Page/EventHandler.cpp @@ -1288,7 +1288,7 @@ EventResult EventHandler::handle_keydown(UIEvents::KeyCode key, u32 modifiers, u FIRE(input_event(UIEvents::EventNames::beforeinput, input_type, m_navigable, code_point)); if (target->handle_return_key(input_type) != EventResult::Handled) - target->handle_insert(String::from_code_point(code_point)); + target->handle_insert(Utf16String::from_code_point(code_point)); return EventResult::Handled; } @@ -1296,7 +1296,7 @@ EventResult EventHandler::handle_keydown(UIEvents::KeyCode key, u32 modifiers, u // FIXME: Text editing shortcut keys (copy/paste etc.) should be handled here. if (!should_ignore_keydown_event(code_point, modifiers)) { FIRE(input_event(UIEvents::EventNames::beforeinput, UIEvents::InputTypes::insertText, m_navigable, code_point)); - target->handle_insert(String::from_code_point(code_point)); + target->handle_insert(Utf16String::from_code_point(code_point)); return EventResult::Handled; } } else if (auto selection = document->get_selection(); selection && !selection->is_collapsed()) { @@ -1386,7 +1386,7 @@ EventResult EventHandler::handle_paste(String const& text) return EventResult::Dropped; FIRE(input_event(UIEvents::EventNames::beforeinput, UIEvents::InputTypes::insertFromPaste, m_navigable, text)); - target->handle_insert(text); + target->handle_insert(Utf16String::from_utf8(text)); return EventResult::Handled; } diff --git a/Services/WebContent/WebDriverConnection.cpp b/Services/WebContent/WebDriverConnection.cpp index 45c59c9c006..d509640fd2f 100644 --- a/Services/WebContent/WebDriverConnection.cpp +++ b/Services/WebContent/WebDriverConnection.cpp @@ -1978,14 +1978,8 @@ Web::WebDriver::Response WebDriverConnection::element_send_keys_impl(StringView if (target.has_value()) { // 1. If element does not currently have focus, let current text length be the length of element's API value. Optional current_text_length; - - if (!element->is_focused()) { - auto api_value = target->relevant_value(); - - // FIXME: This should be a UTF-16 code unit length, but `set_the_selection_range` is also currently - // implemented in terms of code point length. - current_text_length = api_value.code_points().length(); - } + if (!element->is_focused()) + current_text_length = target->relevant_value().length_in_code_units(); // 2. Set the text insertion caret using set selection range using current text length for both the start // and end parameters.