• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Font Settings Extension API implementation.
6 
7 #include "chrome/browser/extensions/api/font_settings/font_settings_api.h"
8 
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/json/json_writer.h"
12 #include "base/lazy_instance.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/values.h"
17 #include "chrome/browser/chrome_notification_types.h"
18 #include "chrome/browser/extensions/api/preference/preference_api.h"
19 #include "chrome/browser/extensions/api/preference/preference_helpers.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/common/extensions/api/font_settings.h"
23 #include "chrome/common/pref_names.h"
24 #include "chrome/common/pref_names_util.h"
25 #include "content/public/browser/font_list_async.h"
26 #include "content/public/browser/notification_details.h"
27 #include "content/public/browser/notification_source.h"
28 #include "extensions/browser/extension_system.h"
29 #include "extensions/common/error_utils.h"
30 
31 #if defined(OS_WIN)
32 #include "ui/gfx/font.h"
33 #include "ui/gfx/platform_font_win.h"
34 #endif
35 
36 namespace extensions {
37 
38 namespace fonts = api::font_settings;
39 
40 namespace {
41 
42 const char kFontIdKey[] = "fontId";
43 const char kGenericFamilyKey[] = "genericFamily";
44 const char kLevelOfControlKey[] = "levelOfControl";
45 const char kDisplayNameKey[] = "displayName";
46 const char kPixelSizeKey[] = "pixelSize";
47 const char kScriptKey[] = "script";
48 
49 const char kSetFromIncognitoError[] =
50     "Can't modify regular settings from an incognito context.";
51 
52 // Format for font name preference paths.
53 const char kWebKitFontPrefFormat[] = "webkit.webprefs.fonts.%s.%s";
54 
55 // Gets the font name preference path for |generic_family| and |script|. If
56 // |script| is NULL, uses prefs::kWebKitCommonScript.
GetFontNamePrefPath(fonts::GenericFamily generic_family_enum,fonts::ScriptCode script_enum)57 std::string GetFontNamePrefPath(fonts::GenericFamily generic_family_enum,
58                                 fonts::ScriptCode script_enum) {
59   std::string script = fonts::ToString(script_enum);
60   if (script.empty())
61     script = prefs::kWebKitCommonScript;
62   std::string generic_family = fonts::ToString(generic_family_enum);
63   return base::StringPrintf(kWebKitFontPrefFormat,
64                             generic_family.c_str(),
65                             script.c_str());
66 }
67 
68 // Returns the localized name of a font so that it can be matched within the
69 // list of system fonts. On Windows, the list of system fonts has names only
70 // for the system locale, but the pref value may be in the English name.
MaybeGetLocalizedFontName(const std::string & font_name)71 std::string MaybeGetLocalizedFontName(const std::string& font_name) {
72 #if defined(OS_WIN)
73   if (!font_name.empty()) {
74     gfx::Font font(font_name, 12);  // dummy font size
75     return static_cast<gfx::PlatformFontWin*>(font.platform_font())->
76         GetLocalizedFontName();
77   }
78 #endif
79   return font_name;
80 }
81 
82 // Registers |obs| to observe per-script font prefs under the path |map_name|.
RegisterFontFamilyMapObserver(PrefChangeRegistrar * registrar,const char * map_name,const PrefChangeRegistrar::NamedChangeCallback & callback)83 void RegisterFontFamilyMapObserver(
84     PrefChangeRegistrar* registrar,
85     const char* map_name,
86     const PrefChangeRegistrar::NamedChangeCallback& callback) {
87   for (size_t i = 0; i < prefs::kWebKitScriptsForFontFamilyMapsLength; ++i) {
88     const char* script = prefs::kWebKitScriptsForFontFamilyMaps[i];
89     std::string pref_name = base::StringPrintf("%s.%s", map_name, script);
90     registrar->Add(pref_name.c_str(), callback);
91   }
92 }
93 
94 }  // namespace
95 
FontSettingsEventRouter(Profile * profile)96 FontSettingsEventRouter::FontSettingsEventRouter(
97     Profile* profile) : profile_(profile) {
98   registrar_.Init(profile_->GetPrefs());
99 
100   AddPrefToObserve(prefs::kWebKitDefaultFixedFontSize,
101                    fonts::OnDefaultFixedFontSizeChanged::kEventName,
102                    kPixelSizeKey);
103   AddPrefToObserve(prefs::kWebKitDefaultFontSize,
104                    fonts::OnDefaultFontSizeChanged::kEventName,
105                    kPixelSizeKey);
106   AddPrefToObserve(prefs::kWebKitMinimumFontSize,
107                    fonts::OnMinimumFontSizeChanged::kEventName,
108                    kPixelSizeKey);
109 
110   PrefChangeRegistrar::NamedChangeCallback callback =
111       base::Bind(&FontSettingsEventRouter::OnFontFamilyMapPrefChanged,
112                  base::Unretained(this));
113   RegisterFontFamilyMapObserver(&registrar_,
114                                 prefs::kWebKitStandardFontFamilyMap, callback);
115   RegisterFontFamilyMapObserver(&registrar_,
116                                 prefs::kWebKitSerifFontFamilyMap, callback);
117   RegisterFontFamilyMapObserver(&registrar_,
118                                 prefs::kWebKitSansSerifFontFamilyMap, callback);
119   RegisterFontFamilyMapObserver(&registrar_,
120                                 prefs::kWebKitFixedFontFamilyMap, callback);
121   RegisterFontFamilyMapObserver(&registrar_,
122                                 prefs::kWebKitCursiveFontFamilyMap, callback);
123   RegisterFontFamilyMapObserver(&registrar_,
124                                 prefs::kWebKitFantasyFontFamilyMap, callback);
125   RegisterFontFamilyMapObserver(&registrar_,
126                                 prefs::kWebKitPictographFontFamilyMap,
127                                 callback);
128 }
129 
~FontSettingsEventRouter()130 FontSettingsEventRouter::~FontSettingsEventRouter() {}
131 
AddPrefToObserve(const char * pref_name,const char * event_name,const char * key)132 void FontSettingsEventRouter::AddPrefToObserve(const char* pref_name,
133                                                const char* event_name,
134                                                const char* key) {
135   registrar_.Add(pref_name,
136                  base::Bind(&FontSettingsEventRouter::OnFontPrefChanged,
137                             base::Unretained(this),
138                             event_name, key));
139 }
140 
OnFontFamilyMapPrefChanged(const std::string & pref_name)141 void FontSettingsEventRouter::OnFontFamilyMapPrefChanged(
142     const std::string& pref_name) {
143   std::string generic_family;
144   std::string script;
145   if (pref_names_util::ParseFontNamePrefPath(pref_name, &generic_family,
146                                              &script)) {
147     OnFontNamePrefChanged(pref_name, generic_family, script);
148     return;
149   }
150 
151   NOTREACHED();
152 }
153 
OnFontNamePrefChanged(const std::string & pref_name,const std::string & generic_family,const std::string & script)154 void FontSettingsEventRouter::OnFontNamePrefChanged(
155     const std::string& pref_name,
156     const std::string& generic_family,
157     const std::string& script) {
158   const PrefService::Preference* pref = registrar_.prefs()->FindPreference(
159       pref_name.c_str());
160   CHECK(pref);
161 
162   std::string font_name;
163   if (!pref->GetValue()->GetAsString(&font_name)) {
164     NOTREACHED();
165     return;
166   }
167   font_name = MaybeGetLocalizedFontName(font_name);
168 
169   base::ListValue args;
170   base::DictionaryValue* dict = new base::DictionaryValue();
171   args.Append(dict);
172   dict->SetString(kFontIdKey, font_name);
173   dict->SetString(kGenericFamilyKey, generic_family);
174   dict->SetString(kScriptKey, script);
175 
176   extensions::preference_helpers::DispatchEventToExtensions(
177       profile_,
178       fonts::OnFontChanged::kEventName,
179       &args,
180       APIPermission::kFontSettings,
181       false,
182       pref_name);
183 }
184 
OnFontPrefChanged(const std::string & event_name,const std::string & key,const std::string & pref_name)185 void FontSettingsEventRouter::OnFontPrefChanged(
186     const std::string& event_name,
187     const std::string& key,
188     const std::string& pref_name) {
189   const PrefService::Preference* pref = registrar_.prefs()->FindPreference(
190       pref_name.c_str());
191   CHECK(pref);
192 
193   base::ListValue args;
194   base::DictionaryValue* dict = new base::DictionaryValue();
195   args.Append(dict);
196   dict->Set(key, pref->GetValue()->DeepCopy());
197 
198   extensions::preference_helpers::DispatchEventToExtensions(
199       profile_,
200       event_name,
201       &args,
202       APIPermission::kFontSettings,
203       false,
204       pref_name);
205 }
206 
FontSettingsAPI(content::BrowserContext * context)207 FontSettingsAPI::FontSettingsAPI(content::BrowserContext* context)
208     : font_settings_event_router_(
209           new FontSettingsEventRouter(Profile::FromBrowserContext(context))) {}
210 
~FontSettingsAPI()211 FontSettingsAPI::~FontSettingsAPI() {
212 }
213 
214 static base::LazyInstance<BrowserContextKeyedAPIFactory<FontSettingsAPI> >
215     g_factory = LAZY_INSTANCE_INITIALIZER;
216 
217 // static
218 BrowserContextKeyedAPIFactory<FontSettingsAPI>*
GetFactoryInstance()219 FontSettingsAPI::GetFactoryInstance() {
220   return g_factory.Pointer();
221 }
222 
RunSync()223 bool FontSettingsClearFontFunction::RunSync() {
224   if (GetProfile()->IsOffTheRecord()) {
225     error_ = kSetFromIncognitoError;
226     return false;
227   }
228 
229   scoped_ptr<fonts::ClearFont::Params> params(
230       fonts::ClearFont::Params::Create(*args_));
231   EXTENSION_FUNCTION_VALIDATE(params.get());
232 
233   std::string pref_path = GetFontNamePrefPath(params->details.generic_family,
234                                               params->details.script);
235 
236   // Ensure |pref_path| really is for a registered per-script font pref.
237   EXTENSION_FUNCTION_VALIDATE(
238       GetProfile()->GetPrefs()->FindPreference(pref_path.c_str()));
239 
240   PreferenceAPI::Get(GetProfile())->RemoveExtensionControlledPref(
241       extension_id(), pref_path.c_str(), kExtensionPrefsScopeRegular);
242   return true;
243 }
244 
RunSync()245 bool FontSettingsGetFontFunction::RunSync() {
246   scoped_ptr<fonts::GetFont::Params> params(
247       fonts::GetFont::Params::Create(*args_));
248   EXTENSION_FUNCTION_VALIDATE(params.get());
249 
250   std::string pref_path = GetFontNamePrefPath(params->details.generic_family,
251                                               params->details.script);
252 
253   PrefService* prefs = GetProfile()->GetPrefs();
254   const PrefService::Preference* pref =
255       prefs->FindPreference(pref_path.c_str());
256 
257   std::string font_name;
258   EXTENSION_FUNCTION_VALIDATE(
259       pref && pref->GetValue()->GetAsString(&font_name));
260   font_name = MaybeGetLocalizedFontName(font_name);
261 
262   // We don't support incognito-specific font prefs, so don't consider them when
263   // getting level of control.
264   const bool kIncognito = false;
265   std::string level_of_control =
266       extensions::preference_helpers::GetLevelOfControl(
267           GetProfile(), extension_id(), pref_path, kIncognito);
268 
269   base::DictionaryValue* result = new base::DictionaryValue();
270   result->SetString(kFontIdKey, font_name);
271   result->SetString(kLevelOfControlKey, level_of_control);
272   SetResult(result);
273   return true;
274 }
275 
RunSync()276 bool FontSettingsSetFontFunction::RunSync() {
277   if (GetProfile()->IsOffTheRecord()) {
278     error_ = kSetFromIncognitoError;
279     return false;
280   }
281 
282   scoped_ptr<fonts::SetFont::Params> params(
283       fonts::SetFont::Params::Create(*args_));
284   EXTENSION_FUNCTION_VALIDATE(params.get());
285 
286   std::string pref_path = GetFontNamePrefPath(params->details.generic_family,
287                                               params->details.script);
288 
289   // Ensure |pref_path| really is for a registered font pref.
290   EXTENSION_FUNCTION_VALIDATE(
291       GetProfile()->GetPrefs()->FindPreference(pref_path.c_str()));
292 
293   PreferenceAPI::Get(GetProfile())->SetExtensionControlledPref(
294       extension_id(),
295       pref_path.c_str(),
296       kExtensionPrefsScopeRegular,
297       new base::StringValue(params->details.font_id));
298   return true;
299 }
300 
RunAsync()301 bool FontSettingsGetFontListFunction::RunAsync() {
302   content::GetFontListAsync(
303       Bind(&FontSettingsGetFontListFunction::FontListHasLoaded, this));
304   return true;
305 }
306 
FontListHasLoaded(scoped_ptr<base::ListValue> list)307 void FontSettingsGetFontListFunction::FontListHasLoaded(
308     scoped_ptr<base::ListValue> list) {
309   bool success = CopyFontsToResult(list.get());
310   SendResponse(success);
311 }
312 
CopyFontsToResult(base::ListValue * fonts)313 bool FontSettingsGetFontListFunction::CopyFontsToResult(
314     base::ListValue* fonts) {
315   scoped_ptr<base::ListValue> result(new base::ListValue());
316   for (base::ListValue::iterator it = fonts->begin();
317        it != fonts->end(); ++it) {
318     base::ListValue* font_list_value;
319     if (!(*it)->GetAsList(&font_list_value)) {
320       NOTREACHED();
321       return false;
322     }
323 
324     std::string name;
325     if (!font_list_value->GetString(0, &name)) {
326       NOTREACHED();
327       return false;
328     }
329 
330     std::string localized_name;
331     if (!font_list_value->GetString(1, &localized_name)) {
332       NOTREACHED();
333       return false;
334     }
335 
336     base::DictionaryValue* font_name = new base::DictionaryValue();
337     font_name->Set(kFontIdKey, new base::StringValue(name));
338     font_name->Set(kDisplayNameKey, new base::StringValue(localized_name));
339     result->Append(font_name);
340   }
341 
342   SetResult(result.release());
343   return true;
344 }
345 
RunSync()346 bool ClearFontPrefExtensionFunction::RunSync() {
347   if (GetProfile()->IsOffTheRecord()) {
348     error_ = kSetFromIncognitoError;
349     return false;
350   }
351 
352   PreferenceAPI::Get(GetProfile())->RemoveExtensionControlledPref(
353       extension_id(), GetPrefName(), kExtensionPrefsScopeRegular);
354   return true;
355 }
356 
RunSync()357 bool GetFontPrefExtensionFunction::RunSync() {
358   PrefService* prefs = GetProfile()->GetPrefs();
359   const PrefService::Preference* pref = prefs->FindPreference(GetPrefName());
360   EXTENSION_FUNCTION_VALIDATE(pref);
361 
362   // We don't support incognito-specific font prefs, so don't consider them when
363   // getting level of control.
364   const bool kIncognito = false;
365 
366   std::string level_of_control =
367       extensions::preference_helpers::GetLevelOfControl(
368           GetProfile(), extension_id(), GetPrefName(), kIncognito);
369 
370   base::DictionaryValue* result = new base::DictionaryValue();
371   result->Set(GetKey(), pref->GetValue()->DeepCopy());
372   result->SetString(kLevelOfControlKey, level_of_control);
373   SetResult(result);
374   return true;
375 }
376 
RunSync()377 bool SetFontPrefExtensionFunction::RunSync() {
378   if (GetProfile()->IsOffTheRecord()) {
379     error_ = kSetFromIncognitoError;
380     return false;
381   }
382 
383   base::DictionaryValue* details = NULL;
384   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details));
385 
386   base::Value* value;
387   EXTENSION_FUNCTION_VALIDATE(details->Get(GetKey(), &value));
388 
389   PreferenceAPI::Get(GetProfile())
390       ->SetExtensionControlledPref(extension_id(),
391                                    GetPrefName(),
392                                    kExtensionPrefsScopeRegular,
393                                    value->DeepCopy());
394   return true;
395 }
396 
GetPrefName()397 const char* FontSettingsClearDefaultFontSizeFunction::GetPrefName() {
398   return prefs::kWebKitDefaultFontSize;
399 }
400 
GetPrefName()401 const char* FontSettingsGetDefaultFontSizeFunction::GetPrefName() {
402   return prefs::kWebKitDefaultFontSize;
403 }
404 
GetKey()405 const char* FontSettingsGetDefaultFontSizeFunction::GetKey() {
406   return kPixelSizeKey;
407 }
408 
GetPrefName()409 const char* FontSettingsSetDefaultFontSizeFunction::GetPrefName() {
410   return prefs::kWebKitDefaultFontSize;
411 }
412 
GetKey()413 const char* FontSettingsSetDefaultFontSizeFunction::GetKey() {
414   return kPixelSizeKey;
415 }
416 
GetPrefName()417 const char* FontSettingsClearDefaultFixedFontSizeFunction::GetPrefName() {
418   return prefs::kWebKitDefaultFixedFontSize;
419 }
420 
GetPrefName()421 const char* FontSettingsGetDefaultFixedFontSizeFunction::GetPrefName() {
422   return prefs::kWebKitDefaultFixedFontSize;
423 }
424 
GetKey()425 const char* FontSettingsGetDefaultFixedFontSizeFunction::GetKey() {
426   return kPixelSizeKey;
427 }
428 
GetPrefName()429 const char* FontSettingsSetDefaultFixedFontSizeFunction::GetPrefName() {
430   return prefs::kWebKitDefaultFixedFontSize;
431 }
432 
GetKey()433 const char* FontSettingsSetDefaultFixedFontSizeFunction::GetKey() {
434   return kPixelSizeKey;
435 }
436 
GetPrefName()437 const char* FontSettingsClearMinimumFontSizeFunction::GetPrefName() {
438   return prefs::kWebKitMinimumFontSize;
439 }
440 
GetPrefName()441 const char* FontSettingsGetMinimumFontSizeFunction::GetPrefName() {
442   return prefs::kWebKitMinimumFontSize;
443 }
444 
GetKey()445 const char* FontSettingsGetMinimumFontSizeFunction::GetKey() {
446   return kPixelSizeKey;
447 }
448 
GetPrefName()449 const char* FontSettingsSetMinimumFontSizeFunction::GetPrefName() {
450   return prefs::kWebKitMinimumFontSize;
451 }
452 
GetKey()453 const char* FontSettingsSetMinimumFontSizeFunction::GetKey() {
454   return kPixelSizeKey;
455 }
456 
457 }  // namespace extensions
458