From 0b753dcb448b042e221126744c419c8f546bfacc Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Sun, 23 Jun 2024 19:05:45 +0100 Subject: [PATCH] LibWeb: Base the current find in page position on the current selection Prior to this change, our find in page function always highlighted the first match whenever the query was updated. After this change the current match index is set such that it is the first match to occur after the end of the current selection. This means the current match position is not lost if the user modifies their existing query. This matches the behavior of find in page in other browsers. --- Userland/Libraries/LibWeb/Page/Page.cpp | 46 +++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/Userland/Libraries/LibWeb/Page/Page.cpp b/Userland/Libraries/LibWeb/Page/Page.cpp index 3e781aaec73..c3e5a0255a7 100644 --- a/Userland/Libraries/LibWeb/Page/Page.cpp +++ b/Userland/Libraries/LibWeb/Page/Page.cpp @@ -572,8 +572,41 @@ Page::FindInPageResult Page::perform_find_in_page_query(FindInPageQuery const& q VERIFY(top_level_traversable_is_initialized()); Vector> all_matches; - for (auto const& document : documents_in_active_window()) { + + auto find_current_match_index = [this, &direction](auto& document, auto& matches) -> size_t { + // Always return the first match if there is no active query. + if (!m_last_find_in_page_query.has_value()) + return 0; + + auto selection = document.get_selection(); + if (!selection) + return 0; + + auto range = selection->range(); + if (!range) + return 0; + + for (size_t i = 0; i < matches.size(); ++i) { + auto boundary_comparison_or_error = matches[i]->compare_boundary_points(DOM::Range::HowToCompareBoundaryPoints::START_TO_START, *range); + if (!boundary_comparison_or_error.is_error() && boundary_comparison_or_error.value() >= 0) { + // If the match occurs after the current selection then we don't need to increment the match index later on. + if (boundary_comparison_or_error.value() && direction == SearchDirection::Forward) + direction = {}; + + return i; + } + } + + return 0; + }; + + for (auto document : documents_in_active_window()) { auto matches = document->find_matching_text(query.string, query.case_sensitivity); + if (document == top_level_traversable()->active_document()) { + auto new_match_index = find_current_match_index(*document, matches); + m_find_in_page_match_index = new_match_index + all_matches.size(); + } + all_matches.extend(move(matches)); } @@ -611,17 +644,18 @@ Page::FindInPageResult Page::find_in_page(FindInPageQuery const& query) if (!top_level_traversable_is_initialized()) return {}; - m_find_in_page_match_index = 0; - m_last_find_in_page_query = query; - m_last_find_in_page_url = top_level_traversable()->active_document()->url(); - if (query.string.is_empty()) { m_last_find_in_page_query = {}; clear_selection(); return {}; } - return perform_find_in_page_query(query); + auto result = perform_find_in_page_query(query); + + m_last_find_in_page_query = query; + m_last_find_in_page_url = top_level_traversable()->active_document()->url(); + + return result; } Page::FindInPageResult Page::find_in_page_next_match()