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