// Copyright 2016 The Chromium Authors. All rights reserved. // 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 #include #include #include #include #include "content/common/content_export.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/common/stop_find_action.h" #include "third_party/WebKit/public/web/WebFindOptions.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_f.h" namespace content { class RenderFrameHost; 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 CONTENT_EXPORT FindRequestManager { public: explicit FindRequestManager(WebContentsImpl* web_contents); ~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 base::string16& search_text, const blink::WebFindOptions& options); // 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); // Called when a reply is received from a frame with the results from a // find request. void OnFindReply(RenderFrameHost* rfh, int request_id, int number_of_matches, const gfx::Rect& selection_rect, int active_match_ordinal, 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); #if defined(OS_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 IPC. void OnGetNearestFindResultReply(RenderFrameHost* rfh, int nearest_find_result_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& rects, const gfx::RectF& active_rect); #endif private: // 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. base::string16 search_text; // The set of find options in effect for this find request. blink::WebFindOptions options; FindRequest() = default; FindRequest(int id, const base::string16& search_text, const blink::WebFindOptions& options) : id(id), search_text(search_text), options(options) {} }; // 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 a find IPC containing the find request |request| to the RenderFrame // associated with |rfh|. void SendFindIPC(const FindRequest& request, RenderFrameHost* rfh); // Sends the find results (as they currently are) to the WebContents. void NotifyFindReply(int request_id, bool final_update); // 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. 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); #if defined(OS_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 x value of the requested point, in find-in-page coordinates. float x = 0.0f; // The y value of the requested point, in find-in-page coordinates. float y = 0.0f; // The distance to the nearest result found so far. float nearest_distance = FLT_MAX; // The frame containing the nearest result found so far. RenderFrameHost* nearest_frame = nullptr; // Nearest find result replies are still pending for these frames. std::unordered_set pending_replies; ActivateNearestFindResultState(); ActivateNearestFindResultState(float x, float y); ~ActivateNearestFindResultState(); static int GetNextID() { static int next_id = 0; return next_id++; } } activate_; // Data for find match rects in a single frame. struct FrameRects { // The rects contained in a single frame. std::vector 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& 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 frame_rects; // The active find match rect. gfx::RectF active_rect; // Find match rects replies are still pending for these frames. std::unordered_set 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. WebContentsImpl* const 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_; // 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 pending_initial_replies_; // The frame (if any) that is still expected to reply to the last pending // "find next" request. RenderFrameHost* pending_find_next_reply_; // 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_; // The number of matches found in 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 matches_per_frame_; // 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_; // The frame containing the active match, if one exists, or nullptr otherwise. RenderFrameHost* active_frame_; // The active match ordinal relative to the matches found in its own frame. int relative_active_match_ordinal_; // The overall active match ordinal for the current find-in-page session. int active_match_ordinal_; // 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. std::queue find_request_queue_; // Keeps track of the find request ID of the last find reply reported via // NotifyFindReply(). int last_reported_id_; // WebContentsObservers to observe frame changes in |contents_| and its inner // WebContentses. std::vector> frame_observers_; DISALLOW_COPY_AND_ASSIGN(FindRequestManager); }; } // namespace content #endif // CONTENT_BROWSER_FIND_REQUEST_MANAGER_H_