OLD | NEW |
| (Empty) |
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/extension_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/stringprintf.h" | |
13 #include "base/string_util.h" | |
14 #include "base/values.h" | |
15 #include "chrome/browser/extensions/extension_preference_helpers.h" | |
16 #include "chrome/browser/extensions/extension_service.h" | |
17 #include "chrome/browser/prefs/pref_service.h" | |
18 #include "chrome/browser/profiles/profile.h" | |
19 #include "chrome/common/chrome_notification_types.h" | |
20 #include "chrome/common/extensions/api/font_settings.h" | |
21 #include "chrome/common/extensions/extension_error_utils.h" | |
22 #include "chrome/common/pref_names.h" | |
23 #include "content/public/browser/font_list_async.h" | |
24 #include "content/public/browser/notification_details.h" | |
25 #include "content/public/browser/notification_source.h" | |
26 | |
27 #if defined(OS_WIN) | |
28 #include "ui/gfx/font.h" | |
29 #include "ui/gfx/platform_font_win.h" | |
30 #endif | |
31 | |
32 using extensions::APIPermission; | |
33 | |
34 namespace fonts = extensions::api::font_settings; | |
35 | |
36 namespace { | |
37 | |
38 const char kFontIdKey[] = "fontId"; | |
39 const char kGenericFamilyKey[] = "genericFamily"; | |
40 const char kLevelOfControlKey[] = "levelOfControl"; | |
41 const char kDisplayNameKey[] = "displayName"; | |
42 const char kPixelSizeKey[] = "pixelSize"; | |
43 const char kScriptKey[] = "script"; | |
44 | |
45 const char kSetFromIncognitoError[] = | |
46 "Can't modify regular settings from an incognito context."; | |
47 | |
48 const char kOnDefaultFixedFontSizeChanged[] = | |
49 "fontSettings.onDefaultFixedFontSizeChanged"; | |
50 const char kOnDefaultFontSizeChanged[] = | |
51 "fontSettings.onDefaultFontSizeChanged"; | |
52 const char kOnFontChanged[] = "fontSettings.onFontChanged"; | |
53 const char kOnMinimumFontSizeChanged[] = | |
54 "fontSettings.onMinimumFontSizeChanged"; | |
55 | |
56 // Format for font name preference paths. | |
57 const char kWebKitFontPrefFormat[] = "webkit.webprefs.fonts.%s.%s"; | |
58 const char kWebKitFontPrefPrefix[] = "webkit.webprefs.fonts."; | |
59 | |
60 // Gets the font name preference path for |generic_family| and |script|. If | |
61 // |script| is NULL, uses prefs::kWebKitCommonScript. | |
62 std::string GetFontNamePrefPath(const std::string& generic_family, | |
63 const std::string* script) { | |
64 return StringPrintf(kWebKitFontPrefFormat, | |
65 generic_family.c_str(), | |
66 script ? script->c_str() : prefs::kWebKitCommonScript); | |
67 } | |
68 | |
69 // Extracts the generic family and script from font name pref path |pref_path|. | |
70 bool ParseFontNamePrefPath(std::string pref_path, | |
71 std::string* generic_family, | |
72 std::string* script) { | |
73 if (!StartsWithASCII(pref_path, kWebKitFontPrefPrefix, true)) | |
74 return false; | |
75 | |
76 size_t start = strlen(kWebKitFontPrefPrefix); | |
77 size_t pos = pref_path.find('.', start); | |
78 if (pos == std::string::npos || pos + 1 == pref_path.length()) | |
79 return false; | |
80 *generic_family = pref_path.substr(start, pos - start); | |
81 *script = pref_path.substr(pos + 1); | |
82 return true; | |
83 } | |
84 | |
85 // Returns the localized name of a font so that it can be matched within the | |
86 // list of system fonts. On Windows, the list of system fonts has names only | |
87 // for the system locale, but the pref value may be in the English name. | |
88 std::string MaybeGetLocalizedFontName(const std::string& font_name) { | |
89 #if defined(OS_WIN) | |
90 if (!font_name.empty()) { | |
91 gfx::Font font(font_name, 12); // dummy font size | |
92 return static_cast<gfx::PlatformFontWin*>(font.platform_font())-> | |
93 GetLocalizedFontName(); | |
94 } | |
95 #endif | |
96 return font_name; | |
97 } | |
98 | |
99 // Registers |obs| to observe per-script font prefs under the path |map_name|. | |
100 void RegisterFontFamilyMapObserver(PrefChangeRegistrar* registrar, | |
101 const char* map_name, | |
102 content::NotificationObserver* obs) { | |
103 for (size_t i = 0; i < prefs::kWebKitScriptsForFontFamilyMapsLength; ++i) { | |
104 const char* script = prefs::kWebKitScriptsForFontFamilyMaps[i]; | |
105 std::string pref_name = base::StringPrintf("%s.%s", map_name, script); | |
106 registrar->Add(pref_name.c_str(), obs); | |
107 } | |
108 } | |
109 | |
110 } // namespace | |
111 | |
112 ExtensionFontSettingsEventRouter::ExtensionFontSettingsEventRouter( | |
113 Profile* profile) : profile_(profile) {} | |
114 | |
115 ExtensionFontSettingsEventRouter::~ExtensionFontSettingsEventRouter() {} | |
116 | |
117 void ExtensionFontSettingsEventRouter::Init() { | |
118 registrar_.Init(profile_->GetPrefs()); | |
119 | |
120 AddPrefToObserve(prefs::kWebKitDefaultFixedFontSize, | |
121 kOnDefaultFixedFontSizeChanged, | |
122 kPixelSizeKey); | |
123 AddPrefToObserve(prefs::kWebKitDefaultFontSize, | |
124 kOnDefaultFontSizeChanged, | |
125 kPixelSizeKey); | |
126 AddPrefToObserve(prefs::kWebKitMinimumFontSize, | |
127 kOnMinimumFontSizeChanged, | |
128 kPixelSizeKey); | |
129 | |
130 RegisterFontFamilyMapObserver(®istrar_, | |
131 prefs::kWebKitStandardFontFamilyMap, this); | |
132 RegisterFontFamilyMapObserver(®istrar_, | |
133 prefs::kWebKitSerifFontFamilyMap, this); | |
134 RegisterFontFamilyMapObserver(®istrar_, | |
135 prefs::kWebKitSansSerifFontFamilyMap, this); | |
136 RegisterFontFamilyMapObserver(®istrar_, | |
137 prefs::kWebKitFixedFontFamilyMap, this); | |
138 RegisterFontFamilyMapObserver(®istrar_, | |
139 prefs::kWebKitCursiveFontFamilyMap, this); | |
140 RegisterFontFamilyMapObserver(®istrar_, | |
141 prefs::kWebKitFantasyFontFamilyMap, this); | |
142 } | |
143 | |
144 void ExtensionFontSettingsEventRouter::AddPrefToObserve(const char* pref_name, | |
145 const char* event_name, | |
146 const char* key) { | |
147 registrar_.Add(pref_name, this); | |
148 pref_event_map_[pref_name] = std::make_pair(event_name, key); | |
149 } | |
150 | |
151 void ExtensionFontSettingsEventRouter::Observe( | |
152 int type, | |
153 const content::NotificationSource& source, | |
154 const content::NotificationDetails& details) { | |
155 if (type != chrome::NOTIFICATION_PREF_CHANGED) { | |
156 NOTREACHED(); | |
157 return; | |
158 } | |
159 | |
160 PrefService* pref_service = content::Source<PrefService>(source).ptr(); | |
161 bool incognito = (pref_service != profile_->GetPrefs()); | |
162 // We're only observing pref changes on the regular profile. | |
163 DCHECK(!incognito); | |
164 const std::string* pref_name = | |
165 content::Details<const std::string>(details).ptr(); | |
166 | |
167 PrefEventMap::iterator iter = pref_event_map_.find(*pref_name); | |
168 if (iter != pref_event_map_.end()) { | |
169 const std::string& event_name = iter->second.first; | |
170 const std::string& key = iter->second.second; | |
171 OnFontPrefChanged(pref_service, *pref_name, event_name, key, incognito); | |
172 return; | |
173 } | |
174 | |
175 std::string generic_family; | |
176 std::string script; | |
177 if (ParseFontNamePrefPath(*pref_name, &generic_family, &script)) { | |
178 OnFontNamePrefChanged(pref_service, *pref_name, generic_family, script, | |
179 incognito); | |
180 return; | |
181 } | |
182 | |
183 NOTREACHED(); | |
184 } | |
185 | |
186 void ExtensionFontSettingsEventRouter::OnFontNamePrefChanged( | |
187 PrefService* pref_service, | |
188 const std::string& pref_name, | |
189 const std::string& generic_family, | |
190 const std::string& script, | |
191 bool incognito) { | |
192 const PrefService::Preference* pref = pref_service->FindPreference( | |
193 pref_name.c_str()); | |
194 CHECK(pref); | |
195 | |
196 std::string font_name; | |
197 if (!pref->GetValue()->GetAsString(&font_name)) { | |
198 NOTREACHED(); | |
199 return; | |
200 } | |
201 font_name = MaybeGetLocalizedFontName(font_name); | |
202 | |
203 ListValue args; | |
204 DictionaryValue* dict = new DictionaryValue(); | |
205 args.Append(dict); | |
206 dict->SetString(kFontIdKey, font_name); | |
207 dict->SetString(kGenericFamilyKey, generic_family); | |
208 dict->SetString(kScriptKey, script); | |
209 | |
210 extension_preference_helpers::DispatchEventToExtensions( | |
211 profile_, | |
212 kOnFontChanged, | |
213 &args, | |
214 APIPermission::kFontSettings, | |
215 incognito, | |
216 pref_name); | |
217 } | |
218 | |
219 void ExtensionFontSettingsEventRouter::OnFontPrefChanged( | |
220 PrefService* pref_service, | |
221 const std::string& pref_name, | |
222 const std::string& event_name, | |
223 const std::string& key, | |
224 bool incognito) { | |
225 const PrefService::Preference* pref = pref_service->FindPreference( | |
226 pref_name.c_str()); | |
227 CHECK(pref); | |
228 | |
229 ListValue args; | |
230 DictionaryValue* dict = new DictionaryValue(); | |
231 args.Append(dict); | |
232 dict->Set(key, pref->GetValue()->DeepCopy()); | |
233 | |
234 extension_preference_helpers::DispatchEventToExtensions( | |
235 profile_, | |
236 event_name, | |
237 &args, | |
238 APIPermission::kFontSettings, | |
239 incognito, | |
240 pref_name); | |
241 } | |
242 | |
243 bool ClearFontFunction::RunImpl() { | |
244 if (profile_->IsOffTheRecord()) { | |
245 error_ = kSetFromIncognitoError; | |
246 return false; | |
247 } | |
248 | |
249 scoped_ptr<fonts::ClearFont::Params> params( | |
250 fonts::ClearFont::Params::Create(*args_)); | |
251 EXTENSION_FUNCTION_VALIDATE(params.get()); | |
252 | |
253 std::string pref_path = GetFontNamePrefPath(params->details.generic_family, | |
254 params->details.script.get()); | |
255 | |
256 // Ensure |pref_path| really is for a registered per-script font pref. | |
257 EXTENSION_FUNCTION_VALIDATE( | |
258 profile_->GetPrefs()->FindPreference(pref_path.c_str())); | |
259 | |
260 extensions::ExtensionPrefs* prefs = | |
261 profile_->GetExtensionService()->extension_prefs(); | |
262 prefs->RemoveExtensionControlledPref(extension_id(), | |
263 pref_path.c_str(), | |
264 extensions::kExtensionPrefsScopeRegular); | |
265 return true; | |
266 } | |
267 | |
268 bool GetFontFunction::RunImpl() { | |
269 scoped_ptr<fonts::GetFont::Params> params( | |
270 fonts::GetFont::Params::Create(*args_)); | |
271 EXTENSION_FUNCTION_VALIDATE(params.get()); | |
272 | |
273 std::string pref_path = GetFontNamePrefPath(params->details.generic_family, | |
274 params->details.script.get()); | |
275 PrefService* prefs = profile_->GetPrefs(); | |
276 const PrefService::Preference* pref = | |
277 prefs->FindPreference(pref_path.c_str()); | |
278 | |
279 std::string font_name; | |
280 EXTENSION_FUNCTION_VALIDATE( | |
281 pref && pref->GetValue()->GetAsString(&font_name)); | |
282 font_name = MaybeGetLocalizedFontName(font_name); | |
283 | |
284 // We don't support incognito-specific font prefs, so don't consider them when | |
285 // getting level of control. | |
286 const bool kIncognito = false; | |
287 std::string level_of_control = | |
288 extension_preference_helpers::GetLevelOfControl(profile_, | |
289 extension_id(), | |
290 pref_path, | |
291 kIncognito); | |
292 | |
293 DictionaryValue* result = new DictionaryValue(); | |
294 result->SetString(kFontIdKey, font_name); | |
295 result->SetString(kLevelOfControlKey, level_of_control); | |
296 SetResult(result); | |
297 return true; | |
298 } | |
299 | |
300 bool SetFontFunction::RunImpl() { | |
301 if (profile_->IsOffTheRecord()) { | |
302 error_ = kSetFromIncognitoError; | |
303 return false; | |
304 } | |
305 | |
306 scoped_ptr<fonts::SetFont::Params> params( | |
307 fonts::SetFont::Params::Create(*args_)); | |
308 EXTENSION_FUNCTION_VALIDATE(params.get()); | |
309 | |
310 std::string pref_path = GetFontNamePrefPath(params->details.generic_family, | |
311 params->details.script.get()); | |
312 // Ensure |pref_path| really is for a registered font pref. | |
313 EXTENSION_FUNCTION_VALIDATE( | |
314 profile_->GetPrefs()->FindPreference(pref_path.c_str())); | |
315 | |
316 extensions::ExtensionPrefs* prefs = | |
317 profile_->GetExtensionService()->extension_prefs(); | |
318 prefs->SetExtensionControlledPref( | |
319 extension_id(), | |
320 pref_path.c_str(), | |
321 extensions::kExtensionPrefsScopeRegular, | |
322 Value::CreateStringValue(params->details.font_id)); | |
323 return true; | |
324 } | |
325 | |
326 bool GetFontListFunction::RunImpl() { | |
327 content::GetFontListAsync( | |
328 Bind(&GetFontListFunction::FontListHasLoaded, this)); | |
329 return true; | |
330 } | |
331 | |
332 void GetFontListFunction::FontListHasLoaded(scoped_ptr<ListValue> list) { | |
333 bool success = CopyFontsToResult(list.get()); | |
334 SendResponse(success); | |
335 } | |
336 | |
337 bool GetFontListFunction::CopyFontsToResult(ListValue* fonts) { | |
338 scoped_ptr<ListValue> result(new ListValue()); | |
339 for (ListValue::iterator it = fonts->begin(); it != fonts->end(); ++it) { | |
340 ListValue* font_list_value; | |
341 if (!(*it)->GetAsList(&font_list_value)) { | |
342 NOTREACHED(); | |
343 return false; | |
344 } | |
345 | |
346 std::string name; | |
347 if (!font_list_value->GetString(0, &name)) { | |
348 NOTREACHED(); | |
349 return false; | |
350 } | |
351 | |
352 std::string localized_name; | |
353 if (!font_list_value->GetString(1, &localized_name)) { | |
354 NOTREACHED(); | |
355 return false; | |
356 } | |
357 | |
358 DictionaryValue* font_name = new DictionaryValue(); | |
359 font_name->Set(kFontIdKey, Value::CreateStringValue(name)); | |
360 font_name->Set(kDisplayNameKey, Value::CreateStringValue(localized_name)); | |
361 result->Append(font_name); | |
362 } | |
363 | |
364 SetResult(result.release()); | |
365 return true; | |
366 } | |
367 | |
368 bool ClearFontPrefExtensionFunction::RunImpl() { | |
369 if (profile_->IsOffTheRecord()) { | |
370 error_ = kSetFromIncognitoError; | |
371 return false; | |
372 } | |
373 | |
374 extensions::ExtensionPrefs* prefs = | |
375 profile_->GetExtensionService()->extension_prefs(); | |
376 prefs->RemoveExtensionControlledPref(extension_id(), | |
377 GetPrefName(), | |
378 extensions::kExtensionPrefsScopeRegular); | |
379 return true; | |
380 } | |
381 | |
382 bool GetFontPrefExtensionFunction::RunImpl() { | |
383 PrefService* prefs = profile_->GetPrefs(); | |
384 const PrefService::Preference* pref = prefs->FindPreference(GetPrefName()); | |
385 EXTENSION_FUNCTION_VALIDATE(pref); | |
386 | |
387 // We don't support incognito-specific font prefs, so don't consider them when | |
388 // getting level of control. | |
389 const bool kIncognito = false; | |
390 | |
391 std::string level_of_control = | |
392 extension_preference_helpers::GetLevelOfControl(profile_, | |
393 extension_id(), | |
394 GetPrefName(), | |
395 kIncognito); | |
396 | |
397 DictionaryValue* result = new DictionaryValue(); | |
398 result->Set(GetKey(), pref->GetValue()->DeepCopy()); | |
399 result->SetString(kLevelOfControlKey, level_of_control); | |
400 SetResult(result); | |
401 return true; | |
402 } | |
403 | |
404 bool SetFontPrefExtensionFunction::RunImpl() { | |
405 if (profile_->IsOffTheRecord()) { | |
406 error_ = kSetFromIncognitoError; | |
407 return false; | |
408 } | |
409 | |
410 DictionaryValue* details = NULL; | |
411 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details)); | |
412 | |
413 Value* value; | |
414 EXTENSION_FUNCTION_VALIDATE(details->Get(GetKey(), &value)); | |
415 | |
416 extensions::ExtensionPrefs* prefs = | |
417 profile_->GetExtensionService()->extension_prefs(); | |
418 prefs->SetExtensionControlledPref(extension_id(), | |
419 GetPrefName(), | |
420 extensions::kExtensionPrefsScopeRegular, | |
421 value->DeepCopy()); | |
422 return true; | |
423 } | |
424 | |
425 const char* ClearDefaultFontSizeFunction::GetPrefName() { | |
426 return prefs::kWebKitDefaultFontSize; | |
427 } | |
428 | |
429 const char* GetDefaultFontSizeFunction::GetPrefName() { | |
430 return prefs::kWebKitDefaultFontSize; | |
431 } | |
432 | |
433 const char* GetDefaultFontSizeFunction::GetKey() { | |
434 return kPixelSizeKey; | |
435 } | |
436 | |
437 const char* SetDefaultFontSizeFunction::GetPrefName() { | |
438 return prefs::kWebKitDefaultFontSize; | |
439 } | |
440 | |
441 const char* SetDefaultFontSizeFunction::GetKey() { | |
442 return kPixelSizeKey; | |
443 } | |
444 | |
445 const char* ClearDefaultFixedFontSizeFunction::GetPrefName() { | |
446 return prefs::kWebKitDefaultFixedFontSize; | |
447 } | |
448 | |
449 const char* GetDefaultFixedFontSizeFunction::GetPrefName() { | |
450 return prefs::kWebKitDefaultFixedFontSize; | |
451 } | |
452 | |
453 const char* GetDefaultFixedFontSizeFunction::GetKey() { | |
454 return kPixelSizeKey; | |
455 } | |
456 | |
457 const char* SetDefaultFixedFontSizeFunction::GetPrefName() { | |
458 return prefs::kWebKitDefaultFixedFontSize; | |
459 } | |
460 | |
461 const char* SetDefaultFixedFontSizeFunction::GetKey() { | |
462 return kPixelSizeKey; | |
463 } | |
464 | |
465 const char* ClearMinimumFontSizeFunction::GetPrefName() { | |
466 return prefs::kWebKitMinimumFontSize; | |
467 } | |
468 | |
469 const char* GetMinimumFontSizeFunction::GetPrefName() { | |
470 return prefs::kWebKitMinimumFontSize; | |
471 } | |
472 | |
473 const char* GetMinimumFontSizeFunction::GetKey() { | |
474 return kPixelSizeKey; | |
475 } | |
476 | |
477 const char* SetMinimumFontSizeFunction::GetPrefName() { | |
478 return prefs::kWebKitMinimumFontSize; | |
479 } | |
480 | |
481 const char* SetMinimumFontSizeFunction::GetKey() { | |
482 return kPixelSizeKey; | |
483 } | |
OLD | NEW |