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/metrics/histogram_macros.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/trace_event/trace_event.h"
18 #include "base/values.h"
19 #include "chrome/browser/chrome_notification_types.h"
20 #include "chrome/browser/extensions/api/preference/preference_api.h"
21 #include "chrome/browser/extensions/api/preference/preference_helpers.h"
22 #include "chrome/browser/extensions/extension_service.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/common/extensions/api/font_settings.h"
25 #include "chrome/common/pref_names.h"
26 #include "chrome/common/pref_names_util.h"
27 #include "content/public/browser/font_list_async.h"
28 #include "content/public/browser/notification_details.h"
29 #include "content/public/browser/notification_source.h"
30 #include "extensions/browser/extension_system.h"
31 #include "extensions/common/error_utils.h"
34 #include "ui/gfx/font.h"
35 #include "ui/gfx/platform_font_win.h"
38 namespace extensions
{
40 namespace fonts
= api::font_settings
;
44 const char kFontIdKey
[] = "fontId";
45 const char kGenericFamilyKey
[] = "genericFamily";
46 const char kLevelOfControlKey
[] = "levelOfControl";
47 const char kDisplayNameKey
[] = "displayName";
48 const char kPixelSizeKey
[] = "pixelSize";
49 const char kScriptKey
[] = "script";
51 const char kSetFromIncognitoError
[] =
52 "Can't modify regular settings from an incognito context.";
54 // Format for font name preference paths.
55 const char kWebKitFontPrefFormat
[] = "webkit.webprefs.fonts.%s.%s";
57 // Gets the font name preference path for |generic_family| and |script|. If
58 // |script| is NULL, uses prefs::kWebKitCommonScript.
59 std::string
GetFontNamePrefPath(fonts::GenericFamily generic_family_enum
,
60 fonts::ScriptCode script_enum
) {
61 std::string script
= fonts::ToString(script_enum
);
63 script
= prefs::kWebKitCommonScript
;
64 std::string generic_family
= fonts::ToString(generic_family_enum
);
65 return base::StringPrintf(kWebKitFontPrefFormat
,
66 generic_family
.c_str(),
70 // Returns the localized name of a font so that it can be matched within the
71 // list of system fonts. On Windows, the list of system fonts has names only
72 // for the system locale, but the pref value may be in the English name.
73 std::string
MaybeGetLocalizedFontName(const std::string
& font_name
) {
75 if (!font_name
.empty()) {
76 gfx::Font
font(font_name
, 12); // dummy font size
77 return static_cast<gfx::PlatformFontWin
*>(font
.platform_font())->
78 GetLocalizedFontName();
84 // Registers |obs| to observe per-script font prefs under the path |map_name|.
85 void RegisterFontFamilyMapObserver(
86 PrefChangeRegistrar
* registrar
,
88 const PrefChangeRegistrar::NamedChangeCallback
& callback
) {
89 for (size_t i
= 0; i
< prefs::kWebKitScriptsForFontFamilyMapsLength
; ++i
) {
90 const char* script
= prefs::kWebKitScriptsForFontFamilyMaps
[i
];
91 registrar
->Add(base::StringPrintf("%s.%s", map_name
, script
), callback
);
97 FontSettingsEventRouter::FontSettingsEventRouter(
98 Profile
* profile
) : profile_(profile
) {
99 TRACE_EVENT0("browser,startup", "FontSettingsEventRouter::ctor")
100 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.FontSettingsEventRouterCtorTime");
102 registrar_
.Init(profile_
->GetPrefs());
104 AddPrefToObserve(prefs::kWebKitDefaultFixedFontSize
,
105 events::FONT_SETTINGS_ON_DEFAULT_FIXED_FONT_SIZE_CHANGED
,
106 fonts::OnDefaultFixedFontSizeChanged::kEventName
,
108 AddPrefToObserve(prefs::kWebKitDefaultFontSize
,
109 events::FONT_SETTINGS_ON_DEFAULT_FONT_SIZE_CHANGED
,
110 fonts::OnDefaultFontSizeChanged::kEventName
, kPixelSizeKey
);
111 AddPrefToObserve(prefs::kWebKitMinimumFontSize
,
112 events::FONT_SETTINGS_ON_MINIMUM_FONT_SIZE_CHANGED
,
113 fonts::OnMinimumFontSizeChanged::kEventName
, kPixelSizeKey
);
115 PrefChangeRegistrar::NamedChangeCallback callback
=
116 base::Bind(&FontSettingsEventRouter::OnFontFamilyMapPrefChanged
,
117 base::Unretained(this));
118 RegisterFontFamilyMapObserver(®istrar_
,
119 prefs::kWebKitStandardFontFamilyMap
, callback
);
120 RegisterFontFamilyMapObserver(®istrar_
,
121 prefs::kWebKitSerifFontFamilyMap
, callback
);
122 RegisterFontFamilyMapObserver(®istrar_
,
123 prefs::kWebKitSansSerifFontFamilyMap
, callback
);
124 RegisterFontFamilyMapObserver(®istrar_
,
125 prefs::kWebKitFixedFontFamilyMap
, callback
);
126 RegisterFontFamilyMapObserver(®istrar_
,
127 prefs::kWebKitCursiveFontFamilyMap
, callback
);
128 RegisterFontFamilyMapObserver(®istrar_
,
129 prefs::kWebKitFantasyFontFamilyMap
, callback
);
130 RegisterFontFamilyMapObserver(®istrar_
,
131 prefs::kWebKitPictographFontFamilyMap
,
135 FontSettingsEventRouter::~FontSettingsEventRouter() {}
137 void FontSettingsEventRouter::AddPrefToObserve(
138 const char* pref_name
,
139 events::HistogramValue histogram_value
,
140 const char* event_name
,
144 base::Bind(&FontSettingsEventRouter::OnFontPrefChanged
,
145 base::Unretained(this), histogram_value
, event_name
, key
));
148 void FontSettingsEventRouter::OnFontFamilyMapPrefChanged(
149 const std::string
& pref_name
) {
150 std::string generic_family
;
152 if (pref_names_util::ParseFontNamePrefPath(pref_name
, &generic_family
,
154 OnFontNamePrefChanged(pref_name
, generic_family
, script
);
161 void FontSettingsEventRouter::OnFontNamePrefChanged(
162 const std::string
& pref_name
,
163 const std::string
& generic_family
,
164 const std::string
& script
) {
165 const PrefService::Preference
* pref
= registrar_
.prefs()->FindPreference(
169 std::string font_name
;
170 if (!pref
->GetValue()->GetAsString(&font_name
)) {
174 font_name
= MaybeGetLocalizedFontName(font_name
);
176 base::ListValue args
;
177 base::DictionaryValue
* dict
= new base::DictionaryValue();
179 dict
->SetString(kFontIdKey
, font_name
);
180 dict
->SetString(kGenericFamilyKey
, generic_family
);
181 dict
->SetString(kScriptKey
, script
);
183 extensions::preference_helpers::DispatchEventToExtensions(
184 profile_
, events::FONT_SETTINGS_ON_FONT_CHANGED
,
185 fonts::OnFontChanged::kEventName
, &args
, APIPermission::kFontSettings
,
189 void FontSettingsEventRouter::OnFontPrefChanged(
190 events::HistogramValue histogram_value
,
191 const std::string
& event_name
,
192 const std::string
& key
,
193 const std::string
& pref_name
) {
194 const PrefService::Preference
* pref
= registrar_
.prefs()->FindPreference(
198 base::ListValue args
;
199 base::DictionaryValue
* dict
= new base::DictionaryValue();
201 dict
->Set(key
, pref
->GetValue()->DeepCopy());
203 extensions::preference_helpers::DispatchEventToExtensions(
204 profile_
, histogram_value
, event_name
, &args
,
205 APIPermission::kFontSettings
, false, pref_name
);
208 FontSettingsAPI::FontSettingsAPI(content::BrowserContext
* context
)
209 : font_settings_event_router_(
210 new FontSettingsEventRouter(Profile::FromBrowserContext(context
))) {}
212 FontSettingsAPI::~FontSettingsAPI() {
215 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<FontSettingsAPI
> >
216 g_factory
= LAZY_INSTANCE_INITIALIZER
;
219 BrowserContextKeyedAPIFactory
<FontSettingsAPI
>*
220 FontSettingsAPI::GetFactoryInstance() {
221 return g_factory
.Pointer();
224 bool FontSettingsClearFontFunction::RunSync() {
225 if (GetProfile()->IsOffTheRecord()) {
226 error_
= kSetFromIncognitoError
;
230 scoped_ptr
<fonts::ClearFont::Params
> params(
231 fonts::ClearFont::Params::Create(*args_
));
232 EXTENSION_FUNCTION_VALIDATE(params
.get());
234 std::string pref_path
= GetFontNamePrefPath(params
->details
.generic_family
,
235 params
->details
.script
);
237 // Ensure |pref_path| really is for a registered per-script font pref.
238 EXTENSION_FUNCTION_VALIDATE(
239 GetProfile()->GetPrefs()->FindPreference(pref_path
));
241 PreferenceAPI::Get(GetProfile())->RemoveExtensionControlledPref(
242 extension_id(), pref_path
, kExtensionPrefsScopeRegular
);
246 bool FontSettingsGetFontFunction::RunSync() {
247 scoped_ptr
<fonts::GetFont::Params
> params(
248 fonts::GetFont::Params::Create(*args_
));
249 EXTENSION_FUNCTION_VALIDATE(params
.get());
251 std::string pref_path
= GetFontNamePrefPath(params
->details
.generic_family
,
252 params
->details
.script
);
254 PrefService
* prefs
= GetProfile()->GetPrefs();
255 const PrefService::Preference
* pref
=
256 prefs
->FindPreference(pref_path
);
258 std::string font_name
;
259 EXTENSION_FUNCTION_VALIDATE(
260 pref
&& pref
->GetValue()->GetAsString(&font_name
));
261 font_name
= MaybeGetLocalizedFontName(font_name
);
263 // We don't support incognito-specific font prefs, so don't consider them when
264 // getting level of control.
265 const bool kIncognito
= false;
266 std::string level_of_control
=
267 extensions::preference_helpers::GetLevelOfControl(
268 GetProfile(), extension_id(), pref_path
, kIncognito
);
270 base::DictionaryValue
* result
= new base::DictionaryValue();
271 result
->SetString(kFontIdKey
, font_name
);
272 result
->SetString(kLevelOfControlKey
, level_of_control
);
277 bool FontSettingsSetFontFunction::RunSync() {
278 if (GetProfile()->IsOffTheRecord()) {
279 error_
= kSetFromIncognitoError
;
283 scoped_ptr
<fonts::SetFont::Params
> params(
284 fonts::SetFont::Params::Create(*args_
));
285 EXTENSION_FUNCTION_VALIDATE(params
.get());
287 std::string pref_path
= GetFontNamePrefPath(params
->details
.generic_family
,
288 params
->details
.script
);
290 // Ensure |pref_path| really is for a registered font pref.
291 EXTENSION_FUNCTION_VALIDATE(
292 GetProfile()->GetPrefs()->FindPreference(pref_path
));
294 PreferenceAPI::Get(GetProfile())->SetExtensionControlledPref(
297 kExtensionPrefsScopeRegular
,
298 new base::StringValue(params
->details
.font_id
));
302 bool FontSettingsGetFontListFunction::RunAsync() {
303 content::GetFontListAsync(
304 Bind(&FontSettingsGetFontListFunction::FontListHasLoaded
, this));
308 void FontSettingsGetFontListFunction::FontListHasLoaded(
309 scoped_ptr
<base::ListValue
> list
) {
310 bool success
= CopyFontsToResult(list
.get());
311 SendResponse(success
);
314 bool FontSettingsGetFontListFunction::CopyFontsToResult(
315 base::ListValue
* fonts
) {
316 scoped_ptr
<base::ListValue
> result(new base::ListValue());
317 for (base::ListValue::iterator it
= fonts
->begin();
318 it
!= fonts
->end(); ++it
) {
319 base::ListValue
* font_list_value
;
320 if (!(*it
)->GetAsList(&font_list_value
)) {
326 if (!font_list_value
->GetString(0, &name
)) {
331 std::string localized_name
;
332 if (!font_list_value
->GetString(1, &localized_name
)) {
337 base::DictionaryValue
* font_name
= new base::DictionaryValue();
338 font_name
->Set(kFontIdKey
, new base::StringValue(name
));
339 font_name
->Set(kDisplayNameKey
, new base::StringValue(localized_name
));
340 result
->Append(font_name
);
343 SetResult(result
.release());
347 bool ClearFontPrefExtensionFunction::RunSync() {
348 if (GetProfile()->IsOffTheRecord()) {
349 error_
= kSetFromIncognitoError
;
353 PreferenceAPI::Get(GetProfile())->RemoveExtensionControlledPref(
354 extension_id(), GetPrefName(), kExtensionPrefsScopeRegular
);
358 bool GetFontPrefExtensionFunction::RunSync() {
359 PrefService
* prefs
= GetProfile()->GetPrefs();
360 const PrefService::Preference
* pref
= prefs
->FindPreference(GetPrefName());
361 EXTENSION_FUNCTION_VALIDATE(pref
);
363 // We don't support incognito-specific font prefs, so don't consider them when
364 // getting level of control.
365 const bool kIncognito
= false;
367 std::string level_of_control
=
368 extensions::preference_helpers::GetLevelOfControl(
369 GetProfile(), extension_id(), GetPrefName(), kIncognito
);
371 base::DictionaryValue
* result
= new base::DictionaryValue();
372 result
->Set(GetKey(), pref
->GetValue()->DeepCopy());
373 result
->SetString(kLevelOfControlKey
, level_of_control
);
378 bool SetFontPrefExtensionFunction::RunSync() {
379 if (GetProfile()->IsOffTheRecord()) {
380 error_
= kSetFromIncognitoError
;
384 base::DictionaryValue
* details
= NULL
;
385 EXTENSION_FUNCTION_VALIDATE(args_
->GetDictionary(0, &details
));
388 EXTENSION_FUNCTION_VALIDATE(details
->Get(GetKey(), &value
));
390 PreferenceAPI::Get(GetProfile())
391 ->SetExtensionControlledPref(extension_id(),
393 kExtensionPrefsScopeRegular
,
398 const char* FontSettingsClearDefaultFontSizeFunction::GetPrefName() {
399 return prefs::kWebKitDefaultFontSize
;
402 const char* FontSettingsGetDefaultFontSizeFunction::GetPrefName() {
403 return prefs::kWebKitDefaultFontSize
;
406 const char* FontSettingsGetDefaultFontSizeFunction::GetKey() {
407 return kPixelSizeKey
;
410 const char* FontSettingsSetDefaultFontSizeFunction::GetPrefName() {
411 return prefs::kWebKitDefaultFontSize
;
414 const char* FontSettingsSetDefaultFontSizeFunction::GetKey() {
415 return kPixelSizeKey
;
418 const char* FontSettingsClearDefaultFixedFontSizeFunction::GetPrefName() {
419 return prefs::kWebKitDefaultFixedFontSize
;
422 const char* FontSettingsGetDefaultFixedFontSizeFunction::GetPrefName() {
423 return prefs::kWebKitDefaultFixedFontSize
;
426 const char* FontSettingsGetDefaultFixedFontSizeFunction::GetKey() {
427 return kPixelSizeKey
;
430 const char* FontSettingsSetDefaultFixedFontSizeFunction::GetPrefName() {
431 return prefs::kWebKitDefaultFixedFontSize
;
434 const char* FontSettingsSetDefaultFixedFontSizeFunction::GetKey() {
435 return kPixelSizeKey
;
438 const char* FontSettingsClearMinimumFontSizeFunction::GetPrefName() {
439 return prefs::kWebKitMinimumFontSize
;
442 const char* FontSettingsGetMinimumFontSizeFunction::GetPrefName() {
443 return prefs::kWebKitMinimumFontSize
;
446 const char* FontSettingsGetMinimumFontSizeFunction::GetKey() {
447 return kPixelSizeKey
;
450 const char* FontSettingsSetMinimumFontSizeFunction::GetPrefName() {
451 return prefs::kWebKitMinimumFontSize
;
454 const char* FontSettingsSetMinimumFontSizeFunction::GetKey() {
455 return kPixelSizeKey
;
458 } // namespace extensions