[M120][Tizen][Onscreen] Fix build errors for TV profile
[platform/framework/web/chromium-efl.git] / chrome / browser / font_prewarmer_tab_helper.cc
1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/font_prewarmer_tab_helper.h"
6
7 #include <set>
8 #include <string>
9
10 #include "base/memory/raw_ptr.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/values.h"
13 #include "build/build_config.h"
14 #include "chrome/browser/history/history_service_factory.h"
15 #include "chrome/browser/history_clusters/history_clusters_tab_helper.h"
16 #include "chrome/browser/preloading/prefetch/no_state_prefetch/no_state_prefetch_manager_factory.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/search_engines/template_url_service_factory.h"
19 #include "chrome/common/font_prewarmer.mojom.h"
20 #include "components/history/content/browser/history_context_helper.h"
21 #include "components/history/core/browser/history_constants.h"
22 #include "components/history/core/browser/history_service.h"
23 #include "components/no_state_prefetch/browser/no_state_prefetch_manager.h"
24 #include "components/pref_registry/pref_registry_syncable.h"
25 #include "components/prefs/pref_service.h"
26 #include "components/search_engines/template_url_service.h"
27 #include "content/public/browser/child_process_host.h"
28 #include "content/public/browser/navigation_entry.h"
29 #include "content/public/browser/navigation_handle.h"
30 #include "content/public/browser/render_frame_host.h"
31 #include "content/public/browser/render_process_host.h"
32 #include "content/public/browser/render_process_host_observer.h"
33 #include "content/public/browser/web_contents.h"
34 #include "mojo/public/cpp/bindings/remote.h"
35 #include "third_party/abseil-cpp/absl/types/optional.h"
36 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
37
38 namespace {
39
40 const char kSearchResultsPagePrimaryFontsPref[] =
41     "cached_fonts.search_results_page.primary";
42 const char kSearchResultsPageFallbackFontsPref[] =
43     "cached_fonts.search_results_page.fallback";
44
45 // Key used to associate FontPrewarmerProfileState with BrowserContext.
46 const void* const kUserDataKey = &kUserDataKey;
47
48 // Returns the font names previously stored to the specified key.
49 std::vector<std::string> GetFontNamesFromPrefsForKey(Profile* profile,
50                                                      const char* pref_name) {
51   const base::Value::List& font_name_list =
52       profile->GetPrefs()->GetList(pref_name);
53   if (font_name_list.empty())
54     return {};
55
56   std::vector<std::string> font_names;
57   for (const auto& font_name_value : font_name_list) {
58     if (const std::string* font_name = font_name_value.GetIfString())
59       font_names.push_back(*font_name);
60   }
61   return font_names;
62 }
63
64 // Saves font names to prefs.
65 void SaveFontNamesToPref(Profile* profile,
66                          const char* pref_name,
67                          const std::vector<std::string>& font_family_names) {
68   base::Value::List font_family_names_values;
69   for (auto& name : font_family_names)
70     font_family_names_values.Append(name);
71   profile->GetPrefs()->SetList(pref_name, std::move(font_family_names_values));
72 }
73
74 // FontPrewarmerCoordinator is responsible for coordinating with the renderer
75 // to request the fonts used by a page as well as prewarm the last set of fonts
76 // used. There is one FontPrewarmerCoordinator per Profile.
77 class FontPrewarmerCoordinator : public base::SupportsUserData::Data,
78                                  public content::RenderProcessHostObserver {
79  public:
80   using RemoteFontPrewarmer = mojo::Remote<chrome::mojom::FontPrewarmer>;
81
82   explicit FontPrewarmerCoordinator(Profile* profile) : profile_(profile) {}
83
84   FontPrewarmerCoordinator(const FontPrewarmerCoordinator&) = delete;
85   FontPrewarmerCoordinator& operator=(const FontPrewarmerCoordinator&) = delete;
86
87   ~FontPrewarmerCoordinator() override {
88     for (content::RenderProcessHost* rph : prewarmed_hosts_)
89       rph->RemoveObserver(this);
90   }
91
92   static FontPrewarmerCoordinator& ForProfile(Profile* profile) {
93     FontPrewarmerCoordinator* instance = static_cast<FontPrewarmerCoordinator*>(
94         profile->GetUserData(kUserDataKey));
95     if (!instance) {
96       profile->SetUserData(kUserDataKey,
97                            std::make_unique<FontPrewarmerCoordinator>(profile));
98       instance = static_cast<FontPrewarmerCoordinator*>(
99           profile->GetUserData(kUserDataKey));
100     }
101     return *instance;
102   }
103
104   // Requests the renderer to prewarm the last set of fonts used for displaying
105   // a search page. Prewarming is done at most once per RenderProcessHost.
106   void SendFontsToPrewarm(content::RenderProcessHost* rph) {
107     // Only need to prewarm a particular host once.
108     if (prewarmed_hosts_.count(rph))
109       return;
110
111     // The following code may early out. Insert the entry to ensure an early out
112     // doesn't attempt to send the fonts again.
113     prewarmed_hosts_.insert(rph);
114     rph->AddObserver(this);
115
116     std::vector<std::string> primary_font_names = GetFontNamesFromPrefsForKey(
117         profile_, kSearchResultsPagePrimaryFontsPref);
118     std::vector<std::string> fallback_font_names = GetFontNamesFromPrefsForKey(
119         profile_, kSearchResultsPageFallbackFontsPref);
120     if (primary_font_names.empty() && fallback_font_names.empty())
121       return;
122
123     RemoteFontPrewarmer remote_font_prewarmer;
124     rph->BindReceiver(remote_font_prewarmer.BindNewPipeAndPassReceiver());
125     remote_font_prewarmer->PrewarmFonts(std::move(primary_font_names),
126                                         std::move(fallback_font_names));
127   }
128
129   // Requests the set of fonts needed to display a search page from `rfh`.
130   void RequestFonts(content::RenderFrameHost* rfh) {
131     mojo::AssociatedRemote<chrome::mojom::RenderFrameFontFamilyAccessor>
132         font_family_accessor;
133     rfh->GetRemoteAssociatedInterfaces()->GetInterface(&font_family_accessor);
134     auto* font_family_accessor_raw = font_family_accessor.get();
135     // Pass ownership of the remote to the callback as otherwise the callback
136     // will never be run (because the mojo connection was destroyed).
137     font_family_accessor_raw->GetFontFamilyNames(base::BindOnce(
138         &FontPrewarmerCoordinator::OnGotFontsForFrame,
139         weak_factory_.GetWeakPtr(), std::move(font_family_accessor)));
140   }
141
142  private:
143   void OnGotFontsForFrame(
144       mojo::AssociatedRemote<chrome::mojom::RenderFrameFontFamilyAccessor>
145           font_family_accessor,
146       const std::vector<std::string>& primary_family_names,
147       const std::vector<std::string>& fallback_family_names) {
148     // TODO(sky): add some metrics here so that we know how often the
149     // fonts change.
150     SaveFontNamesToPref(profile_, kSearchResultsPagePrimaryFontsPref,
151                         primary_family_names);
152     SaveFontNamesToPref(profile_, kSearchResultsPageFallbackFontsPref,
153                         fallback_family_names);
154   }
155
156   // content::RenderProcessHostObserver:
157   void RenderProcessHostDestroyed(content::RenderProcessHost* host) override {
158     host->RemoveObserver(this);
159     prewarmed_hosts_.erase(host);
160   }
161
162   raw_ptr<Profile> profile_;
163   // Set of hosts that were requested to be prewarmed.
164   std::set<content::RenderProcessHost*> prewarmed_hosts_;
165   base::WeakPtrFactory<FontPrewarmerCoordinator> weak_factory_{this};
166 };
167
168 }  // namespace
169
170 // static
171 void FontPrewarmerTabHelper::RegisterProfilePrefs(
172     user_prefs::PrefRegistrySyncable* registry) {
173   registry->RegisterListPref(kSearchResultsPagePrimaryFontsPref);
174   registry->RegisterListPref(kSearchResultsPageFallbackFontsPref);
175 }
176
177 FontPrewarmerTabHelper::~FontPrewarmerTabHelper() = default;
178
179 FontPrewarmerTabHelper::FontPrewarmerTabHelper(
180     content::WebContents* web_contents)
181     : content::WebContentsObserver(web_contents),
182       content::WebContentsUserData<FontPrewarmerTabHelper>(*web_contents) {}
183
184 // static
185 std::string FontPrewarmerTabHelper::GetSearchResultsPagePrimaryFontsPref() {
186   return kSearchResultsPagePrimaryFontsPref;
187 }
188
189 // static
190 std::vector<std::string> FontPrewarmerTabHelper::GetPrimaryFontNames(
191     Profile* profile) {
192   return GetFontNamesFromPrefsForKey(profile,
193                                      kSearchResultsPagePrimaryFontsPref);
194 }
195
196 Profile* FontPrewarmerTabHelper::GetProfile() {
197   return Profile::FromBrowserContext(web_contents()->GetBrowserContext());
198 }
199
200 bool FontPrewarmerTabHelper::IsSearchResultsPageNavigation(
201     content::NavigationHandle* navigation_handle) {
202   if (!navigation_handle->IsInPrimaryMainFrame())
203     return false;
204
205   TemplateURLService* template_url_service =
206       TemplateURLServiceFactory::GetForProfile(GetProfile());
207   return template_url_service &&
208          template_url_service->IsSearchResultsPageFromDefaultSearchProvider(
209              navigation_handle->GetURL());
210 }
211
212 void FontPrewarmerTabHelper::DidStartNavigation(
213     content::NavigationHandle* navigation_handle) {
214   if (!IsSearchResultsPageNavigation(navigation_handle))
215     return;
216
217   const int expected_render_process_host_id =
218       navigation_handle->GetExpectedRenderProcessHostId();
219   if (expected_render_process_host_id ==
220       content::ChildProcessHost::kInvalidUniqueID) {
221     expected_render_process_host_id_.reset();
222   } else {
223     expected_render_process_host_id_ = expected_render_process_host_id;
224     content::RenderProcessHost* rph =
225         content::RenderProcessHost::FromID(expected_render_process_host_id);
226     DCHECK(rph);
227     FontPrewarmerCoordinator::ForProfile(GetProfile()).SendFontsToPrewarm(rph);
228   }
229 }
230
231 void FontPrewarmerTabHelper::ReadyToCommitNavigation(
232     content::NavigationHandle* navigation_handle) {
233   if (!IsSearchResultsPageNavigation(navigation_handle))
234     return;
235
236   content::RenderFrameHost* rfh = navigation_handle->GetRenderFrameHost();
237   DCHECK(rfh);
238   FontPrewarmerCoordinator& coordinator =
239       FontPrewarmerCoordinator::ForProfile(GetProfile());
240   if (expected_render_process_host_id_ != rfh->GetProcess()->GetID())
241     coordinator.SendFontsToPrewarm(rfh->GetProcess());
242   coordinator.RequestFonts(rfh);
243 }
244
245 WEB_CONTENTS_USER_DATA_KEY_IMPL(FontPrewarmerTabHelper);