blob: 5a6b3988d1083017d35dc8b6bd59e33a4c7a315e [file] [log] [blame]
paulmeyerc0b762b2016-04-13 11:55:171// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CONTENT_BROWSER_FIND_REQUEST_MANAGER_H_
6#define CONTENT_BROWSER_FIND_REQUEST_MANAGER_H_
7
paulmeyerc8cb7cb2016-06-07 01:14:198#include <queue>
9#include <unordered_map>
10#include <unordered_set>
11#include <utility>
paulmeyerc0b762b2016-04-13 11:55:1712#include <vector>
13
paulmeyerc8cb7cb2016-06-07 01:14:1914#include "content/common/content_export.h"
15#include "content/public/browser/web_contents_observer.h"
paulmeyerc0b762b2016-04-13 11:55:1716#include "content/public/common/stop_find_action.h"
17#include "third_party/WebKit/public/web/WebFindOptions.h"
18#include "ui/gfx/geometry/rect.h"
19#include "ui/gfx/geometry/rect_f.h"
20
21namespace content {
22
23class RenderFrameHost;
24class WebContentsImpl;
25
26// FindRequestManager manages all of the find-in-page requests/replies
27// initiated/received through a WebContents. It coordinates searching across
28// multiple (potentially out-of-process) frames, handles the aggregation of find
29// results from each frame, and facilitates active match traversal. It is
30// instantiated once per WebContents, and is owned by that WebContents.
paulmeyerc8cb7cb2016-06-07 01:14:1931class CONTENT_EXPORT FindRequestManager : public WebContentsObserver {
paulmeyerc0b762b2016-04-13 11:55:1732 public:
33 explicit FindRequestManager(WebContentsImpl* web_contents);
paulmeyerc8cb7cb2016-06-07 01:14:1934 ~FindRequestManager() override;
paulmeyerc0b762b2016-04-13 11:55:1735
36 // Initiates a find operation for |search_text| with the options specified in
37 // |options|. |request_id| uniquely identifies the find request.
38 void Find(int request_id,
39 const base::string16& search_text,
40 const blink::WebFindOptions& options);
41
42 // Stops the active find session and clears the general highlighting of the
43 // matches. |action| determines whether the last active match (if any) will be
44 // activated, cleared, or remain highlighted.
45 void StopFinding(StopFindAction action);
46
47 // Called when a reply is received from a frame with the results from a
48 // find request.
49 void OnFindReply(RenderFrameHost* rfh,
50 int request_id,
51 int number_of_matches,
52 const gfx::Rect& selection_rect,
53 int active_match_ordinal,
54 bool final_update);
55
paulmeyerc8cb7cb2016-06-07 01:14:1956 // Removes a frame from the set of frames being searched. This should be
57 // called whenever a frame is discovered to no longer exist.
58 void RemoveFrame(RenderFrameHost* rfh);
59
paulmeyerc0b762b2016-04-13 11:55:1760#if defined(OS_ANDROID)
paulmeyerc8cb7cb2016-06-07 01:14:1961 // Selects and zooms to the find result nearest to the point (x, y), defined
62 // in find-in-page coordinates.
paulmeyerc0b762b2016-04-13 11:55:1763 void ActivateNearestFindResult(float x, float y);
64
paulmeyerc8cb7cb2016-06-07 01:14:1965 // Called when a reply is received from a frame in response to the
66 // GetNearestFindResult IPC.
67 void OnGetNearestFindResultReply(RenderFrameHost* rfh,
68 int nearest_find_result_request_id,
69 float distance);
70
paulmeyerc0b762b2016-04-13 11:55:1771 // Requests the rects of the current find matches from the renderer process.
72 void RequestFindMatchRects(int current_version);
73
paulmeyerc8cb7cb2016-06-07 01:14:1974 // Called when a reply is received from a frame in response to a request for
75 // find match rects.
paulmeyerc0b762b2016-04-13 11:55:1776 void OnFindMatchRectsReply(RenderFrameHost* rfh,
77 int version,
78 const std::vector<gfx::RectF>& rects,
79 const gfx::RectF& active_rect);
80#endif
81
82 private:
83 // An invalid ID. This value is invalid for any render process ID, render
paulmeyerc8cb7cb2016-06-07 01:14:1984 // frame ID, find request ID, or find match rects version number.
paulmeyerc0b762b2016-04-13 11:55:1785 static const int kInvalidId;
86
87 // The request data for a single find request.
88 struct FindRequest {
89 // The find request ID that uniquely identifies this find request.
90 int id = kInvalidId;
91
92 // The text that is being searched for in this find request.
93 base::string16 search_text;
94
95 // The set of find options in effect for this find request.
96 blink::WebFindOptions options;
97
98 FindRequest() = default;
99 FindRequest(int id,
100 const base::string16& search_text,
101 const blink::WebFindOptions& options)
102 : id(id), search_text(search_text), options(options) {}
103 };
104
paulmeyerc8cb7cb2016-06-07 01:14:19105 // WebContentsObserver implementation.
paulmeyer3ac612d2016-09-30 19:21:06106 void DidFinishLoad(RenderFrameHost* rfh, const GURL& validated_url) override;
paulmeyerc8cb7cb2016-06-07 01:14:19107 void RenderFrameDeleted(RenderFrameHost* rfh) override;
108 void RenderFrameHostChanged(RenderFrameHost* old_host,
109 RenderFrameHost* new_host) override;
110 void FrameDeleted(RenderFrameHost* rfh) override;
111
112 // Resets all of the per-session state for a new find-in-page session.
113 void Reset(const FindRequest& initial_request);
114
115 // Called internally as find requests come up in the queue.
116 void FindInternal(const FindRequest& request);
117
118 // Called when an informative response (a response with enough information to
119 // be able to route subsequent find requests) comes in for the find request
120 // with ID |request_id|. Advances the |find_request_queue_| if appropriate.
121 void AdvanceQueue(int request_id);
122
123 // Sends a find IPC containing the find request |request| to the RenderFrame
paulmeyerc0b762b2016-04-13 11:55:17124 // associated with |rfh|.
125 void SendFindIPC(const FindRequest& request, RenderFrameHost* rfh);
126
paulmeyerc8cb7cb2016-06-07 01:14:19127 // Sends the find results (as they currently are) to the WebContents.
paulmeyerbbaacbe2016-08-30 18:04:13128 void NotifyFindReply(int request_id, bool final_update);
paulmeyerc0b762b2016-04-13 11:55:17129
paulmeyerc8cb7cb2016-06-07 01:14:19130 // Returns the initial frame in search order. This will be either the first
131 // frame, if searching forward, or the last frame, if searching backward.
132 RenderFrameHost* GetInitialFrame(bool forward) const;
133
134 // Traverses the frame tree to find and return the next RenderFrameHost after
135 // |from_rfh| in search order. |forward| indicates whether the frame tree
136 // should be traversed forward (if true) or backward (if false). If
137 // |matches_only| is set, then the frame tree will be traversed until the
138 // first frame is found for which matches have been found. If |wrap| is set,
139 // then the traversal can wrap around past the last frame to the first one (or
140 // vice-versa, if |forward| == false). If no frame can be found under these
141 // conditions, nullptr is returned.
142 RenderFrameHost* Traverse(RenderFrameHost* from_rfh,
143 bool forward,
144 bool matches_only,
145 bool wrap) const;
146
147 // Adds a frame to the set of frames that are being searched. The new frame
148 // will automatically be searched when added, using the same options (stored
paulmeyer3ac612d2016-09-30 19:21:06149 // in |current_request_.options|). |force| should be set to true when a
150 // dynamic content change is suspected, which will treat the frame as a newly
151 // added frame even if it has already been searched. This will force a
152 // re-search of the frame.
153 void AddFrame(RenderFrameHost* rfh, bool force);
paulmeyerc8cb7cb2016-06-07 01:14:19154
155 // Returns whether |rfh| is in the set of frames being searched in the current
156 // find session.
157 bool CheckFrame(RenderFrameHost* rfh) const;
158
159 // Computes and updates |active_match_ordinal_| based on |active_frame_| and
160 // |relative_active_match_ordinal_|.
161 void UpdateActiveMatchOrdinal();
162
163 // Called when all pending find replies have been received for the find
164 // request with ID |request_id|. The final update was received from |rfh|.
paulmeyerbbaacbe2016-08-30 18:04:13165 //
166 // Note that this is the final update for this particular find request, but
167 // not necessarily for all issued requests. If there are still pending replies
168 // expected for a previous find request, then the outgoing find reply issued
169 // from this function will not be marked final.
170 void FinalUpdateReceived(int request_id, RenderFrameHost* rfh);
paulmeyerc8cb7cb2016-06-07 01:14:19171
paulmeyerc0b762b2016-04-13 11:55:17172#if defined(OS_ANDROID)
paulmeyerc8cb7cb2016-06-07 01:14:19173 // Called when a nearest find result reply is no longer pending for a frame.
174 void RemoveNearestFindResultPendingReply(RenderFrameHost* rfh);
175
176 // Called when a find match rects reply is no longer pending for a frame.
177 void RemoveFindMatchRectsPendingReply(RenderFrameHost* rfh);
178
179 // State related to ActivateNearestFindResult requests.
180 struct ActivateNearestFindResultState {
181 // An ID to uniquely identify the current nearest find result request and
182 // its replies.
183 int current_request_id = kInvalidId;
184
185 // The x value of the requested point, in find-in-page coordinates.
186 float x = 0.0f;
187
188 // The y value of the requested point, in find-in-page coordinates.
189 float y = 0.0f;
190
191 // The distance to the nearest result found so far.
192 float nearest_distance = FLT_MAX;
193
194 // The frame containing the nearest result found so far.
195 RenderFrameHost* nearest_frame = nullptr;
196
197 // Nearest find result replies are still pending for these frames.
198 std::unordered_set<RenderFrameHost*> pending_replies;
199
200 ActivateNearestFindResultState();
201 ActivateNearestFindResultState(float x, float y);
202 ~ActivateNearestFindResultState();
203
204 static int GetNextID() {
205 static int next_id = 0;
206 return next_id++;
207 }
208 } activate_;
209
210 // Data for find match rects in a single frame.
211 struct FrameRects {
212 // The rects contained in a single frame.
213 std::vector<gfx::RectF> rects;
214
215 // The version number for these rects, as reported by their containing
216 // frame. This version is incremented independently in each frame.
217 int version = kInvalidId;
218
219 FrameRects();
220 FrameRects(const std::vector<gfx::RectF>& rects, int version);
221 ~FrameRects();
222 };
paulmeyerc0b762b2016-04-13 11:55:17223
224 // State related to FindMatchRects requests.
225 struct FindMatchRectsState {
paulmeyerc8cb7cb2016-06-07 01:14:19226 // The latest find match rects version known by the requester. This will be
227 // compared to |known_version_| after polling frames for updates to their
228 // match rects, in order to determine if the requester already has the
229 // latest version of rects or not.
paulmeyerc0b762b2016-04-13 11:55:17230 int request_version = kInvalidId;
paulmeyerc8cb7cb2016-06-07 01:14:19231
232 // The current overall find match rects version known by
233 // FindRequestManager. This version should be incremented whenever
234 // |frame_rects| is updated.
235 int known_version = 0;
236
237 // A map from each frame to its find match rects.
238 std::unordered_map<RenderFrameHost*, FrameRects> frame_rects;
239
240 // The active find match rect.
241 gfx::RectF active_rect;
242
243 // Find match rects replies are still pending for these frames.
244 std::unordered_set<RenderFrameHost*> pending_replies;
245
246 FindMatchRectsState();
247 ~FindMatchRectsState();
paulmeyerc0b762b2016-04-13 11:55:17248 } match_rects_;
249#endif
250
251 // The WebContents that owns this FindRequestManager.
252 WebContentsImpl* const contents_;
253
254 // The request ID of the initial find request in the current find-in-page
255 // session, which uniquely identifies this session. Request IDs are included
256 // in all find-related IPCs, which allows reply IPCs containing results from
257 // previous sessions (with |request_id| < |current_session_id_|) to be easily
258 // identified and ignored.
259 int current_session_id_;
260
261 // The current find request.
262 FindRequest current_request_;
263
paulmeyerbbaacbe2016-08-30 18:04:13264 // The set of frames that are still expected to reply to a pending initial
265 // find request. Frames are removed from |pending_initial_replies_| when their
266 // reply to the initial find request is received with |final_update| set to
267 // true.
268 std::unordered_set<RenderFrameHost*> pending_initial_replies_;
269
270 // The frame (if any) that is still expected to reply to the last pending
271 // "find next" request.
272 RenderFrameHost* pending_find_next_reply_;
paulmeyerc8cb7cb2016-06-07 01:14:19273
274 // Indicates whether an update to the active match ordinal is expected. Once
275 // set, |pending_active_match_ordinal_| will not reset until an update to the
276 // active match ordinal is received in response to the find request with ID
277 // |current_request_.id| (the latest request).
278 bool pending_active_match_ordinal_;
279
280 // The number of matches found in each frame. There will necessarily be
281 // entries in this map for every frame that is being (or has been) searched in
282 // the current find session, and no other frames.
283 std::unordered_map<RenderFrameHost*, int> matches_per_frame_;
284
285 // The total number of matches found in the current find-in-page session. This
286 // should always be equal to the sum of all the entries in
287 // |matches_per_frame_|.
paulmeyerc0b762b2016-04-13 11:55:17288 int number_of_matches_;
289
paulmeyerc8cb7cb2016-06-07 01:14:19290 // The frame containing the active match, if one exists, or nullptr otherwise.
291 RenderFrameHost* active_frame_;
292
293 // The active match ordinal relative to the matches found in its own frame.
294 int relative_active_match_ordinal_;
295
paulmeyerc0b762b2016-04-13 11:55:17296 // The overall active match ordinal for the current find-in-page session.
297 int active_match_ordinal_;
298
299 // The rectangle around the active match, in screen coordinates.
300 gfx::Rect selection_rect_;
paulmeyerc8cb7cb2016-06-07 01:14:19301
302 // Find requests are queued here when previous requests need to be handled
303 // before these ones can be properly routed.
304 std::queue<FindRequest> find_request_queue_;
paulmeyerbbaacbe2016-08-30 18:04:13305
306 // Keeps track of the find request ID of the last find reply reported via
307 // NotifyFindReply().
308 int last_reported_id_;
paulmeyerc0b762b2016-04-13 11:55:17309};
310
311} // namespace content
312
313#endif // CONTENT_BROWSER_FIND_REQUEST_MANAGER_H_