blob: b94f420dc1e7458e0d9bba6fdf4365af28fbb8a5 [file] [log] [blame]
[email protected]e9856c22012-01-27 01:51:591// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[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#include <vector>
9
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"
[email protected]ad50def52011-10-19 23:17:0714#include "content/public/browser/notification_service.h"
dmazzoni1a69e2b32014-11-06 20:34:2815#include "content/public/browser/render_frame_host.h"
[email protected]9c1662b2012-03-06 15:44:3316#include "content/public/browser/render_view_host.h"
[email protected]d9083482012-01-06 00:38:4617#include "content/public/browser/web_contents.h"
[email protected]815dd9872011-11-23 18:40:3018#include "content/public/common/stop_find_action.h"
Rakina Zata Amni3f77dff2018-09-08 16:19:4319#include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
tfarina3b0452d2014-12-31 15:20:0920#include "ui/gfx/geometry/rect_f.h"
[email protected]216813952011-05-19 22:21:2621
[email protected]768c5472011-12-26 19:06:1722using content::WebContents;
[email protected]9c318862011-02-01 22:27:2423
Evan Stade61ccab72020-01-17 20:17:5124namespace find_in_page {
25
[email protected]9c318862011-02-01 22:27:2426// static
[email protected]c90c6ca2011-02-16 20:11:3827int FindTabHelper::find_request_id_counter_ = -1;
[email protected]9c318862011-02-01 22:27:2428
[email protected]d9083482012-01-06 00:38:4629FindTabHelper::FindTabHelper(WebContents* web_contents)
30 : content::WebContentsObserver(web_contents),
[email protected]9c318862011-02-01 22:27:2431 current_find_request_id_(find_request_id_counter_++),
Evan Stade61ccab72020-01-17 20:17:5132 current_find_session_id_(current_find_request_id_) {}
[email protected]9c318862011-02-01 22:27:2433
Evan Stade0e39ab762019-11-15 01:42:1334FindTabHelper::~FindTabHelper() {
35 for (auto& observer : observers_)
36 observer.OnFindTabHelperDestroyed(this);
37}
Evan Stade70a3cef2019-07-11 20:45:3638
39void FindTabHelper::AddObserver(FindResultObserver* observer) {
40 observers_.AddObserver(observer);
41}
42
43void FindTabHelper::RemoveObserver(FindResultObserver* observer) {
44 observers_.RemoveObserver(observer);
[email protected]9c318862011-02-01 22:27:2445}
46
[email protected]b959d7d42013-12-13 17:26:3747void FindTabHelper::StartFinding(base::string16 search_string,
[email protected]c90c6ca2011-02-16 20:11:3848 bool forward_direction,
Rakina Zata Amnid4ce97f2018-08-17 12:51:4249 bool case_sensitive,
50 bool run_synchronously_for_testing) {
[email protected]102402c2014-07-09 19:53:3851 // Remove the carriage return character, which generally isn't in web content.
Evan Stade61ccab72020-01-17 20:17:5152 const base::char16 kInvalidChars[] = {'\r', 0};
[email protected]102402c2014-07-09 19:53:3853 base::RemoveChars(search_string, kInvalidChars, &search_string);
54
[email protected]9c318862011-02-01 22:27:2455 // If search_string is empty, it means FindNext was pressed with a keyboard
56 // shortcut so unless we have something to search for we return early.
57 if (search_string.empty() && find_text_.empty()) {
Evan Stade61ccab72020-01-17 20:17:5158 search_string = GetInitialSearchText();
[email protected]9c318862011-02-01 22:27:2459
Evan Stade61ccab72020-01-17 20:17:5160 if (search_string.empty())
[email protected]9c318862011-02-01 22:27:2461 return;
62 }
63
64 // Keep track of the previous search.
65 previous_find_text_ = find_text_;
66
67 // This is a FindNext operation if we are searching for the same text again,
68 // or if the passed in search text is empty (FindNext keyboard shortcut). The
69 // exception to this is if the Find was aborted (then we don't want FindNext
70 // because the highlighting has been cleared and we need it to reappear). We
71 // therefore treat FindNext after an aborted Find operation as a full fledged
72 // Find.
73 bool find_next = (find_text_ == search_string || search_string.empty()) &&
74 (last_search_case_sensitive_ == case_sensitive) &&
75 !find_op_aborted_;
paulmeyerc0b762b2016-04-13 11:55:1776
77 current_find_request_id_ = find_request_id_counter_++;
paulmeyer1cfca292016-04-25 23:25:5778 if (!find_next)
79 current_find_session_id_ = current_find_request_id_;
[email protected]9c318862011-02-01 22:27:2480
81 if (!search_string.empty())
82 find_text_ = search_string;
83 last_search_case_sensitive_ = case_sensitive;
84
85 find_op_aborted_ = false;
86
87 // Keep track of what the last search was across the tabs.
Evan Stade61ccab72020-01-17 20:17:5188 if (delegate_)
89 delegate_->SetLastSearchText(find_text_);
[email protected]216813952011-05-19 22:21:2690
Rakina Zata Amni3f77dff2018-09-08 16:19:4391 auto options = blink::mojom::FindOptions::New();
92 options->forward = forward_direction;
93 options->match_case = case_sensitive;
94 options->find_next = find_next;
95 options->run_synchronously_for_testing = run_synchronously_for_testing;
96 web_contents()->Find(current_find_request_id_, find_text_,
97 std::move(options));
[email protected]9c318862011-02-01 22:27:2498}
99
Evan Stade61ccab72020-01-17 20:17:51100void FindTabHelper::StopFinding(SelectionAction selection_action) {
101 if (selection_action == SelectionAction::kClear) {
[email protected]9c318862011-02-01 22:27:24102 // kClearSelection means the find string has been cleared by the user, but
103 // the UI has not been dismissed. In that case we want to clear the
104 // previously remembered search (http://crbug.com/42639).
[email protected]a04db822013-12-11 19:14:40105 previous_find_text_ = base::string16();
[email protected]9c318862011-02-01 22:27:24106 } else {
107 find_ui_active_ = false;
108 if (!find_text_.empty())
109 previous_find_text_ = find_text_;
110 }
111 find_text_.clear();
Eric Lawrence92b29bf2019-02-15 16:40:24112 last_completed_find_text_.clear();
[email protected]9c318862011-02-01 22:27:24113 find_op_aborted_ = true;
114 last_search_result_ = FindNotificationDetails();
[email protected]216813952011-05-19 22:21:26115
[email protected]815dd9872011-11-23 18:40:30116 content::StopFindAction action;
[email protected]216813952011-05-19 22:21:26117 switch (selection_action) {
Evan Stade61ccab72020-01-17 20:17:51118 case SelectionAction::kClear:
[email protected]815dd9872011-11-23 18:40:30119 action = content::STOP_FIND_ACTION_CLEAR_SELECTION;
[email protected]216813952011-05-19 22:21:26120 break;
Evan Stade61ccab72020-01-17 20:17:51121 case SelectionAction::kKeep:
[email protected]815dd9872011-11-23 18:40:30122 action = content::STOP_FIND_ACTION_KEEP_SELECTION;
[email protected]216813952011-05-19 22:21:26123 break;
Evan Stade61ccab72020-01-17 20:17:51124 case SelectionAction::kActivate:
[email protected]815dd9872011-11-23 18:40:30125 action = content::STOP_FIND_ACTION_ACTIVATE_SELECTION;
[email protected]216813952011-05-19 22:21:26126 break;
127 default:
128 NOTREACHED();
[email protected]815dd9872011-11-23 18:40:30129 action = content::STOP_FIND_ACTION_KEEP_SELECTION;
[email protected]216813952011-05-19 22:21:26130 }
[email protected]36ec24f2014-01-09 00:32:08131 web_contents()->StopFinding(action);
[email protected]9c318862011-02-01 22:27:24132}
133
dmazzoni1a69e2b32014-11-06 20:34:28134void FindTabHelper::ActivateFindInPageResultForAccessibility() {
135 web_contents()->GetMainFrame()->ActivateFindInPageResultForAccessibility(
136 current_find_request_id_);
137}
138
Evan Stade61ccab72020-01-17 20:17:51139base::string16 FindTabHelper::GetInitialSearchText() {
140 // Try the last thing we searched for in this tab.
141 if (!previous_find_text_.empty())
142 return previous_find_text_;
143
144 // Then defer to the delegate.
145 return delegate_ ? delegate_->GetSearchPrepopulateText() : base::string16();
146}
147
[email protected]59363fc92012-09-05 03:46:31148#if defined(OS_ANDROID)
149void FindTabHelper::ActivateNearestFindResult(float x, float y) {
150 if (!find_op_aborted_ && !find_text_.empty()) {
paulmeyerc0b762b2016-04-13 11:55:17151 web_contents()->ActivateNearestFindResult(x, y);
[email protected]59363fc92012-09-05 03:46:31152 }
153}
154
155void FindTabHelper::RequestFindMatchRects(int current_version) {
156 if (!find_op_aborted_ && !find_text_.empty())
paulmeyerc0b762b2016-04-13 11:55:17157 web_contents()->RequestFindMatchRects(current_version);
[email protected]59363fc92012-09-05 03:46:31158}
159#endif
160
[email protected]b888919c2011-09-02 00:32:16161void FindTabHelper::HandleFindReply(int request_id,
162 int number_of_matches,
163 const gfx::Rect& selection_rect,
164 int active_match_ordinal,
165 bool final_update) {
[email protected]9c318862011-02-01 22:27:24166 // Ignore responses for requests that have been aborted.
paulmeyer1cfca292016-04-25 23:25:57167 // Ignore responses for requests from previous sessions. That way we won't act
168 // on stale results when the user has already typed in another query.
169 if (!find_op_aborted_ && request_id >= current_find_session_id_) {
[email protected]9c318862011-02-01 22:27:24170 if (number_of_matches == -1)
171 number_of_matches = last_search_result_.number_of_matches();
172 if (active_match_ordinal == -1)
173 active_match_ordinal = last_search_result_.active_match_ordinal();
174
175 gfx::Rect selection = selection_rect;
[email protected]27e7a0552012-03-16 00:01:17176 if (final_update && active_match_ordinal == 0)
177 selection = gfx::Rect();
178 else if (selection_rect.IsEmpty())
[email protected]9c318862011-02-01 22:27:24179 selection = last_search_result_.selection_rect();
180
181 // Notify the UI, automation and any other observers that a find result was
182 // found.
Evan Stade61ccab72020-01-17 20:17:51183 last_search_result_ =
184 FindNotificationDetails(request_id, number_of_matches, selection,
185 active_match_ordinal, final_update);
Evan Stade70a3cef2019-07-11 20:45:36186 for (auto& observer : observers_)
187 observer.OnFindResultAvailable(web_contents());
[email protected]9c318862011-02-01 22:27:24188 }
[email protected]9c318862011-02-01 22:27:24189}
François Doray4f51d5d2018-12-03 22:26:24190
191WEB_CONTENTS_USER_DATA_KEY_IMPL(FindTabHelper)
Evan Stade61ccab72020-01-17 20:17:51192
193} // namespace find_in_page