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