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.
5 // Font Settings Extension API implementation.
7 #include "chrome/browser/extensions/api/font_settings/font_settings_api.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"
32 #include "ui/gfx/font.h"
33 #include "ui/gfx/platform_font_win.h"
36 namespace extensions {
38 namespace fonts = api::font_settings;
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";
49 const char kSetFromIncognitoError[] =
50 "Can't modify regular settings from an incognito context.";
52 // Format for font name preference paths.
53 const char kWebKitFontPrefFormat[] = "webkit.webprefs.fonts.%s.%s";
55 // Gets the font name preference path for |generic_family| and |script|. If
56 // |script| is NULL, uses prefs::kWebKitCommonScript.
57 std::string GetFontNamePrefPath(fonts::GenericFamily generic_family_enum,
58 fonts::ScriptCode script_enum) {
59 std::string script = fonts::ToString(script_enum);
61 script = prefs::kWebKitCommonScript;
62 std::string generic_family = fonts::ToString(generic_family_enum);
63 return base::StringPrintf(kWebKitFontPrefFormat,
64 generic_family.c_str(),
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.
71 std::string MaybeGetLocalizedFontName(const std::string& font_name) {
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();
82 // Registers |obs| to observe per-script font prefs under the path |map_name|.
83 void RegisterFontFamilyMapObserver(
84 PrefChangeRegistrar* registrar,
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);
96 FontSettingsEventRouter::FontSettingsEventRouter(
97 Profile* profile) : profile_(profile) {
98 registrar_.Init(profile_->GetPrefs());
100 AddPrefToObserve(prefs::kWebKitDefaultFixedFontSize,
101 fonts::OnDefaultFixedFontSizeChanged::kEventName,
103 AddPrefToObserve(prefs::kWebKitDefaultFontSize,
104 fonts::OnDefaultFontSizeChanged::kEventName,
106 AddPrefToObserve(prefs::kWebKitMinimumFontSize,
107 fonts::OnMinimumFontSizeChanged::kEventName,
110 PrefChangeRegistrar::NamedChangeCallback callback =
111 base::Bind(&FontSettingsEventRouter::OnFontFamilyMapPrefChanged,
112 base::Unretained(this));
113 RegisterFontFamilyMapObserver(®istrar_,
114 prefs::kWebKitStandardFontFamilyMap, callback);
115 RegisterFontFamilyMapObserver(®istrar_,
116 prefs::kWebKitSerifFontFamilyMap, callback);
117 RegisterFontFamilyMapObserver(®istrar_,
118 prefs::kWebKitSansSerifFontFamilyMap, callback);
119 RegisterFontFamilyMapObserver(®istrar_,
120 prefs::kWebKitFixedFontFamilyMap, callback);
121 RegisterFontFamilyMapObserver(®istrar_,
122 prefs::kWebKitCursiveFontFamilyMap, callback);
123 RegisterFontFamilyMapObserver(®istrar_,
124 prefs::kWebKitFantasyFontFamilyMap, callback);
125 RegisterFontFamilyMapObserver(®istrar_,
126 prefs::kWebKitPictographFontFamilyMap,
130 FontSettingsEventRouter::~FontSettingsEventRouter() {}
132 void FontSettingsEventRouter::AddPrefToObserve(const char* pref_name,
133 const char* event_name,
135 registrar_.Add(pref_name,
136 base::Bind(&FontSettingsEventRouter::OnFontPrefChanged,
137 base::Unretained(this),
141 void FontSettingsEventRouter::OnFontFamilyMapPrefChanged(
142 const std::string& pref_name) {
143 std::string generic_family;
145 if (pref_names_util::ParseFontNamePrefPath(pref_name, &generic_family,
147 OnFontNamePrefChanged(pref_name, generic_family, 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(
162 std::string font_name;
163 if (!pref->GetValue()->GetAsString(&font_name)) {
167 font_name = MaybeGetLocalizedFontName(font_name);
169 base::ListValue args;
170 base::DictionaryValue* dict = new base::DictionaryValue();
172 dict->SetString(kFontIdKey, font_name);
173 dict->SetString(kGenericFamilyKey, generic_family);
174 dict->SetString(kScriptKey, script);
176 extensions::preference_helpers::DispatchEventToExtensions(
178 fonts::OnFontChanged::kEventName,
180 APIPermission::kFontSettings,
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(
193 base::ListValue args;
194 base::DictionaryValue* dict = new base::DictionaryValue();
196 dict->Set(key, pref->GetValue()->DeepCopy());
198 extensions::preference_helpers::DispatchEventToExtensions(
202 APIPermission::kFontSettings,
207 FontSettingsAPI::FontSettingsAPI(Profile* profile)
208 : font_settings_event_router_(new FontSettingsEventRouter(profile)) {
211 FontSettingsAPI::~FontSettingsAPI() {
214 static base::LazyInstance<ProfileKeyedAPIFactory<FontSettingsAPI> >
215 g_factory = LAZY_INSTANCE_INITIALIZER;
218 ProfileKeyedAPIFactory<FontSettingsAPI>* FontSettingsAPI::GetFactoryInstance() {
219 return g_factory.Pointer();
222 bool FontSettingsClearFontFunction::RunImpl() {
223 if (GetProfile()->IsOffTheRecord()) {
224 error_ = kSetFromIncognitoError;
228 scoped_ptr<fonts::ClearFont::Params> params(
229 fonts::ClearFont::Params::Create(*args_));
230 EXTENSION_FUNCTION_VALIDATE(params.get());
232 std::string pref_path = GetFontNamePrefPath(params->details.generic_family,
233 params->details.script);
235 // Ensure |pref_path| really is for a registered per-script font pref.
236 EXTENSION_FUNCTION_VALIDATE(
237 GetProfile()->GetPrefs()->FindPreference(pref_path.c_str()));
239 PreferenceAPI::Get(GetProfile())->RemoveExtensionControlledPref(
240 extension_id(), pref_path.c_str(), kExtensionPrefsScopeRegular);
244 bool FontSettingsGetFontFunction::RunImpl() {
245 scoped_ptr<fonts::GetFont::Params> params(
246 fonts::GetFont::Params::Create(*args_));
247 EXTENSION_FUNCTION_VALIDATE(params.get());
249 std::string pref_path = GetFontNamePrefPath(params->details.generic_family,
250 params->details.script);
252 PrefService* prefs = GetProfile()->GetPrefs();
253 const PrefService::Preference* pref =
254 prefs->FindPreference(pref_path.c_str());
256 std::string font_name;
257 EXTENSION_FUNCTION_VALIDATE(
258 pref && pref->GetValue()->GetAsString(&font_name));
259 font_name = MaybeGetLocalizedFontName(font_name);
261 // We don't support incognito-specific font prefs, so don't consider them when
262 // getting level of control.
263 const bool kIncognito = false;
264 std::string level_of_control =
265 extensions::preference_helpers::GetLevelOfControl(
266 GetProfile(), extension_id(), pref_path, kIncognito);
268 base::DictionaryValue* result = new base::DictionaryValue();
269 result->SetString(kFontIdKey, font_name);
270 result->SetString(kLevelOfControlKey, level_of_control);
275 bool FontSettingsSetFontFunction::RunImpl() {
276 if (GetProfile()->IsOffTheRecord()) {
277 error_ = kSetFromIncognitoError;
281 scoped_ptr<fonts::SetFont::Params> params(
282 fonts::SetFont::Params::Create(*args_));
283 EXTENSION_FUNCTION_VALIDATE(params.get());
285 std::string pref_path = GetFontNamePrefPath(params->details.generic_family,
286 params->details.script);
288 // Ensure |pref_path| really is for a registered font pref.
289 EXTENSION_FUNCTION_VALIDATE(
290 GetProfile()->GetPrefs()->FindPreference(pref_path.c_str()));
292 PreferenceAPI::Get(GetProfile())->SetExtensionControlledPref(
295 kExtensionPrefsScopeRegular,
296 new base::StringValue(params->details.font_id));
300 bool FontSettingsGetFontListFunction::RunImpl() {
301 content::GetFontListAsync(
302 Bind(&FontSettingsGetFontListFunction::FontListHasLoaded, this));
306 void FontSettingsGetFontListFunction::FontListHasLoaded(
307 scoped_ptr<base::ListValue> list) {
308 bool success = CopyFontsToResult(list.get());
309 SendResponse(success);
312 bool FontSettingsGetFontListFunction::CopyFontsToResult(
313 base::ListValue* fonts) {
314 scoped_ptr<base::ListValue> result(new base::ListValue());
315 for (base::ListValue::iterator it = fonts->begin();
316 it != fonts->end(); ++it) {
317 base::ListValue* font_list_value;
318 if (!(*it)->GetAsList(&font_list_value)) {
324 if (!font_list_value->GetString(0, &name)) {
329 std::string localized_name;
330 if (!font_list_value->GetString(1, &localized_name)) {
335 base::DictionaryValue* font_name = new base::DictionaryValue();
336 font_name->Set(kFontIdKey, new base::StringValue(name));
337 font_name->Set(kDisplayNameKey, new base::StringValue(localized_name));
338 result->Append(font_name);
341 SetResult(result.release());
345 bool ClearFontPrefExtensionFunction::RunImpl() {
346 if (GetProfile()->IsOffTheRecord()) {
347 error_ = kSetFromIncognitoError;
351 PreferenceAPI::Get(GetProfile())->RemoveExtensionControlledPref(
352 extension_id(), GetPrefName(), kExtensionPrefsScopeRegular);
356 bool GetFontPrefExtensionFunction::RunImpl() {
357 PrefService* prefs = GetProfile()->GetPrefs();
358 const PrefService::Preference* pref = prefs->FindPreference(GetPrefName());
359 EXTENSION_FUNCTION_VALIDATE(pref);
361 // We don't support incognito-specific font prefs, so don't consider them when
362 // getting level of control.
363 const bool kIncognito = false;
365 std::string level_of_control =
366 extensions::preference_helpers::GetLevelOfControl(
367 GetProfile(), extension_id(), GetPrefName(), kIncognito);
369 base::DictionaryValue* result = new base::DictionaryValue();
370 result->Set(GetKey(), pref->GetValue()->DeepCopy());
371 result->SetString(kLevelOfControlKey, level_of_control);
376 bool SetFontPrefExtensionFunction::RunImpl() {
377 if (GetProfile()->IsOffTheRecord()) {
378 error_ = kSetFromIncognitoError;
382 base::DictionaryValue* details = NULL;
383 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details));
386 EXTENSION_FUNCTION_VALIDATE(details->Get(GetKey(), &value));
388 PreferenceAPI::Get(GetProfile())
389 ->SetExtensionControlledPref(extension_id(),
391 kExtensionPrefsScopeRegular,
396 const char* FontSettingsClearDefaultFontSizeFunction::GetPrefName() {
397 return prefs::kWebKitDefaultFontSize;
400 const char* FontSettingsGetDefaultFontSizeFunction::GetPrefName() {
401 return prefs::kWebKitDefaultFontSize;
404 const char* FontSettingsGetDefaultFontSizeFunction::GetKey() {
405 return kPixelSizeKey;
408 const char* FontSettingsSetDefaultFontSizeFunction::GetPrefName() {
409 return prefs::kWebKitDefaultFontSize;
412 const char* FontSettingsSetDefaultFontSizeFunction::GetKey() {
413 return kPixelSizeKey;
416 const char* FontSettingsClearDefaultFixedFontSizeFunction::GetPrefName() {
417 return prefs::kWebKitDefaultFixedFontSize;
420 const char* FontSettingsGetDefaultFixedFontSizeFunction::GetPrefName() {
421 return prefs::kWebKitDefaultFixedFontSize;
424 const char* FontSettingsGetDefaultFixedFontSizeFunction::GetKey() {
425 return kPixelSizeKey;
428 const char* FontSettingsSetDefaultFixedFontSizeFunction::GetPrefName() {
429 return prefs::kWebKitDefaultFixedFontSize;
432 const char* FontSettingsSetDefaultFixedFontSizeFunction::GetKey() {
433 return kPixelSizeKey;
436 const char* FontSettingsClearMinimumFontSizeFunction::GetPrefName() {
437 return prefs::kWebKitMinimumFontSize;
440 const char* FontSettingsGetMinimumFontSizeFunction::GetPrefName() {
441 return prefs::kWebKitMinimumFontSize;
444 const char* FontSettingsGetMinimumFontSizeFunction::GetKey() {
445 return kPixelSizeKey;
448 const char* FontSettingsSetMinimumFontSizeFunction::GetPrefName() {
449 return prefs::kWebKitMinimumFontSize;
452 const char* FontSettingsSetMinimumFontSizeFunction::GetKey() {
453 return kPixelSizeKey;
456 } // namespace extensions