123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- // Copyright 2021 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.
- #include "chrome/browser/font_prewarmer_tab_helper.h"
- #include <set>
- #include <string>
- #include "base/memory/raw_ptr.h"
- #include "base/memory/weak_ptr.h"
- #include "base/values.h"
- #include "build/build_config.h"
- #include "chrome/browser/history/history_service_factory.h"
- #include "chrome/browser/history_clusters/history_clusters_tab_helper.h"
- #include "chrome/browser/preloading/prefetch/no_state_prefetch/no_state_prefetch_manager_factory.h"
- #include "chrome/browser/profiles/profile.h"
- #include "chrome/browser/search_engines/template_url_service_factory.h"
- #include "chrome/common/font_prewarmer.mojom.h"
- #include "components/history/content/browser/history_context_helper.h"
- #include "components/history/core/browser/history_constants.h"
- #include "components/history/core/browser/history_service.h"
- #include "components/no_state_prefetch/browser/no_state_prefetch_manager.h"
- #include "components/pref_registry/pref_registry_syncable.h"
- #include "components/prefs/pref_service.h"
- #include "components/search_engines/template_url_service.h"
- #include "content/public/browser/navigation_entry.h"
- #include "content/public/browser/navigation_handle.h"
- #include "content/public/browser/render_frame_host.h"
- #include "content/public/browser/render_process_host.h"
- #include "content/public/browser/render_process_host_observer.h"
- #include "content/public/browser/web_contents.h"
- #include "content/public/common/child_process_host.h"
- #include "mojo/public/cpp/bindings/remote.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
- namespace {
- const char kSearchResultsPagePrimaryFontsPref[] =
- "cached_fonts.search_results_page.primary";
- const char kSearchResultsPageFallbackFontsPref[] =
- "cached_fonts.search_results_page.fallback";
- // Key used to associate FontPrewarmerProfileState with BrowserContext.
- const void* const kUserDataKey = &kUserDataKey;
- // Returns the font names previously stored to the specified key.
- std::vector<std::string> GetFontNamesFromPrefsForKey(Profile* profile,
- const char* pref_name) {
- const base::Value::List& font_name_list =
- profile->GetPrefs()->GetValueList(pref_name);
- if (font_name_list.empty())
- return {};
- std::vector<std::string> font_names;
- for (const auto& font_name_value : font_name_list) {
- if (const std::string* font_name = font_name_value.GetIfString())
- font_names.push_back(*font_name);
- }
- return font_names;
- }
- // Saves font names to prefs.
- void SaveFontNamesToPref(Profile* profile,
- const char* pref_name,
- const std::vector<std::string>& font_family_names) {
- base::Value::List font_family_names_values;
- for (auto& name : font_family_names)
- font_family_names_values.Append(name);
- profile->GetPrefs()->SetList(pref_name, std::move(font_family_names_values));
- }
- // FontPrewarmerCoordinator is responsible for coordinating with the renderer
- // to request the fonts used by a page as well as prewarm the last set of fonts
- // used. There is one FontPrewarmerCoordinator per Profile.
- class FontPrewarmerCoordinator : public base::SupportsUserData::Data,
- public content::RenderProcessHostObserver {
- public:
- using RemoteFontPrewarmer = mojo::Remote<chrome::mojom::FontPrewarmer>;
- explicit FontPrewarmerCoordinator(Profile* profile) : profile_(profile) {}
- FontPrewarmerCoordinator(const FontPrewarmerCoordinator&) = delete;
- FontPrewarmerCoordinator& operator=(const FontPrewarmerCoordinator&) = delete;
- ~FontPrewarmerCoordinator() override {
- for (content::RenderProcessHost* rph : prewarmed_hosts_)
- rph->RemoveObserver(this);
- }
- static FontPrewarmerCoordinator& ForProfile(Profile* profile) {
- FontPrewarmerCoordinator* instance = static_cast<FontPrewarmerCoordinator*>(
- profile->GetUserData(kUserDataKey));
- if (!instance) {
- profile->SetUserData(kUserDataKey,
- std::make_unique<FontPrewarmerCoordinator>(profile));
- instance = static_cast<FontPrewarmerCoordinator*>(
- profile->GetUserData(kUserDataKey));
- }
- return *instance;
- }
- // Requests the renderer to prewarm the last set of fonts used for displaying
- // a search page. Prewarming is done at most once per RenderProcessHost.
- void SendFontsToPrewarm(content::RenderProcessHost* rph) {
- // Only need to prewarm a particular host once.
- if (prewarmed_hosts_.count(rph))
- return;
- // The following code may early out. Insert the entry to ensure an early out
- // doesn't attempt to send the fonts again.
- prewarmed_hosts_.insert(rph);
- rph->AddObserver(this);
- std::vector<std::string> primary_font_names = GetFontNamesFromPrefsForKey(
- profile_, kSearchResultsPagePrimaryFontsPref);
- std::vector<std::string> fallback_font_names = GetFontNamesFromPrefsForKey(
- profile_, kSearchResultsPageFallbackFontsPref);
- if (primary_font_names.empty() && fallback_font_names.empty())
- return;
- RemoteFontPrewarmer remote_font_prewarmer;
- rph->BindReceiver(remote_font_prewarmer.BindNewPipeAndPassReceiver());
- remote_font_prewarmer->PrewarmFonts(std::move(primary_font_names),
- std::move(fallback_font_names));
- }
- // Requests the set of fonts needed to display a search page from `rfh`.
- void RequestFonts(content::RenderFrameHost* rfh) {
- mojo::AssociatedRemote<chrome::mojom::RenderFrameFontFamilyAccessor>
- font_family_accessor;
- rfh->GetRemoteAssociatedInterfaces()->GetInterface(&font_family_accessor);
- auto* font_family_accessor_raw = font_family_accessor.get();
- // Pass ownership of the remote to the callback as otherwise the callback
- // will never be run (because the mojo connection was destroyed).
- font_family_accessor_raw->GetFontFamilyNames(base::BindOnce(
- &FontPrewarmerCoordinator::OnGotFontsForFrame,
- weak_factory_.GetWeakPtr(), std::move(font_family_accessor)));
- }
- private:
- void OnGotFontsForFrame(
- mojo::AssociatedRemote<chrome::mojom::RenderFrameFontFamilyAccessor>
- font_family_accessor,
- const std::vector<std::string>& primary_family_names,
- const std::vector<std::string>& fallback_family_names) {
- // TODO(sky): add some metrics here so that we know how often the
- // fonts change.
- SaveFontNamesToPref(profile_, kSearchResultsPagePrimaryFontsPref,
- primary_family_names);
- SaveFontNamesToPref(profile_, kSearchResultsPageFallbackFontsPref,
- fallback_family_names);
- }
- // content::RenderProcessHostObserver:
- void RenderProcessHostDestroyed(content::RenderProcessHost* host) override {
- host->RemoveObserver(this);
- prewarmed_hosts_.erase(host);
- }
- raw_ptr<Profile> profile_;
- // Set of hosts that were requested to be prewarmed.
- std::set<content::RenderProcessHost*> prewarmed_hosts_;
- base::WeakPtrFactory<FontPrewarmerCoordinator> weak_factory_{this};
- };
- } // namespace
- // static
- void FontPrewarmerTabHelper::RegisterProfilePrefs(
- user_prefs::PrefRegistrySyncable* registry) {
- registry->RegisterListPref(kSearchResultsPagePrimaryFontsPref);
- registry->RegisterListPref(kSearchResultsPageFallbackFontsPref);
- }
- FontPrewarmerTabHelper::~FontPrewarmerTabHelper() = default;
- FontPrewarmerTabHelper::FontPrewarmerTabHelper(
- content::WebContents* web_contents)
- : content::WebContentsObserver(web_contents),
- content::WebContentsUserData<FontPrewarmerTabHelper>(*web_contents) {}
- // static
- std::string FontPrewarmerTabHelper::GetSearchResultsPagePrimaryFontsPref() {
- return kSearchResultsPagePrimaryFontsPref;
- }
- // static
- std::vector<std::string> FontPrewarmerTabHelper::GetPrimaryFontNames(
- Profile* profile) {
- return GetFontNamesFromPrefsForKey(profile,
- kSearchResultsPagePrimaryFontsPref);
- }
- Profile* FontPrewarmerTabHelper::GetProfile() {
- return Profile::FromBrowserContext(web_contents()->GetBrowserContext());
- }
- bool FontPrewarmerTabHelper::IsSearchResultsPageNavigation(
- content::NavigationHandle* navigation_handle) {
- if (!navigation_handle->IsInPrimaryMainFrame())
- return false;
- TemplateURLService* template_url_service =
- TemplateURLServiceFactory::GetForProfile(GetProfile());
- return template_url_service &&
- template_url_service->IsSearchResultsPageFromDefaultSearchProvider(
- navigation_handle->GetURL());
- }
- void FontPrewarmerTabHelper::DidStartNavigation(
- content::NavigationHandle* navigation_handle) {
- if (!IsSearchResultsPageNavigation(navigation_handle))
- return;
- const int expected_render_process_host_id =
- navigation_handle->GetExpectedRenderProcessHostId();
- if (expected_render_process_host_id ==
- content::ChildProcessHost::kInvalidUniqueID) {
- expected_render_process_host_id_.reset();
- } else {
- expected_render_process_host_id_ = expected_render_process_host_id;
- content::RenderProcessHost* rph =
- content::RenderProcessHost::FromID(expected_render_process_host_id);
- DCHECK(rph);
- FontPrewarmerCoordinator::ForProfile(GetProfile()).SendFontsToPrewarm(rph);
- }
- }
- void FontPrewarmerTabHelper::ReadyToCommitNavigation(
- content::NavigationHandle* navigation_handle) {
- if (!IsSearchResultsPageNavigation(navigation_handle))
- return;
- content::RenderFrameHost* rfh = navigation_handle->GetRenderFrameHost();
- DCHECK(rfh);
- FontPrewarmerCoordinator& coordinator =
- FontPrewarmerCoordinator::ForProfile(GetProfile());
- if (expected_render_process_host_id_ != rfh->GetProcess()->GetID())
- coordinator.SendFontsToPrewarm(rfh->GetProcess());
- coordinator.RequestFonts(rfh);
- }
- WEB_CONTENTS_USER_DATA_KEY_IMPL(FontPrewarmerTabHelper);
|