From 2da615ed315032f2abd49cb7882de96c47be4baa Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Fri, 25 Jul 2025 15:57:20 -0400 Subject: [PATCH] LibWeb: Port document.execCommand and InputEvent to UTF-16 --- Libraries/LibWeb/DOM/Document.h | 2 +- Libraries/LibWeb/DOM/Document.idl | 2 +- Libraries/LibWeb/DOM/EditingHostManager.cpp | 2 +- Libraries/LibWeb/Editing/ExecCommand.cpp | 5 ++-- Libraries/LibWeb/Page/EventHandler.cpp | 26 +++++++++++---------- Libraries/LibWeb/Page/EventHandler.h | 2 +- Libraries/LibWeb/UIEvents/InputEvent.h | 6 ++--- Libraries/LibWeb/UIEvents/InputEvent.idl | 4 ++-- 8 files changed, 25 insertions(+), 24 deletions(-) diff --git a/Libraries/LibWeb/DOM/Document.h b/Libraries/LibWeb/DOM/Document.h index 27b67787354..bcc8a2ab0fc 100644 --- a/Libraries/LibWeb/DOM/Document.h +++ b/Libraries/LibWeb/DOM/Document.h @@ -665,7 +665,7 @@ public: void set_previous_document_unload_timing(DocumentUnloadTimingInfo const& previous_document_unload_timing) { m_previous_document_unload_timing = previous_document_unload_timing; } // https://w3c.github.io/editing/docs/execCommand/ - WebIDL::ExceptionOr exec_command(FlyString const& command, bool show_ui, String const& value); + WebIDL::ExceptionOr exec_command(FlyString const& command, bool show_ui, Utf16String const& value); WebIDL::ExceptionOr query_command_enabled(FlyString const& command); WebIDL::ExceptionOr query_command_indeterm(FlyString const& command); WebIDL::ExceptionOr query_command_state(FlyString const& command); diff --git a/Libraries/LibWeb/DOM/Document.idl b/Libraries/LibWeb/DOM/Document.idl index 2ae2ebf650f..0016a664de4 100644 --- a/Libraries/LibWeb/DOM/Document.idl +++ b/Libraries/LibWeb/DOM/Document.idl @@ -146,7 +146,7 @@ interface Document : Node { // https://w3c.github.io/editing/docs/execCommand/ // FIXME: [CEReactions] boolean execCommand(DOMString commandId, optional boolean showUI = false, optional (TrustedHTML or DOMString) value = ""); - [CEReactions] boolean execCommand(DOMString commandId, optional boolean showUI = false, optional DOMString value = ""); + [CEReactions] boolean execCommand(DOMString commandId, optional boolean showUI = false, optional Utf16DOMString value = ""); boolean queryCommandEnabled(DOMString commandId); boolean queryCommandIndeterm(DOMString commandId); boolean queryCommandState(DOMString commandId); diff --git a/Libraries/LibWeb/DOM/EditingHostManager.cpp b/Libraries/LibWeb/DOM/EditingHostManager.cpp index 450204f836a..f96c97f7434 100644 --- a/Libraries/LibWeb/DOM/EditingHostManager.cpp +++ b/Libraries/LibWeb/DOM/EditingHostManager.cpp @@ -43,7 +43,7 @@ void EditingHostManager::handle_insert(Utf16String 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.to_utf8_but_should_be_ported_to_utf16()); + auto editing_result = m_document->exec_command(Editing::CommandNames::insertText, false, value); if (editing_result.is_exception()) dbgln("handle_insert(): editing resulted in exception: {}", editing_result.exception()); } diff --git a/Libraries/LibWeb/Editing/ExecCommand.cpp b/Libraries/LibWeb/Editing/ExecCommand.cpp index 25fab8c5e31..e31f38c6908 100644 --- a/Libraries/LibWeb/Editing/ExecCommand.cpp +++ b/Libraries/LibWeb/Editing/ExecCommand.cpp @@ -17,7 +17,7 @@ namespace Web::DOM { // https://w3c.github.io/editing/docs/execCommand/#execcommand() -WebIDL::ExceptionOr Document::exec_command(FlyString const& command, [[maybe_unused]] bool show_ui, String const& value) +WebIDL::ExceptionOr Document::exec_command(FlyString const& command, [[maybe_unused]] bool show_ui, Utf16String const& value) { // AD-HOC: This is not directly mentioned in the spec, but all major browsers limit editing API calls to HTML documents if (!is_html_document()) @@ -101,8 +101,7 @@ WebIDL::ExceptionOr Document::exec_command(FlyString const& command, [[may auto old_character_data_version = character_data_version(); // 5. Take the action for command, passing value to the instructions as an argument. - auto utf16_value = Utf16String::from_utf8_without_validation(value); - auto command_result = command_definition.action(*this, utf16_value.utf16_view()); + auto command_result = command_definition.action(*this, value); // https://w3c.github.io/editing/docs/execCommand/#preserves-overrides // After taking the action, if the active range is collapsed, it must restore states and values from the recorded diff --git a/Libraries/LibWeb/Page/EventHandler.cpp b/Libraries/LibWeb/Page/EventHandler.cpp index 681593390ce..b41487869ad 100644 --- a/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Libraries/LibWeb/Page/EventHandler.cpp @@ -1129,7 +1129,7 @@ static GC::RootVector> target_ranges_for_input_event(D return target_ranges; } -EventResult EventHandler::input_event(FlyString const& event_name, FlyString const& input_type, HTML::Navigable& navigable, Variant code_point_or_string) +EventResult EventHandler::input_event(FlyString const& event_name, FlyString const& input_type, HTML::Navigable& navigable, Variant code_point_or_string) { auto document = navigable.active_document(); if (!document) @@ -1139,14 +1139,14 @@ EventResult EventHandler::input_event(FlyString const& event_name, FlyString con UIEvents::InputEventInit input_event_init; - if (code_point_or_string.has()) { - auto code_point = code_point_or_string.get(); - if (!is_unicode_control(code_point)) { - input_event_init.data = String::from_code_point(code_point); - } - } else { - input_event_init.data = code_point_or_string.get(); - } + code_point_or_string.visit( + [&](u32 code_point) { + if (!is_unicode_control(code_point)) + input_event_init.data = Utf16String::from_code_point(code_point); + }, + [&](Utf16String const& string) { + input_event_init.data = string; + }); input_event_init.input_type = input_type; @@ -1154,7 +1154,7 @@ EventResult EventHandler::input_event(FlyString const& event_name, FlyString con if (is(*focused_element)) { auto& navigable_container = as(*focused_element); if (navigable_container.content_navigable()) - return input_event(event_name, input_type, *navigable_container.content_navigable(), code_point_or_string); + return input_event(event_name, input_type, *navigable_container.content_navigable(), move(code_point_or_string)); } auto event = UIEvents::InputEvent::create_from_platform_event(document->realm(), event_name, input_event_init, target_ranges_for_input_event(*document)); @@ -1385,8 +1385,10 @@ EventResult EventHandler::handle_paste(String const& text) if (!target) return EventResult::Dropped; - FIRE(input_event(UIEvents::EventNames::beforeinput, UIEvents::InputTypes::insertFromPaste, m_navigable, text)); - target->handle_insert(Utf16String::from_utf8(text)); + auto utf16_string = Utf16String::from_utf8(text); + + FIRE(input_event(UIEvents::EventNames::beforeinput, UIEvents::InputTypes::insertFromPaste, m_navigable, utf16_string)); + target->handle_insert(utf16_string); return EventResult::Handled; } diff --git a/Libraries/LibWeb/Page/EventHandler.h b/Libraries/LibWeb/Page/EventHandler.h index f6b959ffeaa..ef24cb7d726 100644 --- a/Libraries/LibWeb/Page/EventHandler.h +++ b/Libraries/LibWeb/Page/EventHandler.h @@ -50,7 +50,7 @@ private: EventResult focus_previous_element(); EventResult fire_keyboard_event(FlyString const& event_name, HTML::Navigable&, UIEvents::KeyCode, unsigned modifiers, u32 code_point, bool repeat); - [[nodiscard]] EventResult input_event(FlyString const& event_name, FlyString const& input_type, HTML::Navigable&, Variant code_point_or_string); + [[nodiscard]] EventResult input_event(FlyString const& event_name, FlyString const& input_type, HTML::Navigable&, Variant code_point_or_string); CSSPixelPoint compute_mouse_event_client_offset(CSSPixelPoint event_page_position) const; CSSPixelPoint compute_mouse_event_page_offset(CSSPixelPoint event_client_offset) const; CSSPixelPoint compute_mouse_event_movement(CSSPixelPoint event_client_offset) const; diff --git a/Libraries/LibWeb/UIEvents/InputEvent.h b/Libraries/LibWeb/UIEvents/InputEvent.h index bdecfd2b26a..5f064bd04b5 100644 --- a/Libraries/LibWeb/UIEvents/InputEvent.h +++ b/Libraries/LibWeb/UIEvents/InputEvent.h @@ -12,7 +12,7 @@ namespace Web::UIEvents { struct InputEventInit : public UIEventInit { - Optional data; + Optional data; bool is_composing { false }; FlyString input_type {}; }; @@ -28,7 +28,7 @@ public: virtual ~InputEvent() override; // https://w3c.github.io/uievents/#dom-inputevent-data - Optional data() const { return m_data; } + Optional data() const { return m_data; } // https://w3c.github.io/uievents/#dom-inputevent-iscomposing bool is_composing() const { return m_is_composing; } @@ -44,7 +44,7 @@ private: virtual void initialize(JS::Realm&) override; virtual void visit_edges(Visitor&) override; - Optional m_data; + Optional m_data; bool m_is_composing; FlyString m_input_type; Vector> m_target_ranges; diff --git a/Libraries/LibWeb/UIEvents/InputEvent.idl b/Libraries/LibWeb/UIEvents/InputEvent.idl index d47e1cb21f1..644efa04d53 100644 --- a/Libraries/LibWeb/UIEvents/InputEvent.idl +++ b/Libraries/LibWeb/UIEvents/InputEvent.idl @@ -5,7 +5,7 @@ [Exposed=Window] interface InputEvent : UIEvent { constructor(DOMString type, optional InputEventInit eventInitDict = {}); - readonly attribute USVString? data; + readonly attribute Utf16USVString? data; readonly attribute boolean isComposing; readonly attribute DOMString inputType; @@ -14,7 +14,7 @@ interface InputEvent : UIEvent { // https://w3c.github.io/uievents/#dictdef-inputeventinit dictionary InputEventInit : UIEventInit { - DOMString? data = null; + Utf16DOMString? data = null; boolean isComposing = false; DOMString inputType = ""; };