blob: 7a38b9c3b76764fbbc1c5e536c647f08105de78b [file] [log] [blame]
Avi Drissman8ba1bad2022-09-13 19:22:361// Copyright 2012 The Chromium Authors
[email protected]9c318862011-02-01 22:27:242// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Evan Stade61ccab72020-01-17 20:17:515#include "components/find_in_page/find_tab_helper.h"
[email protected]9c318862011-02-01 22:27:246
Eric Lawrence92b29bf2019-02-15 16:40:247#include <utility>
[email protected]9c318862011-02-01 22:27:248
David Sanders646a03e2022-02-22 14:33:349#include "base/observer_list.h"
avif9ab5d942015-10-15 14:05:4410#include "base/strings/string_util.h"
avi655876a2015-12-25 07:18:1511#include "build/build_config.h"
Evan Stade61ccab72020-01-17 20:17:5112#include "components/find_in_page/find_result_observer.h"
13#include "components/find_in_page/find_types.h"
dmazzoni1a69e2b32014-11-06 20:34:2814#include "content/public/browser/render_frame_host.h"
[email protected]d9083482012-01-06 00:38:4615#include "content/public/browser/web_contents.h"
[email protected]815dd9872011-11-23 18:40:3016#include "content/public/common/stop_find_action.h"
Rakina Zata Amni3f77dff2018-09-08 16:19:4317#include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
tfarina3b0452d2014-12-31 15:20:0918#include "ui/gfx/geometry/rect_f.h"
[email protected]216813952011-05-19 22:21:2619
[email protected]768c5472011-12-26 19:06:1720using content::WebContents;
[email protected]9c318862011-02-01 22:27:2421
Evan Stade61ccab72020-01-17 20:17:5122namespace find_in_page {
23
[email protected]9c318862011-02-01 22:27:2424// static
[email protected]c90c6ca2011-02-16 20:11:3825int FindTabHelper::find_request_id_counter_ = -1;
[email protected]9c318862011-02-01 22:27:2426
[email protected]d9083482012-01-06 00:38:4627FindTabHelper::FindTabHelper(WebContents* web_contents)
Dave Tapuskaeeb68792021-11-16 21:38:4028 : content::WebContentsUserData<FindTabHelper>(*web_contents),
[email protected]9c318862011-02-01 22:27:2429 current_find_request_id_(find_request_id_counter_++),
Evan Stade61ccab72020-01-17 20:17:5130 current_find_session_id_(current_find_request_id_) {}
[email protected]9c318862011-02-01 22:27:2431
Evan Stade0e39ab762019-11-15 01:42:1332FindTabHelper::~FindTabHelper() {
33 for (auto& observer : observers_)
34 observer.OnFindTabHelperDestroyed(this);
35}
Evan Stade70a3cef2019-07-11 20:45:3636
37void FindTabHelper::AddObserver(FindResultObserver* observer) {
38 observers_.AddObserver(observer);
39}
40
41void FindTabHelper::RemoveObserver(FindResultObserver* observer) {
42 observers_.RemoveObserver(observer);
[email protected]9c318862011-02-01 22:27:2443}
44
Jan Wilken Dörriefa241ba2021-03-11 17:57:0145void FindTabHelper::StartFinding(std::u16string search_string,
[email protected]c90c6ca2011-02-16 20:11:3846 bool forward_direction,
Rakina Zata Amnid4ce97f2018-08-17 12:51:4247 bool case_sensitive,
Russell Davis715fe032020-09-16 01:51:0948 bool find_match,
Rakina Zata Amnid4ce97f2018-08-17 12:51:4249 bool run_synchronously_for_testing) {
[email protected]102402c2014-07-09 19:53:3850 // Remove the carriage return character, which generally isn't in web content.
Jan Wilken Dörriecf672362021-03-15 14:16:0151 const char16_t kInvalidChars[] = u"\r";
[email protected]102402c2014-07-09 19:53:3852 base::RemoveChars(search_string, kInvalidChars, &search_string);
Sakib Shabir Tantrayf889010a2025-01-31 10:01:5953 is_find_session_active_ = true;
[email protected]102402c2014-07-09 19:53:3854
Russell Davis136df172020-10-15 18:00:4255 // Keep track of what the last search was across the tabs.
56 if (delegate_)
57 delegate_->SetLastSearchText(search_string);
[email protected]9c318862011-02-01 22:27:2458
Russell Davis136df172020-10-15 18:00:4259 if (search_string.empty()) {
60 StopFinding(find_in_page::SelectionAction::kClear);
61 for (auto& observer : observers_)
Dave Tapuskaeeb68792021-11-16 21:38:4062 observer.OnFindEmptyText(&GetWebContents());
Russell Davis136df172020-10-15 18:00:4263 return;
[email protected]9c318862011-02-01 22:27:2464 }
65
Russell Davis136df172020-10-15 18:00:4266 bool new_session = find_text_ != search_string ||
Russell Davis8a36226c2020-06-05 17:09:5067 (last_search_case_sensitive_ != case_sensitive) ||
68 find_op_aborted_;
paulmeyerc0b762b2016-04-13 11:55:1769
Russell Davisdd2b6782020-09-21 23:55:5670 // Continuing here would just find the same results, potentially causing
71 // some flicker in the highlighting.
72 if (!new_session && !find_match)
73 return;
74
paulmeyerc0b762b2016-04-13 11:55:1775 current_find_request_id_ = find_request_id_counter_++;
Russell Davis8a36226c2020-06-05 17:09:5076 if (new_session)
paulmeyer1cfca292016-04-25 23:25:5777 current_find_session_id_ = current_find_request_id_;
[email protected]9c318862011-02-01 22:27:2478
Russell Davis136df172020-10-15 18:00:4279 previous_find_text_ = find_text_;
80 find_text_ = search_string;
[email protected]9c318862011-02-01 22:27:2481 last_search_case_sensitive_ = case_sensitive;
[email protected]9c318862011-02-01 22:27:2482 find_op_aborted_ = false;
Russell Davis0fa45e92020-09-30 23:09:5683 should_find_match_ = find_match;
[email protected]9c318862011-02-01 22:27:2484
Rakina Zata Amni3f77dff2018-09-08 16:19:4385 auto options = blink::mojom::FindOptions::New();
86 options->forward = forward_direction;
87 options->match_case = case_sensitive;
Russell Davis8a36226c2020-06-05 17:09:5088 options->new_session = new_session;
Russell Davis715fe032020-09-16 01:51:0989 options->find_match = find_match;
Rakina Zata Amni3f77dff2018-09-08 16:19:4390 options->run_synchronously_for_testing = run_synchronously_for_testing;
Dave Tapuskaeeb68792021-11-16 21:38:4091 GetWebContents().Find(current_find_request_id_, find_text_,
Avi Drissman5710b062024-07-02 21:23:2992 std::move(options), /*skip_delay=*/false);
[email protected]9c318862011-02-01 22:27:2493}
94
Evan Stade61ccab72020-01-17 20:17:5195void FindTabHelper::StopFinding(SelectionAction selection_action) {
96 if (selection_action == SelectionAction::kClear) {
[email protected]9c318862011-02-01 22:27:2497 // kClearSelection means the find string has been cleared by the user, but
98 // the UI has not been dismissed. In that case we want to clear the
99 // previously remembered search (http://crbug.com/42639).
Jan Wilken Dörriefa241ba2021-03-11 17:57:01100 previous_find_text_ = std::u16string();
[email protected]9c318862011-02-01 22:27:24101 } else {
102 find_ui_active_ = false;
103 if (!find_text_.empty())
104 previous_find_text_ = find_text_;
105 }
106 find_text_.clear();
Eric Lawrence92b29bf2019-02-15 16:40:24107 last_completed_find_text_.clear();
[email protected]9c318862011-02-01 22:27:24108 find_op_aborted_ = true;
109 last_search_result_ = FindNotificationDetails();
Russell Davis0fa45e92020-09-30 23:09:56110 should_find_match_ = false;
Sakib Shabir Tantrayf889010a2025-01-31 10:01:59111 is_find_session_active_ = false;
[email protected]216813952011-05-19 22:21:26112
[email protected]815dd9872011-11-23 18:40:30113 content::StopFindAction action;
[email protected]216813952011-05-19 22:21:26114 switch (selection_action) {
Evan Stade61ccab72020-01-17 20:17:51115 case SelectionAction::kClear:
[email protected]815dd9872011-11-23 18:40:30116 action = content::STOP_FIND_ACTION_CLEAR_SELECTION;
[email protected]216813952011-05-19 22:21:26117 break;
Evan Stade61ccab72020-01-17 20:17:51118 case SelectionAction::kKeep:
[email protected]815dd9872011-11-23 18:40:30119 action = content::STOP_FIND_ACTION_KEEP_SELECTION;
[email protected]216813952011-05-19 22:21:26120 break;
Evan Stade61ccab72020-01-17 20:17:51121 case SelectionAction::kActivate:
[email protected]815dd9872011-11-23 18:40:30122 action = content::STOP_FIND_ACTION_ACTIVATE_SELECTION;
[email protected]216813952011-05-19 22:21:26123 break;
124 default:
Peter Boström77d21352024-11-13 22:26:11125 NOTREACHED();
[email protected]216813952011-05-19 22:21:26126 }
Dave Tapuskaeeb68792021-11-16 21:38:40127 GetWebContents().StopFinding(action);
[email protected]9c318862011-02-01 22:27:24128}
129
dmazzoni1a69e2b32014-11-06 20:34:28130void FindTabHelper::ActivateFindInPageResultForAccessibility() {
Dave Tapuska88d7b2e72022-06-07 21:00:51131 GetWebContents()
132 .GetPrimaryMainFrame()
133 ->ActivateFindInPageResultForAccessibility(current_find_request_id_);
dmazzoni1a69e2b32014-11-06 20:34:28134}
135
Jan Wilken Dörriefa241ba2021-03-11 17:57:01136std::u16string FindTabHelper::GetInitialSearchText() {
Evan Stade61ccab72020-01-17 20:17:51137 // Try the last thing we searched for in this tab.
138 if (!previous_find_text_.empty())
139 return previous_find_text_;
140
141 // Then defer to the delegate.
Jan Wilken Dörriefa241ba2021-03-11 17:57:01142 return delegate_ ? delegate_->GetSearchPrepopulateText() : std::u16string();
Evan Stade61ccab72020-01-17 20:17:51143}
144
Xiaohan Wangbca91f92022-01-15 19:56:21145#if BUILDFLAG(IS_ANDROID)
[email protected]59363fc92012-09-05 03:46:31146void FindTabHelper::ActivateNearestFindResult(float x, float y) {
147 if (!find_op_aborted_ && !find_text_.empty()) {
Dave Tapuskaeeb68792021-11-16 21:38:40148 GetWebContents().ActivateNearestFindResult(x, y);
[email protected]59363fc92012-09-05 03:46:31149 }
150}
151
152void FindTabHelper::RequestFindMatchRects(int current_version) {
153 if (!find_op_aborted_ && !find_text_.empty())
Dave Tapuskaeeb68792021-11-16 21:38:40154 GetWebContents().RequestFindMatchRects(current_version);
[email protected]59363fc92012-09-05 03:46:31155}
156#endif
157
[email protected]b888919c2011-09-02 00:32:16158void FindTabHelper::HandleFindReply(int request_id,
159 int number_of_matches,
160 const gfx::Rect& selection_rect,
161 int active_match_ordinal,
162 bool final_update) {
[email protected]9c318862011-02-01 22:27:24163 // Ignore responses for requests that have been aborted.
paulmeyer1cfca292016-04-25 23:25:57164 // Ignore responses for requests from previous sessions. That way we won't act
165 // on stale results when the user has already typed in another query.
166 if (!find_op_aborted_ && request_id >= current_find_session_id_) {
[email protected]9c318862011-02-01 22:27:24167 if (number_of_matches == -1)
168 number_of_matches = last_search_result_.number_of_matches();
169 if (active_match_ordinal == -1)
170 active_match_ordinal = last_search_result_.active_match_ordinal();
171
172 gfx::Rect selection = selection_rect;
[email protected]27e7a0552012-03-16 00:01:17173 if (final_update && active_match_ordinal == 0)
174 selection = gfx::Rect();
175 else if (selection_rect.IsEmpty())
[email protected]9c318862011-02-01 22:27:24176 selection = last_search_result_.selection_rect();
177
178 // Notify the UI, automation and any other observers that a find result was
179 // found.
Evan Stade61ccab72020-01-17 20:17:51180 last_search_result_ =
181 FindNotificationDetails(request_id, number_of_matches, selection,
182 active_match_ordinal, final_update);
Evan Stade70a3cef2019-07-11 20:45:36183 for (auto& observer : observers_)
Dave Tapuskaeeb68792021-11-16 21:38:40184 observer.OnFindResultAvailable(&GetWebContents());
[email protected]9c318862011-02-01 22:27:24185 }
[email protected]9c318862011-02-01 22:27:24186}
François Doray4f51d5d2018-12-03 22:26:24187
Daniel Cheng383df852021-10-02 03:28:01188WEB_CONTENTS_USER_DATA_KEY_IMPL(FindTabHelper);
Evan Stade61ccab72020-01-17 20:17:51189
190} // namespace find_in_page