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 36namespace extensions { 37 38namespace fonts = api::font_settings; 39 40namespace { 41 42const char kFontIdKey[] = "fontId"; 43const char kGenericFamilyKey[] = "genericFamily"; 44const char kLevelOfControlKey[] = "levelOfControl"; 45const char kDisplayNameKey[] = "displayName"; 46const char kPixelSizeKey[] = "pixelSize"; 47const char kScriptKey[] = "script"; 48 49const char kSetFromIncognitoError[] = 50 "Can't modify regular settings from an incognito context."; 51 52// Format for font name preference paths. 53const 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. 57std::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. 71std::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|. 83void 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 96FontSettingsEventRouter::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 130FontSettingsEventRouter::~FontSettingsEventRouter() {} 131 132void 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 141void 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 154void 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 185void 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 207FontSettingsAPI::FontSettingsAPI(content::BrowserContext* context) 208 : font_settings_event_router_( 209 new FontSettingsEventRouter(Profile::FromBrowserContext(context))) {} 210 211FontSettingsAPI::~FontSettingsAPI() { 212} 213 214static base::LazyInstance<BrowserContextKeyedAPIFactory<FontSettingsAPI> > 215 g_factory = LAZY_INSTANCE_INITIALIZER; 216 217// static 218BrowserContextKeyedAPIFactory<FontSettingsAPI>* 219FontSettingsAPI::GetFactoryInstance() { 220 return g_factory.Pointer(); 221} 222 223bool 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 245bool 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 276bool 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 301bool FontSettingsGetFontListFunction::RunAsync() { 302 content::GetFontListAsync( 303 Bind(&FontSettingsGetFontListFunction::FontListHasLoaded, this)); 304 return true; 305} 306 307void FontSettingsGetFontListFunction::FontListHasLoaded( 308 scoped_ptr<base::ListValue> list) { 309 bool success = CopyFontsToResult(list.get()); 310 SendResponse(success); 311} 312 313bool 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 346bool 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 357bool 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 377bool 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 397const char* FontSettingsClearDefaultFontSizeFunction::GetPrefName() { 398 return prefs::kWebKitDefaultFontSize; 399} 400 401const char* FontSettingsGetDefaultFontSizeFunction::GetPrefName() { 402 return prefs::kWebKitDefaultFontSize; 403} 404 405const char* FontSettingsGetDefaultFontSizeFunction::GetKey() { 406 return kPixelSizeKey; 407} 408 409const char* FontSettingsSetDefaultFontSizeFunction::GetPrefName() { 410 return prefs::kWebKitDefaultFontSize; 411} 412 413const char* FontSettingsSetDefaultFontSizeFunction::GetKey() { 414 return kPixelSizeKey; 415} 416 417const char* FontSettingsClearDefaultFixedFontSizeFunction::GetPrefName() { 418 return prefs::kWebKitDefaultFixedFontSize; 419} 420 421const char* FontSettingsGetDefaultFixedFontSizeFunction::GetPrefName() { 422 return prefs::kWebKitDefaultFixedFontSize; 423} 424 425const char* FontSettingsGetDefaultFixedFontSizeFunction::GetKey() { 426 return kPixelSizeKey; 427} 428 429const char* FontSettingsSetDefaultFixedFontSizeFunction::GetPrefName() { 430 return prefs::kWebKitDefaultFixedFontSize; 431} 432 433const char* FontSettingsSetDefaultFixedFontSizeFunction::GetKey() { 434 return kPixelSizeKey; 435} 436 437const char* FontSettingsClearMinimumFontSizeFunction::GetPrefName() { 438 return prefs::kWebKitMinimumFontSize; 439} 440 441const char* FontSettingsGetMinimumFontSizeFunction::GetPrefName() { 442 return prefs::kWebKitMinimumFontSize; 443} 444 445const char* FontSettingsGetMinimumFontSizeFunction::GetKey() { 446 return kPixelSizeKey; 447} 448 449const char* FontSettingsSetMinimumFontSizeFunction::GetPrefName() { 450 return prefs::kWebKitMinimumFontSize; 451} 452 453const char* FontSettingsSetMinimumFontSizeFunction::GetKey() { 454 return kPixelSizeKey; 455} 456 457} // namespace extensions 458