| // Copyright 2013 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/search/search_ipc_router.h" |
| |
| #include <utility> |
| |
| #include "base/memory/raw_ptr.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/search/instant_service.h" |
| #include "chrome/browser/search/instant_service_factory.h" |
| #include "chrome/browser/search/search.h" |
| #include "components/search/search.h" |
| #include "content/public/browser/child_process_host.h" |
| #include "content/public/browser/navigation_details.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/render_frame_host_receiver_set.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/web_contents.h" |
| #include "mojo/public/cpp/bindings/associated_remote.h" |
| #include "mojo/public/cpp/bindings/pending_associated_receiver.h" |
| #include "mojo/public/cpp/bindings/pending_associated_remote.h" |
| #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" |
| |
| namespace { |
| |
| bool IsInInstantProcess(content::RenderFrameHost* render_frame) { |
| content::RenderProcessHost* process_host = render_frame->GetProcess(); |
| const InstantService* instant_service = InstantServiceFactory::GetForProfile( |
| Profile::FromBrowserContext(process_host->GetBrowserContext())); |
| if (!instant_service) { |
| return false; |
| } |
| |
| return instant_service->IsInstantProcess(process_host->GetDeprecatedID()); |
| } |
| |
| } // namespace |
| |
| class EmbeddedSearchClientFactoryImpl |
| : public SearchIPCRouter::EmbeddedSearchClientFactory, |
| public search::mojom::EmbeddedSearchConnector { |
| public: |
| // |web_contents| and |binding| must outlive this object. |
| EmbeddedSearchClientFactoryImpl( |
| content::WebContents* web_contents, |
| mojo::AssociatedReceiver<search::mojom::EmbeddedSearch>* receiver) |
| : client_receiver_(receiver), factory_receivers_(web_contents, this) { |
| DCHECK(web_contents); |
| DCHECK(receiver); |
| // Before we are connected to a frame we throw away all messages. |
| embedded_search_client_.reset(); |
| } |
| |
| EmbeddedSearchClientFactoryImpl(const EmbeddedSearchClientFactoryImpl&) = |
| delete; |
| EmbeddedSearchClientFactoryImpl& operator=( |
| const EmbeddedSearchClientFactoryImpl&) = delete; |
| |
| search::mojom::EmbeddedSearchClient* GetEmbeddedSearchClient() override { |
| return embedded_search_client_.is_bound() ? embedded_search_client_.get() |
| : nullptr; |
| } |
| |
| void BindFactoryReceiver(mojo::PendingAssociatedReceiver< |
| search::mojom::EmbeddedSearchConnector> receiver, |
| content::RenderFrameHost* rfh) override { |
| factory_receivers_.Bind(rfh, std::move(receiver)); |
| } |
| |
| private: |
| void Connect( |
| mojo::PendingAssociatedReceiver<search::mojom::EmbeddedSearch> receiver, |
| mojo::PendingAssociatedRemote<search::mojom::EmbeddedSearchClient> client) |
| override; |
| |
| // An interface used to push updates to the frame that connected to us. Before |
| // we've been connected to a frame, messages sent on this interface go into |
| // the void. |
| mojo::AssociatedRemote<search::mojom::EmbeddedSearchClient> |
| embedded_search_client_; |
| |
| // Used to bind incoming pending receivers to the implementation, which lives |
| // in SearchIPCRouter. |
| raw_ptr<mojo::AssociatedReceiver<search::mojom::EmbeddedSearch>> |
| client_receiver_; |
| |
| // Receivers used to listen to connection requests. |
| content::RenderFrameHostReceiverSet<search::mojom::EmbeddedSearchConnector> |
| factory_receivers_; |
| }; |
| |
| void EmbeddedSearchClientFactoryImpl::Connect( |
| mojo::PendingAssociatedReceiver<search::mojom::EmbeddedSearch> receiver, |
| mojo::PendingAssociatedRemote<search::mojom::EmbeddedSearchClient> client) { |
| content::RenderFrameHost* frame = factory_receivers_.GetCurrentTargetFrame(); |
| const bool is_main_frame = frame->GetParent() == nullptr; |
| if (!IsInInstantProcess(frame) || !is_main_frame) { |
| return; |
| } |
| client_receiver_->reset(); |
| client_receiver_->Bind(std::move(receiver)); |
| embedded_search_client_.reset(); |
| embedded_search_client_.Bind(std::move(client)); |
| } |
| |
| SearchIPCRouter::SearchIPCRouter(content::WebContents* web_contents, |
| Delegate* delegate, |
| std::unique_ptr<Policy> policy) |
| : delegate_(delegate), |
| policy_(std::move(policy)), |
| commit_counter_(0), |
| is_active_tab_(false), |
| embedded_search_client_factory_( |
| new EmbeddedSearchClientFactoryImpl(web_contents, &receiver_)) { |
| DCHECK(delegate); |
| DCHECK(policy_.get()); |
| } |
| |
| SearchIPCRouter::~SearchIPCRouter() = default; |
| |
| void SearchIPCRouter::BindEmbeddedSearchConnecter( |
| mojo::PendingAssociatedReceiver<search::mojom::EmbeddedSearchConnector> |
| receiver, |
| content::RenderFrameHost* rfh) { |
| embedded_search_client_factory_->BindFactoryReceiver(std::move(receiver), |
| rfh); |
| } |
| |
| void SearchIPCRouter::OnNavigationEntryCommitted() { |
| ++commit_counter_; |
| if (!embedded_search_client()) { |
| return; |
| } |
| embedded_search_client()->SetPageSequenceNumber(commit_counter_); |
| } |
| |
| void SearchIPCRouter::SetInputInProgress(bool input_in_progress) { |
| if (!policy_->ShouldSendSetInputInProgress(is_active_tab_) || |
| !embedded_search_client()) { |
| return; |
| } |
| |
| embedded_search_client()->SetInputInProgress(input_in_progress); |
| } |
| |
| void SearchIPCRouter::OmniboxFocusChanged(OmniboxFocusState state, |
| OmniboxFocusChangeReason reason) { |
| if (!policy_->ShouldSendOmniboxFocusChanged() || !embedded_search_client()) { |
| return; |
| } |
| |
| embedded_search_client()->FocusChanged(state, reason); |
| } |
| |
| void SearchIPCRouter::SendMostVisitedInfo( |
| const InstantMostVisitedInfo& most_visited_info) { |
| if (!policy_->ShouldSendMostVisitedInfo() || !embedded_search_client()) { |
| return; |
| } |
| |
| embedded_search_client()->MostVisitedInfoChanged(most_visited_info); |
| } |
| |
| void SearchIPCRouter::SendNtpTheme(const NtpTheme& theme) { |
| if (!policy_->ShouldSendNtpTheme() || !embedded_search_client()) { |
| return; |
| } |
| |
| embedded_search_client()->ThemeChanged(theme); |
| } |
| |
| void SearchIPCRouter::OnTabActivated() { |
| is_active_tab_ = true; |
| } |
| |
| void SearchIPCRouter::OnTabDeactivated() { |
| is_active_tab_ = false; |
| } |
| |
| void SearchIPCRouter::FocusOmnibox(int page_seq_no, bool focus) { |
| if (page_seq_no != commit_counter_) { |
| return; |
| } |
| |
| if (!policy_->ShouldProcessFocusOmnibox(is_active_tab_)) { |
| return; |
| } |
| |
| delegate_->FocusOmnibox(focus); |
| } |
| |
| void SearchIPCRouter::DeleteMostVisitedItem(int page_seq_no, const GURL& url) { |
| if (page_seq_no != commit_counter_) { |
| return; |
| } |
| |
| if (!policy_->ShouldProcessDeleteMostVisitedItem()) { |
| return; |
| } |
| |
| delegate_->OnDeleteMostVisitedItem(url); |
| } |
| |
| void SearchIPCRouter::UndoMostVisitedDeletion(int page_seq_no, |
| const GURL& url) { |
| if (page_seq_no != commit_counter_) { |
| return; |
| } |
| |
| if (!policy_->ShouldProcessUndoMostVisitedDeletion()) { |
| return; |
| } |
| |
| delegate_->OnUndoMostVisitedDeletion(url); |
| } |
| |
| void SearchIPCRouter::UndoAllMostVisitedDeletions(int page_seq_no) { |
| if (page_seq_no != commit_counter_) { |
| return; |
| } |
| |
| if (!policy_->ShouldProcessUndoAllMostVisitedDeletions()) { |
| return; |
| } |
| |
| delegate_->OnUndoAllMostVisitedDeletions(); |
| } |
| |
| void SearchIPCRouter::set_delegate_for_testing(Delegate* delegate) { |
| DCHECK(delegate); |
| delegate_ = delegate; |
| } |
| |
| void SearchIPCRouter::set_policy_for_testing(std::unique_ptr<Policy> policy) { |
| DCHECK(policy); |
| policy_ = std::move(policy); |
| } |