#include "content/browser/find_request_manager.h"
#include <utility>
#include "base/containers/contains.h"
#include "base/containers/queue.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/ranges/algorithm.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "content/browser/find_in_page_client.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/common/content_client.h"
namespace content {
namespace {
std::vector<RenderFrameHostImpl*> GetChildren(RenderFrameHostImpl* rfh) { … }
RenderFrameHostImpl* GetFirstChild(RenderFrameHostImpl* rfh) { … }
RenderFrameHostImpl* GetLastChild(RenderFrameHostImpl* rfh) { … }
RenderFrameHostImpl* GetDeepestLastChild(RenderFrameHostImpl* rfh) { … }
RenderFrameHostImpl* GetAncestor(RenderFrameHostImpl* rfh) { … }
RenderFrameHostImpl* GetPreviousSibling(RenderFrameHostImpl* rfh) { … }
RenderFrameHostImpl* GetNextSibling(RenderFrameHostImpl* rfh) { … }
RenderFrameHostImpl* TraverseNext(RenderFrameHostImpl* rfh, bool wrap) { … }
RenderFrameHostImpl* TraversePrevious(RenderFrameHostImpl* rfh, bool wrap) { … }
RenderFrameHostImpl* TraverseFrame(RenderFrameHostImpl* rfh,
bool forward,
bool wrap) { … }
bool IsFindInPageDisabled(RenderFrameHost* rfh) { … }
bool IsUnattachedGuestView(RenderFrameHost* rfh) { … }
constexpr int kMinKeystrokesWithoutDelay = …;
constexpr int kDelayMs = …;
}
class FindRequestManager::FrameObserver : public WebContentsObserver { … };
bool FindRequestManager::RunDelayedFindTaskForTesting() { … }
FindRequestManager::FindRequest::FindRequest() = default;
FindRequestManager::FindRequest::FindRequest(
int id,
const std::u16string& search_text,
blink::mojom::FindOptionsPtr options)
: … { … }
FindRequestManager::FindRequest::FindRequest(const FindRequest& request)
: … { … }
FindRequestManager::FindRequest::~FindRequest() = default;
FindRequestManager::FindRequest& FindRequestManager::FindRequest::operator=(
const FindRequest& request) { … }
#if BUILDFLAG(IS_ANDROID)
FindRequestManager::ActivateNearestFindResultState::
ActivateNearestFindResultState() = default;
FindRequestManager::ActivateNearestFindResultState::
ActivateNearestFindResultState(float x, float y)
: current_request_id(GetNextID()), point(x, y) {}
FindRequestManager::ActivateNearestFindResultState::
~ActivateNearestFindResultState() = default;
FindRequestManager::FrameRects::FrameRects() = default;
FindRequestManager::FrameRects::FrameRects(const std::vector<gfx::RectF>& rects,
int version)
: rects(rects), version(version) {}
FindRequestManager::FrameRects::~FrameRects() = default;
FindRequestManager::FindMatchRectsState::FindMatchRectsState() = default;
FindRequestManager::FindMatchRectsState::~FindMatchRectsState() = default;
#endif
const int FindRequestManager::kInvalidId = …;
FindRequestManager::FindRequestManager(WebContentsImpl* web_contents)
: … { … }
FindRequestManager::~FindRequestManager() = default;
void FindRequestManager::Find(int request_id,
const std::u16string& search_text,
blink::mojom::FindOptionsPtr options,
bool skip_delay) { … }
void FindRequestManager::EmitFindRequest(int request_id,
const std::u16string& search_text,
blink::mojom::FindOptionsPtr options) { … }
void FindRequestManager::ForEachAddedFindInPageRenderFrameHost(
base::FunctionRef<void(RenderFrameHostImpl*)> func_ref) { … }
void FindRequestManager::StopFinding(StopFindAction action) { … }
bool FindRequestManager::ShouldIgnoreReply(RenderFrameHostImpl* rfh,
int request_id) { … }
void FindRequestManager::HandleFinalUpdateForFrame(RenderFrameHostImpl* rfh,
int request_id) { … }
void FindRequestManager::UpdatedFrameNumberOfMatches(RenderFrameHostImpl* rfh,
unsigned int old_count,
unsigned int new_count) { … }
void FindRequestManager::SetActiveMatchRect(
const gfx::Rect& active_match_rect) { … }
void FindRequestManager::SetActiveMatchOrdinal(RenderFrameHostImpl* rfh,
int request_id,
int active_match_ordinal) { … }
void FindRequestManager::RemoveFrame(RenderFrameHost* rfh) { … }
void FindRequestManager::ClearActiveFindMatch() { … }
#if BUILDFLAG(IS_ANDROID)
void FindRequestManager::ActivateNearestFindResult(float x, float y) {
if (current_session_id_ == kInvalidId)
return;
activate_ = ActivateNearestFindResultState(x, y);
ForEachAddedFindInPageRenderFrameHost([this](RenderFrameHostImpl* rfh) {
activate_.pending_replies.insert(rfh);
rfh->GetFindInPage()->GetNearestFindResult(
activate_.point,
base::BindOnce(&FindRequestManager::OnGetNearestFindResultReply,
base::Unretained(this), rfh,
activate_.current_request_id));
});
}
void FindRequestManager::OnGetNearestFindResultReply(RenderFrameHostImpl* rfh,
int request_id,
float distance) {
if (request_id != activate_.current_request_id ||
!base::Contains(activate_.pending_replies, rfh)) {
return;
}
if (distance < activate_.nearest_distance) {
activate_.nearest_frame = rfh;
activate_.nearest_distance = distance;
}
RemoveNearestFindResultPendingReply(rfh);
}
void FindRequestManager::RequestFindMatchRects(int current_version) {
match_rects_.pending_replies.clear();
match_rects_.request_version = current_version;
match_rects_.active_rect = gfx::RectF();
ForEachAddedFindInPageRenderFrameHost([this](RenderFrameHostImpl* rfh) {
match_rects_.pending_replies.insert(rfh);
auto it = match_rects_.frame_rects.find(rfh);
int version = (it != match_rects_.frame_rects.end()) ? it->second.version
: kInvalidId;
rfh->GetFindInPage()->FindMatchRects(
version, base::BindOnce(&FindRequestManager::OnFindMatchRectsReply,
base::Unretained(this), rfh));
});
}
void FindRequestManager::OnFindMatchRectsReply(
RenderFrameHost* rfh,
int version,
const std::vector<gfx::RectF>& rects,
const gfx::RectF& active_rect) {
auto it = match_rects_.frame_rects.find(rfh);
if (it == match_rects_.frame_rects.end() || it->second.version != version) {
match_rects_.frame_rects[rfh] = FrameRects(rects, version);
++match_rects_.known_version;
}
if (!active_rect.IsEmpty())
match_rects_.active_rect = active_rect;
RemoveFindMatchRectsPendingReply(rfh);
}
#endif
void FindRequestManager::Reset(const FindRequest& initial_request) { … }
void FindRequestManager::FindInternal(const FindRequest& request) { … }
void FindRequestManager::AdvanceQueue(int request_id) { … }
void FindRequestManager::SendFindRequest(const FindRequest& request,
RenderFrameHost* rfh) { … }
void FindRequestManager::NotifyFindReply(int request_id, bool final_update) { … }
RenderFrameHost* FindRequestManager::GetInitialFrame(bool forward) const { … }
RenderFrameHost* FindRequestManager::Traverse(RenderFrameHost* from_rfh,
bool forward,
bool matches_only,
bool wrap) const { … }
void FindRequestManager::AddFrame(RenderFrameHost* rfh, bool force) { … }
bool FindRequestManager::CheckFrame(RenderFrameHost* rfh) const { … }
void FindRequestManager::UpdateActiveMatchOrdinal() { … }
void FindRequestManager::FinalUpdateReceived(int request_id,
RenderFrameHost* rfh) { … }
std::unique_ptr<FindInPageClient> FindRequestManager::CreateFindInPageClient(
RenderFrameHostImpl* rfh) { … }
#if BUILDFLAG(IS_ANDROID)
void FindRequestManager::RemoveNearestFindResultPendingReply(
RenderFrameHost* rfh) {
auto it = activate_.pending_replies.find(rfh);
if (it == activate_.pending_replies.end())
return;
activate_.pending_replies.erase(it);
if (activate_.pending_replies.empty() &&
CheckFrame(activate_.nearest_frame)) {
const auto client_it = find_in_page_clients_.find(activate_.nearest_frame);
if (client_it != find_in_page_clients_.end())
client_it->second->ActivateNearestFindResult(current_session_id_,
activate_.point);
}
}
void FindRequestManager::RemoveFindMatchRectsPendingReply(
RenderFrameHost* rfh) {
auto it = match_rects_.pending_replies.find(rfh);
if (it == match_rects_.pending_replies.end())
return;
match_rects_.pending_replies.erase(it);
if (!match_rects_.pending_replies.empty())
return;
std::vector<gfx::RectF> aggregate_rects;
if (match_rects_.request_version != match_rects_.known_version) {
for (RenderFrameHost* frame = GetInitialFrame(true ); frame;
frame = Traverse(frame, true , true ,
false )) {
auto frame_it = match_rects_.frame_rects.find(frame);
if (frame_it == match_rects_.frame_rects.end())
continue;
std::vector<gfx::RectF>& frame_rects = frame_it->second.rects;
aggregate_rects.insert(aggregate_rects.end(), frame_rects.begin(),
frame_rects.end());
}
}
contents_->NotifyFindMatchRectsReply(
match_rects_.known_version, aggregate_rects, match_rects_.active_rect);
}
#endif
}