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(®istrar_, 115 prefs::kWebKitStandardFontFamilyMap, this); 116 RegisterFontFamilyMapObserver(®istrar_, 117 prefs::kWebKitSerifFontFamilyMap, this); 118 RegisterFontFamilyMapObserver(®istrar_, 119 prefs::kWebKitSansSerifFontFamilyMap, this); 120 RegisterFontFamilyMapObserver(®istrar_, 121 prefs::kWebKitFixedFontFamilyMap, this); 122 RegisterFontFamilyMapObserver(®istrar_, 123 prefs::kWebKitCursiveFontFamilyMap, this); 124 RegisterFontFamilyMapObserver(®istrar_, 125 prefs::kWebKitFantasyFontFamilyMap, this); 126 RegisterFontFamilyMapObserver(®istrar_, 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