Home | History | Annotate | Download | only in font_settings
      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.
     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.
     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|.
     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 
     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 
    130 FontSettingsEventRouter::~FontSettingsEventRouter() {}
    131 
    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 
    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 
    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 
    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 
    207 FontSettingsAPI::FontSettingsAPI(content::BrowserContext* context)
    208     : font_settings_event_router_(
    209           new FontSettingsEventRouter(Profile::FromBrowserContext(context))) {}
    210 
    211 FontSettingsAPI::~FontSettingsAPI() {
    212 }
    213 
    214 static base::LazyInstance<BrowserContextKeyedAPIFactory<FontSettingsAPI> >
    215     g_factory = LAZY_INSTANCE_INITIALIZER;
    216 
    217 // static
    218 BrowserContextKeyedAPIFactory<FontSettingsAPI>*
    219 FontSettingsAPI::GetFactoryInstance() {
    220   return g_factory.Pointer();
    221 }
    222 
    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 
    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 
    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 
    301 bool FontSettingsGetFontListFunction::RunAsync() {
    302   content::GetFontListAsync(
    303       Bind(&FontSettingsGetFontListFunction::FontListHasLoaded, this));
    304   return true;
    305 }
    306 
    307 void FontSettingsGetFontListFunction::FontListHasLoaded(
    308     scoped_ptr<base::ListValue> list) {
    309   bool success = CopyFontsToResult(list.get());
    310   SendResponse(success);
    311 }
    312 
    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 
    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 
    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 
    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 
    397 const char* FontSettingsClearDefaultFontSizeFunction::GetPrefName() {
    398   return prefs::kWebKitDefaultFontSize;
    399 }
    400 
    401 const char* FontSettingsGetDefaultFontSizeFunction::GetPrefName() {
    402   return prefs::kWebKitDefaultFontSize;
    403 }
    404 
    405 const char* FontSettingsGetDefaultFontSizeFunction::GetKey() {
    406   return kPixelSizeKey;
    407 }
    408 
    409 const char* FontSettingsSetDefaultFontSizeFunction::GetPrefName() {
    410   return prefs::kWebKitDefaultFontSize;
    411 }
    412 
    413 const char* FontSettingsSetDefaultFontSizeFunction::GetKey() {
    414   return kPixelSizeKey;
    415 }
    416 
    417 const char* FontSettingsClearDefaultFixedFontSizeFunction::GetPrefName() {
    418   return prefs::kWebKitDefaultFixedFontSize;
    419 }
    420 
    421 const char* FontSettingsGetDefaultFixedFontSizeFunction::GetPrefName() {
    422   return prefs::kWebKitDefaultFixedFontSize;
    423 }
    424 
    425 const char* FontSettingsGetDefaultFixedFontSizeFunction::GetKey() {
    426   return kPixelSizeKey;
    427 }
    428 
    429 const char* FontSettingsSetDefaultFixedFontSizeFunction::GetPrefName() {
    430   return prefs::kWebKitDefaultFixedFontSize;
    431 }
    432 
    433 const char* FontSettingsSetDefaultFixedFontSizeFunction::GetKey() {
    434   return kPixelSizeKey;
    435 }
    436 
    437 const char* FontSettingsClearMinimumFontSizeFunction::GetPrefName() {
    438   return prefs::kWebKitMinimumFontSize;
    439 }
    440 
    441 const char* FontSettingsGetMinimumFontSizeFunction::GetPrefName() {
    442   return prefs::kWebKitMinimumFontSize;
    443 }
    444 
    445 const char* FontSettingsGetMinimumFontSizeFunction::GetKey() {
    446   return kPixelSizeKey;
    447 }
    448 
    449 const char* FontSettingsSetMinimumFontSizeFunction::GetPrefName() {
    450   return prefs::kWebKitMinimumFontSize;
    451 }
    452 
    453 const char* FontSettingsSetMinimumFontSizeFunction::GetKey() {
    454   return kPixelSizeKey;
    455 }
    456 
    457 }  // namespace extensions
    458