diff --git a/Userland/Libraries/LibWeb/Page/EventHandler.cpp b/Userland/Libraries/LibWeb/Page/EventHandler.cpp index 28c98f5698f..6171cf9a236 100644 --- a/Userland/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Userland/Libraries/LibWeb/Page/EventHandler.cpp @@ -5,6 +5,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -685,30 +686,16 @@ bool EventHandler::handle_doubleclick(CSSPixelPoint viewport_position, CSSPixelP auto& hit_dom_node = const_cast(verify_cast(*hit_paintable.dom_node())); auto const& text_for_rendering = hit_paintable.text_for_rendering(); - int first_word_break_before = [&] { - // Start from one before the index position to prevent selecting only spaces between words, caused by the addition below. - // This also helps us dealing with cases where index is equal to the string length. - for (int i = result->index_in_node - 1; i >= 0; --i) { - if (is_ascii_space(text_for_rendering.bytes_as_string_view()[i])) { - // Don't include the space in the selection - return i + 1; - } - } - return 0; - }(); + auto& segmenter = word_segmenter(); + segmenter.set_segmented_text(text_for_rendering); - int first_word_break_after = [&] { - for (size_t i = result->index_in_node; i < text_for_rendering.bytes().size(); ++i) { - if (is_ascii_space(text_for_rendering.bytes_as_string_view()[i])) - return i; - } - return text_for_rendering.bytes().size(); - }(); + auto previous_boundary = segmenter.previous_boundary(result->index_in_node, Unicode::Segmenter::Inclusive::Yes).value_or(0); + auto next_boundary = segmenter.next_boundary(result->index_in_node).value_or(text_for_rendering.byte_count()); auto& realm = node->document().realm(); - document.set_cursor_position(DOM::Position::create(realm, hit_dom_node, first_word_break_after)); + document.set_cursor_position(DOM::Position::create(realm, hit_dom_node, next_boundary)); if (auto selection = node->document().get_selection()) { - (void)selection->set_base_and_extent(hit_dom_node, first_word_break_before, hit_dom_node, first_word_break_after); + (void)selection->set_base_and_extent(hit_dom_node, previous_boundary, hit_dom_node, next_boundary); } update_selection_range_for_input_or_textarea(); } @@ -1169,4 +1156,11 @@ void EventHandler::update_selection_range_for_input_or_textarea() target.value().set_the_selection_range(selection_start, selection_end, direction); } +Unicode::Segmenter& EventHandler::word_segmenter() +{ + if (!m_word_segmenter) + m_word_segmenter = Unicode::Segmenter::create(Unicode::SegmenterGranularity::Word); + return *m_word_segmenter; +} + } diff --git a/Userland/Libraries/LibWeb/Page/EventHandler.h b/Userland/Libraries/LibWeb/Page/EventHandler.h index d6c5392c186..adaa33bf300 100644 --- a/Userland/Libraries/LibWeb/Page/EventHandler.h +++ b/Userland/Libraries/LibWeb/Page/EventHandler.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,8 @@ public: void visit_edges(JS::Cell::Visitor& visitor) const; + Unicode::Segmenter& word_segmenter(); + private: bool focus_next_element(); bool focus_previous_element(); @@ -74,6 +77,8 @@ private: WeakPtr m_mousedown_target; Optional m_mousemove_previous_screen_position; + + OwnPtr m_word_segmenter; }; }