1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
|
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_FIND_REQUEST_MANAGER_H_
#define CONTENT_BROWSER_FIND_REQUEST_MANAGER_H_
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "base/cancelable_callback.h"
#include "base/containers/queue.h"
#include "base/functional/function_ref.h"
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/stop_find_action.h"
#include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
namespace content {
class FindInPageClient;
class RenderFrameHost;
class RenderFrameHostImpl;
class WebContentsImpl;
// FindRequestManager manages all of the find-in-page requests/replies
// initiated/received through a WebContents. It coordinates searching across
// multiple (potentially out-of-process) frames, handles the aggregation of find
// results from each frame, and facilitates active match traversal. It is
// instantiated once per top-level WebContents, and is owned by that
// WebContents.
class FindRequestManager {
public:
explicit FindRequestManager(WebContentsImpl* web_contents);
FindRequestManager(const FindRequestManager&) = delete;
FindRequestManager& operator=(const FindRequestManager&) = delete;
~FindRequestManager();
// Initiates a find operation for |search_text| with the options specified in
// |options|. |request_id| uniquely identifies the find request.
void Find(int request_id,
const std::u16string& search_text,
blink::mojom::FindOptionsPtr options,
bool skip_delay = false);
// Stops the active find session and clears the general highlighting of the
// matches. |action| determines whether the last active match (if any) will be
// activated, cleared, or remain highlighted.
void StopFinding(StopFindAction action);
// Handles the final update from |rfh| for the find request with id
// |request_id|.
void HandleFinalUpdateForFrame(RenderFrameHostImpl* rfh, int request_id);
// The number of matches on |rfh| has changed from |old_count| to |new_count|.
// This method updates the total number of matches and also updates
// |active_match_ordinal_| accordingly.
void UpdatedFrameNumberOfMatches(RenderFrameHostImpl* rfh,
unsigned int old_count,
unsigned int new_count);
bool ShouldIgnoreReply(RenderFrameHostImpl* rfh, int request_id);
void SetActiveMatchRect(const gfx::Rect& active_match_rect);
void SetActiveMatchOrdinal(RenderFrameHostImpl* rfh,
int request_id,
int active_match_ordinal);
// Sends the find results (as they currently are) to the WebContents.
// |final_update| is true if we have received all of the updates from
// every frame for this request.
void NotifyFindReply(int request_id, bool final_update);
// Removes a frame from the set of frames being searched. This should be
// called whenever a frame is discovered to no longer exist.
void RemoveFrame(RenderFrameHost* rfh);
// Tells active frame to clear the active match highlighting.
void ClearActiveFindMatch();
// Runs the delayed find task if present. Returns true if there was a task
// which got run. Returns false if there was no delayed task.
bool CONTENT_EXPORT RunDelayedFindTaskForTesting();
#if BUILDFLAG(IS_ANDROID)
// Selects and zooms to the find result nearest to the point (x, y), defined
// in find-in-page coordinates.
void ActivateNearestFindResult(float x, float y);
// Called when a reply is received from a frame in response to the
// GetNearestFindResult mojo call.
void OnGetNearestFindResultReply(RenderFrameHostImpl* rfh,
int request_id,
float distance);
// Requests the rects of the current find matches from the renderer process.
void RequestFindMatchRects(int current_version);
// Called when a reply is received from a frame in response to a request for
// find match rects.
void OnFindMatchRectsReply(RenderFrameHost* rfh,
int version,
const std::vector<gfx::RectF>& rects,
const gfx::RectF& active_rect);
#endif
const std::unordered_set<raw_ptr<RenderFrameHost, CtnExperimental>>
render_frame_hosts_pending_initial_reply_for_testing() const {
return pending_initial_replies_;
}
gfx::Rect GetSelectionRectForTesting() { return selection_rect_; }
using CreateFindInPageClientFunction = std::unique_ptr<FindInPageClient> (*)(
FindRequestManager* find_request_manager,
RenderFrameHostImpl* rfh);
void SetCreateFindInPageClientFunctionForTesting(
CreateFindInPageClientFunction create_func) {
create_find_in_page_client_for_testing_ = create_func;
}
private:
friend class FindRequestManagerFencedFrameTest;
// An invalid ID. This value is invalid for any render process ID, render
// frame ID, find request ID, or find match rects version number.
static const int kInvalidId;
class FrameObserver;
// The request data for a single find request.
struct FindRequest {
// The find request ID that uniquely identifies this find request.
int id = kInvalidId;
// The text that is being searched for in this find request.
std::u16string search_text;
// The set of find options in effect for this find request.
blink::mojom::FindOptionsPtr options;
FindRequest();
FindRequest(int id,
const std::u16string& search_text,
blink::mojom::FindOptionsPtr options);
FindRequest(const FindRequest& request);
~FindRequest();
FindRequest& operator=(const FindRequest& request);
};
// Resets all of the per-session state for a new find-in-page session.
void Reset(const FindRequest& initial_request);
// Called internally as find requests come up in the queue.
void FindInternal(const FindRequest& request);
// Called when an informative response (a response with enough information to
// be able to route subsequent find requests) comes in for the find request
// with ID |request_id|. Advances the |find_request_queue_| if appropriate.
void AdvanceQueue(int request_id);
// Sends find request |request| through mojo to the RenderFrame associated
// with |rfh|.
void SendFindRequest(const FindRequest& request, RenderFrameHost* rfh);
// Returns the initial frame in search order. This will be either the first
// frame, if searching forward, or the last frame, if searching backward.
RenderFrameHost* GetInitialFrame(bool forward) const;
// Traverses the frame tree to find and return the next RenderFrameHost after
// |from_rfh| in search order. |forward| indicates whether the frame tree
// should be traversed forward (if true) or backward (if false). If
// |matches_only| is set, then the frame tree will be traversed until the
// first frame is found for which matches have been found. If |wrap| is set,
// then the traversal can wrap around past the last frame to the first one (or
// vice-versa, if |forward| == false). If no frame can be found under these
// conditions, nullptr is returned.
RenderFrameHost* Traverse(RenderFrameHost* from_rfh,
bool forward,
bool matches_only,
bool wrap) const;
// Adds a frame to the set of frames that are being searched. The new frame
// will automatically be searched when added, using the same options (stored
// in |current_request_.options|). |force| should be set to true when a
// dynamic content change is suspected, which will treat the frame as a newly
// added frame even if it has already been searched. This will force a
// re-search of the frame.
void AddFrame(RenderFrameHost* rfh, bool force);
// Returns whether |rfh| is in the set of frames being searched in the current
// find session.
CONTENT_EXPORT bool CheckFrame(RenderFrameHost* rfh) const;
// Computes and updates |active_match_ordinal_| based on |active_frame_| and
// |relative_active_match_ordinal_|.
void UpdateActiveMatchOrdinal();
// Called when all pending find replies have been received for the find
// request with ID |request_id|. The final update was received from |rfh|.
//
// Note that this is the final update for this particular find request, but
// not necessarily for all issued requests. If there are still pending replies
// expected for a previous find request, then the outgoing find reply issued
// from this function will not be marked final.
void FinalUpdateReceived(int request_id, RenderFrameHost* rfh);
std::unique_ptr<FindInPageClient> CreateFindInPageClient(
RenderFrameHostImpl* rfh);
// Traverses all RenderFrameHosts added for find-in-page and invokes the
// callback if the each RenderFrameHost is alive and active.
void ForEachAddedFindInPageRenderFrameHost(
base::FunctionRef<void(RenderFrameHostImpl*)> func_ref);
void EmitFindRequest(int request_id,
const std::u16string& search_text,
blink::mojom::FindOptionsPtr options);
#if BUILDFLAG(IS_ANDROID)
// Called when a nearest find result reply is no longer pending for a frame.
void RemoveNearestFindResultPendingReply(RenderFrameHost* rfh);
// Called when a find match rects reply is no longer pending for a frame.
void RemoveFindMatchRectsPendingReply(RenderFrameHost* rfh);
// State related to ActivateNearestFindResult requests.
struct ActivateNearestFindResultState {
// An ID to uniquely identify the current nearest find result request and
// its replies.
int current_request_id = kInvalidId;
// The value of the requested point, in find-in-page coordinates.
gfx::PointF point = gfx::PointF(0.0f, 0.0f);
float nearest_distance = FLT_MAX;
// The frame containing the nearest result found so far.
raw_ptr<RenderFrameHostImpl> nearest_frame = nullptr;
// Nearest find result replies are still pending for these frames.
std::unordered_set<raw_ptr<RenderFrameHost, CtnExperimental>>
pending_replies;
ActivateNearestFindResultState();
ActivateNearestFindResultState(float x, float y);
~ActivateNearestFindResultState();
static int GetNextID();
} activate_;
// Data for find match rects in a single frame.
struct FrameRects {
// The rects contained in a single frame.
std::vector<gfx::RectF> rects;
// The version number for these rects, as reported by their containing
// frame. This version is incremented independently in each frame.
int version = kInvalidId;
FrameRects();
FrameRects(const std::vector<gfx::RectF>& rects, int version);
~FrameRects();
};
// State related to FindMatchRects requests.
struct FindMatchRectsState {
// The latest find match rects version known by the requester. This will be
// compared to |known_version_| after polling frames for updates to their
// match rects, in order to determine if the requester already has the
// latest version of rects or not.
int request_version = kInvalidId;
// The current overall find match rects version known by
// FindRequestManager. This version should be incremented whenever
// |frame_rects| is updated.
int known_version = 0;
// A map from each frame to its find match rects.
std::unordered_map<RenderFrameHost*, FrameRects> frame_rects;
// The active find match rect.
gfx::RectF active_rect;
// Find match rects replies are still pending for these frames.
std::unordered_set<raw_ptr<RenderFrameHost, CtnExperimental>>
pending_replies;
FindMatchRectsState();
~FindMatchRectsState();
} match_rects_;
#endif
// The WebContents that owns this FindRequestManager. This also defines the
// scope of all find sessions. Only frames in |contents_| and any inner
// WebContentses within it will be searched.
const raw_ptr<WebContentsImpl> contents_;
// The request ID of the initial find request in the current find-in-page
// session, which uniquely identifies this session. Request IDs are included
// in all find-related IPCs, which allows reply IPCs containing results from
// previous sessions (with |request_id| < |current_session_id_|) to be easily
// identified and ignored.
int current_session_id_ = kInvalidId;
// The current find request.
FindRequest current_request_;
// The set of frames that are still expected to reply to a pending initial
// find request. Frames are removed from |pending_initial_replies_| when their
// reply to the initial find request is received with |final_update| set to
// true.
std::unordered_set<raw_ptr<RenderFrameHost, CtnExperimental>>
pending_initial_replies_;
// The frame (if any) that is still expected to reply to the last pending
// "find next" request.
raw_ptr<RenderFrameHost> pending_find_next_reply_ = nullptr;
// Indicates whether an update to the active match ordinal is expected. Once
// set, |pending_active_match_ordinal_| will not reset until an update to the
// active match ordinal is received in response to the find request with ID
// |current_request_.id| (the latest request).
bool pending_active_match_ordinal_ = false;
// The FindInPageClient associated with each frame. There will necessarily be
// entries in this map for every frame that is being (or has been) searched in
// the current find session, and no other frames.
std::unordered_map<RenderFrameHost*, std::unique_ptr<FindInPageClient>>
find_in_page_clients_;
// The total number of matches found in the current find-in-page session. This
// should always be equal to the sum of all the entries in
// |matches_per_frame_|.
int number_of_matches_ = 0;
// The frame containing the active match, if one exists, or nullptr otherwise.
raw_ptr<RenderFrameHostImpl> active_frame_ = nullptr;
// The active match ordinal relative to the matches found in its own frame.
int relative_active_match_ordinal_ = 0;
// The overall active match ordinal for the current find-in-page session.
int active_match_ordinal_ = 0;
// The rectangle around the active match, in screen coordinates.
gfx::Rect selection_rect_;
// Find requests are queued here when previous requests need to be handled
// before these ones can be properly routed.
base::queue<FindRequest> find_request_queue_;
// Keeps track of the find request ID of the last find reply reported via
// NotifyFindReply().
int last_reported_id_ = kInvalidId;
// WebContentsObservers to observe frame changes in |contents_| and its inner
// WebContentses.
std::vector<std::unique_ptr<FrameObserver>> frame_observers_;
base::CancelableOnceClosure delayed_find_task_;
CreateFindInPageClientFunction create_find_in_page_client_for_testing_ =
nullptr;
base::WeakPtrFactory<FindRequestManager> weak_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_FIND_REQUEST_MANAGER_H_
|