prefs_tab_helper.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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#include "chrome/browser/ui/prefs/prefs_tab_helper.h"
6
7#include <string>
8
9#include "base/prefs/overlay_user_pref_store.h"
10#include "base/prefs/pref_service.h"
11#include "base/strings/string_util.h"
12#include "base/strings/stringprintf.h"
13#include "base/strings/utf_string_conversions.h"
14#include "chrome/browser/browser_process.h"
15#include "chrome/browser/chrome_notification_types.h"
16#include "chrome/browser/profiles/profile.h"
17#include "chrome/browser/renderer_preferences_util.h"
18#include "chrome/common/pref_font_webkit_names.h"
19#include "chrome/common/pref_names.h"
20#include "chrome/common/pref_names_util.h"
21#include "components/user_prefs/pref_registry_syncable.h"
22#include "content/public/browser/notification_details.h"
23#include "content/public/browser/notification_service.h"
24#include "content/public/browser/render_view_host.h"
25#include "content/public/browser/web_contents.h"
26#include "grit/locale_settings.h"
27#include "grit/platform_locale_settings.h"
28#include "third_party/icu/source/common/unicode/uchar.h"
29#include "third_party/icu/source/common/unicode/uscript.h"
30#include "webkit/common/webpreferences.h"
31
32#if defined(OS_POSIX) && !defined(OS_MACOSX) && defined(ENABLE_THEMES)
33#include "chrome/browser/themes/theme_service.h"
34#include "chrome/browser/themes/theme_service_factory.h"
35#endif
36
37using content::WebContents;
38
39DEFINE_WEB_CONTENTS_USER_DATA_KEY(PrefsTabHelper);
40
41namespace {
42
43// The list of prefs we want to observe.
44const char* kPrefsToObserve[] = {
45  prefs::kDefaultCharset,
46  prefs::kWebKitAllowDisplayingInsecureContent,
47  prefs::kWebKitAllowRunningInsecureContent,
48  prefs::kWebKitDefaultFixedFontSize,
49  prefs::kWebKitDefaultFontSize,
50#if defined(OS_ANDROID)
51  prefs::kWebKitFontScaleFactor,
52  prefs::kWebKitForceEnableZoom,
53  prefs::kWebKitPasswordEchoEnabled,
54#endif
55  prefs::kWebKitJavascriptEnabled,
56  prefs::kWebKitJavaEnabled,
57  prefs::kWebKitLoadsImagesAutomatically,
58  prefs::kWebKitMinimumFontSize,
59  prefs::kWebKitMinimumLogicalFontSize,
60  prefs::kWebKitPluginsEnabled,
61  prefs::kWebkitTabsToLinks,
62  prefs::kWebKitUsesUniversalDetector
63};
64
65const int kPrefsToObserveLength = arraysize(kPrefsToObserve);
66
67#if !defined(OS_ANDROID)
68// Registers a preference under the path |pref_name| for each script used for
69// per-script font prefs.
70// For example, for WEBKIT_WEBPREFS_FONTS_SERIF ("fonts.serif"):
71// "fonts.serif.Arab", "fonts.serif.Hang", etc. are registered.
72// |fonts_with_defaults| contains all |pref_names| already registered since they
73// have a specified default value.
74// On Android there are no default values for these properties and there is no
75// way to set them (because extensions are not supported so the Font Settings
76// API cannot be used), so we can avoid registering them altogether.
77void RegisterFontFamilyPrefs(user_prefs::PrefRegistrySyncable* registry,
78                             const std::set<std::string>& fonts_with_defaults) {
79
80  // Expand the font concatenated with script name so this stays at RO memory
81  // rather than allocated in heap.
82  static const char* const kFontFamilyMap[] = {
83#define EXPAND_SCRIPT_FONT(map_name, script_name) map_name "." script_name,
84
85#include "chrome/common/pref_font_script_names-inl.h"
86ALL_FONT_SCRIPTS(WEBKIT_WEBPREFS_FONTS_CURSIVE)
87ALL_FONT_SCRIPTS(WEBKIT_WEBPREFS_FONTS_FANTASY)
88ALL_FONT_SCRIPTS(WEBKIT_WEBPREFS_FONTS_FIXED)
89ALL_FONT_SCRIPTS(WEBKIT_WEBPREFS_FONTS_PICTOGRAPH)
90ALL_FONT_SCRIPTS(WEBKIT_WEBPREFS_FONTS_SANSERIF)
91ALL_FONT_SCRIPTS(WEBKIT_WEBPREFS_FONTS_SERIF)
92ALL_FONT_SCRIPTS(WEBKIT_WEBPREFS_FONTS_STANDARD)
93
94#undef EXPAND_SCRIPT_FONT
95  };
96
97  for (size_t i = 0; i < arraysize(kFontFamilyMap); ++i) {
98    const char* pref_name = kFontFamilyMap[i];
99    if (fonts_with_defaults.find(pref_name) == fonts_with_defaults.end()) {
100      // We haven't already set a default value for this font preference, so set
101      // an empty string as the default.
102      registry->RegisterStringPref(
103          pref_name,
104          std::string(),
105          user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
106    }
107  }
108}
109
110// Registers |obs| to observe per-script font prefs under the path |map_name|.
111// On android, there's no exposed way to change these prefs, so we can save
112// ~715KB of heap and some startup cycles by avoiding observing these prefs
113// since they will never change.
114void RegisterFontFamilyMapObserver(
115    PrefChangeRegistrar* registrar,
116    const char* map_name,
117    const PrefChangeRegistrar::NamedChangeCallback& obs) {
118  DCHECK(StartsWithASCII(map_name, "webkit.webprefs.", true));
119  for (size_t i = 0; i < prefs::kWebKitScriptsForFontFamilyMapsLength; ++i) {
120    const char* script = prefs::kWebKitScriptsForFontFamilyMaps[i];
121    std::string pref_name = base::StringPrintf("%s.%s", map_name, script);
122    registrar->Add(pref_name.c_str(), obs);
123  }
124}
125#endif  // !defined(OS_ANDROID)
126
127struct FontDefault {
128  const char* pref_name;
129  int resource_id;
130};
131
132// Font pref defaults.  The prefs that have defaults vary by platform, since not
133// all platforms have fonts for all scripts for all generic families.
134// TODO(falken): add proper defaults when possible for all
135// platforms/scripts/generic families.
136const FontDefault kFontDefaults[] = {
137  { prefs::kWebKitStandardFontFamily, IDS_STANDARD_FONT_FAMILY },
138  { prefs::kWebKitFixedFontFamily, IDS_FIXED_FONT_FAMILY },
139  { prefs::kWebKitSerifFontFamily, IDS_SERIF_FONT_FAMILY },
140  { prefs::kWebKitSansSerifFontFamily, IDS_SANS_SERIF_FONT_FAMILY },
141  { prefs::kWebKitCursiveFontFamily, IDS_CURSIVE_FONT_FAMILY },
142  { prefs::kWebKitFantasyFontFamily, IDS_FANTASY_FONT_FAMILY },
143  { prefs::kWebKitPictographFontFamily, IDS_PICTOGRAPH_FONT_FAMILY },
144#if defined(OS_CHROMEOS) || defined(OS_MACOSX) || defined(OS_WIN)
145  { prefs::kWebKitStandardFontFamilyJapanese,
146    IDS_STANDARD_FONT_FAMILY_JAPANESE },
147  { prefs::kWebKitFixedFontFamilyJapanese, IDS_FIXED_FONT_FAMILY_JAPANESE },
148  { prefs::kWebKitSerifFontFamilyJapanese, IDS_SERIF_FONT_FAMILY_JAPANESE },
149  { prefs::kWebKitSansSerifFontFamilyJapanese,
150    IDS_SANS_SERIF_FONT_FAMILY_JAPANESE },
151  { prefs::kWebKitStandardFontFamilyKorean, IDS_STANDARD_FONT_FAMILY_KOREAN },
152  { prefs::kWebKitSerifFontFamilyKorean, IDS_SERIF_FONT_FAMILY_KOREAN },
153  { prefs::kWebKitSansSerifFontFamilyKorean,
154    IDS_SANS_SERIF_FONT_FAMILY_KOREAN },
155  { prefs::kWebKitStandardFontFamilySimplifiedHan,
156    IDS_STANDARD_FONT_FAMILY_SIMPLIFIED_HAN },
157  { prefs::kWebKitSerifFontFamilySimplifiedHan,
158    IDS_SERIF_FONT_FAMILY_SIMPLIFIED_HAN },
159  { prefs::kWebKitSansSerifFontFamilySimplifiedHan,
160    IDS_SANS_SERIF_FONT_FAMILY_SIMPLIFIED_HAN },
161  { prefs::kWebKitStandardFontFamilyTraditionalHan,
162    IDS_STANDARD_FONT_FAMILY_TRADITIONAL_HAN },
163  { prefs::kWebKitSerifFontFamilyTraditionalHan,
164    IDS_SERIF_FONT_FAMILY_TRADITIONAL_HAN },
165  { prefs::kWebKitSansSerifFontFamilyTraditionalHan,
166    IDS_SANS_SERIF_FONT_FAMILY_TRADITIONAL_HAN },
167#endif
168#if defined(OS_CHROMEOS)
169  { prefs::kWebKitStandardFontFamilyArabic, IDS_STANDARD_FONT_FAMILY_ARABIC },
170  { prefs::kWebKitSerifFontFamilyArabic, IDS_SERIF_FONT_FAMILY_ARABIC },
171  { prefs::kWebKitSansSerifFontFamilyArabic,
172    IDS_SANS_SERIF_FONT_FAMILY_ARABIC },
173  { prefs::kWebKitFixedFontFamilyKorean, IDS_FIXED_FONT_FAMILY_KOREAN },
174  { prefs::kWebKitFixedFontFamilySimplifiedHan,
175    IDS_FIXED_FONT_FAMILY_SIMPLIFIED_HAN },
176  { prefs::kWebKitFixedFontFamilyTraditionalHan,
177    IDS_FIXED_FONT_FAMILY_TRADITIONAL_HAN },
178#elif defined(OS_WIN)
179  { prefs::kWebKitStandardFontFamilyCyrillic,
180    IDS_STANDARD_FONT_FAMILY_CYRILLIC },
181  { prefs::kWebKitFixedFontFamilyCyrillic, IDS_FIXED_FONT_FAMILY_CYRILLIC },
182  { prefs::kWebKitSerifFontFamilyCyrillic, IDS_SERIF_FONT_FAMILY_CYRILLIC },
183  { prefs::kWebKitSansSerifFontFamilyCyrillic,
184    IDS_SANS_SERIF_FONT_FAMILY_CYRILLIC },
185  { prefs::kWebKitStandardFontFamilyGreek, IDS_STANDARD_FONT_FAMILY_GREEK },
186  { prefs::kWebKitFixedFontFamilyGreek, IDS_FIXED_FONT_FAMILY_GREEK },
187  { prefs::kWebKitSerifFontFamilyGreek, IDS_SERIF_FONT_FAMILY_GREEK },
188  { prefs::kWebKitSansSerifFontFamilyGreek, IDS_SANS_SERIF_FONT_FAMILY_GREEK },
189  { prefs::kWebKitFixedFontFamilyKorean, IDS_FIXED_FONT_FAMILY_KOREAN },
190  { prefs::kWebKitCursiveFontFamilyKorean, IDS_CURSIVE_FONT_FAMILY_KOREAN },
191  { prefs::kWebKitFixedFontFamilySimplifiedHan,
192    IDS_FIXED_FONT_FAMILY_SIMPLIFIED_HAN },
193  { prefs::kWebKitFixedFontFamilyTraditionalHan,
194    IDS_FIXED_FONT_FAMILY_TRADITIONAL_HAN },
195#endif
196};
197
198const size_t kFontDefaultsLength = arraysize(kFontDefaults);
199
200// Returns the script of the font pref |pref_name|.  For example, suppose
201// |pref_name| is "webkit.webprefs.fonts.serif.Hant".  Since the script code for
202// the script name "Hant" is USCRIPT_TRADITIONAL_HAN, the function returns
203// USCRIPT_TRADITIONAL_HAN.  |pref_name| must be a valid font pref name.
204UScriptCode GetScriptOfFontPref(const char* pref_name) {
205  // ICU script names are four letters.
206  static const size_t kScriptNameLength = 4;
207
208  size_t len = strlen(pref_name);
209  DCHECK_GT(len, kScriptNameLength);
210  const char* scriptName = &pref_name[len - kScriptNameLength];
211  int32 code = u_getPropertyValueEnum(UCHAR_SCRIPT, scriptName);
212  DCHECK(code >= 0 && code < USCRIPT_CODE_LIMIT);
213  return static_cast<UScriptCode>(code);
214}
215
216// If |scriptCode| is a member of a family of "similar" script codes, returns
217// the script code in that family that is used in font pref names.  For example,
218// USCRIPT_HANGUL and USCRIPT_KOREAN are considered equivalent for the purposes
219// of font selection.  Chrome uses the script code USCRIPT_HANGUL (script name
220// "Hang") in Korean font pref names (for example,
221// "webkit.webprefs.fonts.serif.Hang").  So, if |scriptCode| is USCRIPT_KOREAN,
222// the function returns USCRIPT_HANGUL.  If |scriptCode| is not a member of such
223// a family, returns |scriptCode|.
224UScriptCode GetScriptForFontPrefMatching(UScriptCode scriptCode) {
225  switch (scriptCode) {
226  case USCRIPT_HIRAGANA:
227  case USCRIPT_KATAKANA:
228  case USCRIPT_KATAKANA_OR_HIRAGANA:
229    return USCRIPT_JAPANESE;
230  case USCRIPT_KOREAN:
231    return USCRIPT_HANGUL;
232  default:
233    return scriptCode;
234  }
235}
236
237// Returns the primary script used by the browser's UI locale.  For example, if
238// the locale is "ru", the function returns USCRIPT_CYRILLIC, and if the locale
239// is "en", the function returns USCRIPT_LATIN.
240UScriptCode GetScriptOfBrowserLocale() {
241  std::string locale = g_browser_process->GetApplicationLocale();
242
243  // For Chinese locales, uscript_getCode() just returns USCRIPT_HAN but our
244  // per-script fonts are for USCRIPT_SIMPLIFIED_HAN and
245  // USCRIPT_TRADITIONAL_HAN.
246  if (locale == "zh-CN")
247    return USCRIPT_SIMPLIFIED_HAN;
248  if (locale == "zh-TW")
249    return USCRIPT_TRADITIONAL_HAN;
250
251  UScriptCode code = USCRIPT_INVALID_CODE;
252  UErrorCode err = U_ZERO_ERROR;
253  uscript_getCode(locale.c_str(), &code, 1, &err);
254
255  // Ignore the error that multiple scripts could be returned, since we only
256  // want one script.
257  if (U_FAILURE(err) && err != U_BUFFER_OVERFLOW_ERROR)
258    code = USCRIPT_INVALID_CODE;
259  return GetScriptForFontPrefMatching(code);
260}
261
262// Sets a font family pref in |prefs| to |pref_value|.
263void OverrideFontFamily(WebPreferences* prefs,
264                        const std::string& generic_family,
265                        const std::string& script,
266                        const std::string& pref_value) {
267  webkit_glue::ScriptFontFamilyMap* map = NULL;
268  if (generic_family == "standard")
269    map = &prefs->standard_font_family_map;
270  else if (generic_family == "fixed")
271    map = &prefs->fixed_font_family_map;
272  else if (generic_family == "serif")
273    map = &prefs->serif_font_family_map;
274  else if (generic_family == "sansserif")
275    map = &prefs->sans_serif_font_family_map;
276  else if (generic_family == "cursive")
277    map = &prefs->cursive_font_family_map;
278  else if (generic_family == "fantasy")
279    map = &prefs->fantasy_font_family_map;
280  else if (generic_family == "pictograph")
281    map = &prefs->pictograph_font_family_map;
282  else
283    NOTREACHED() << "Unknown generic font family: " << generic_family;
284  (*map)[script] = base::UTF8ToUTF16(pref_value);
285}
286
287}  // namespace
288
289PrefsTabHelper::PrefsTabHelper(WebContents* contents)
290    : web_contents_(contents),
291      weak_ptr_factory_(this) {
292  PrefService* prefs = GetProfile()->GetPrefs();
293  pref_change_registrar_.Init(prefs);
294  if (prefs) {
295    base::Closure renderer_callback = base::Bind(
296        &PrefsTabHelper::UpdateRendererPreferences, base::Unretained(this));
297    pref_change_registrar_.Add(prefs::kAcceptLanguages, renderer_callback);
298    pref_change_registrar_.Add(prefs::kDefaultZoomLevel, renderer_callback);
299    pref_change_registrar_.Add(prefs::kEnableDoNotTrack, renderer_callback);
300    pref_change_registrar_.Add(prefs::kEnableReferrers, renderer_callback);
301
302#if !defined(OS_MACOSX)
303    pref_change_registrar_.Add(prefs::kFullscreenAllowed, renderer_callback);
304#endif
305
306    PrefChangeRegistrar::NamedChangeCallback webkit_callback = base::Bind(
307        &PrefsTabHelper::OnWebPrefChanged, base::Unretained(this));
308    for (int i = 0; i < kPrefsToObserveLength; ++i) {
309      const char* pref_name = kPrefsToObserve[i];
310      DCHECK(std::string(pref_name) == prefs::kDefaultCharset ||
311             StartsWithASCII(pref_name, "webkit.webprefs.", true));
312      pref_change_registrar_.Add(pref_name, webkit_callback);
313    }
314
315#if !defined(OS_ANDROID)
316    RegisterFontFamilyMapObserver(&pref_change_registrar_,
317                                  prefs::kWebKitStandardFontFamilyMap,
318                                  webkit_callback);
319    RegisterFontFamilyMapObserver(&pref_change_registrar_,
320                                  prefs::kWebKitFixedFontFamilyMap,
321                                  webkit_callback);
322    RegisterFontFamilyMapObserver(&pref_change_registrar_,
323                                  prefs::kWebKitSerifFontFamilyMap,
324                                  webkit_callback);
325    RegisterFontFamilyMapObserver(&pref_change_registrar_,
326                                  prefs::kWebKitSansSerifFontFamilyMap,
327                                  webkit_callback);
328    RegisterFontFamilyMapObserver(&pref_change_registrar_,
329                                  prefs::kWebKitCursiveFontFamilyMap,
330                                  webkit_callback);
331    RegisterFontFamilyMapObserver(&pref_change_registrar_,
332                                  prefs::kWebKitFantasyFontFamilyMap,
333                                  webkit_callback);
334    RegisterFontFamilyMapObserver(&pref_change_registrar_,
335                                  prefs::kWebKitPictographFontFamilyMap,
336                                  webkit_callback);
337#endif  // !defined(OS_ANDROID)
338  }
339
340  renderer_preferences_util::UpdateFromSystemSettings(
341      web_contents_->GetMutableRendererPrefs(), GetProfile());
342
343#if defined(OS_POSIX) && !defined(OS_MACOSX) && defined(ENABLE_THEMES)
344  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
345                 content::Source<ThemeService>(
346                     ThemeServiceFactory::GetForProfile(GetProfile())));
347#endif
348#if defined(USE_AURA)
349  registrar_.Add(this,
350                 chrome::NOTIFICATION_BROWSER_FLING_CURVE_PARAMETERS_CHANGED,
351                 content::NotificationService::AllSources());
352#endif
353}
354
355PrefsTabHelper::~PrefsTabHelper() {
356}
357
358// static
359void PrefsTabHelper::InitIncognitoUserPrefStore(
360    OverlayUserPrefStore* pref_store) {
361  // List of keys that cannot be changed in the user prefs file by the incognito
362  // profile.  All preferences that store information about the browsing history
363  // or behavior of the user should have this property.
364  pref_store->RegisterOverlayPref(prefs::kBrowserWindowPlacement);
365  pref_store->RegisterOverlayPref(prefs::kSaveFileDefaultDirectory);
366#if defined(OS_ANDROID) || defined(OS_IOS)
367  pref_store->RegisterOverlayPref(prefs::kProxy);
368#endif  // defined(OS_ANDROID) || defined(OS_IOS)
369}
370
371// static
372void PrefsTabHelper::RegisterProfilePrefs(
373    user_prefs::PrefRegistrySyncable* registry) {
374  WebPreferences pref_defaults;
375  registry->RegisterBooleanPref(
376      prefs::kWebKitJavascriptEnabled,
377      pref_defaults.javascript_enabled,
378      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
379  registry->RegisterBooleanPref(
380      prefs::kWebKitWebSecurityEnabled,
381      pref_defaults.web_security_enabled,
382      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
383  registry->RegisterBooleanPref(
384      prefs::kWebKitJavascriptCanOpenWindowsAutomatically,
385      true,
386      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
387  registry->RegisterBooleanPref(
388      prefs::kWebKitLoadsImagesAutomatically,
389      pref_defaults.loads_images_automatically,
390      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
391  registry->RegisterBooleanPref(
392      prefs::kWebKitPluginsEnabled,
393      pref_defaults.plugins_enabled,
394      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
395  registry->RegisterBooleanPref(
396      prefs::kWebKitDomPasteEnabled,
397      pref_defaults.dom_paste_enabled,
398      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
399  registry->RegisterBooleanPref(
400      prefs::kWebKitShrinksStandaloneImagesToFit,
401      pref_defaults.shrinks_standalone_images_to_fit,
402      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
403  registry->RegisterDictionaryPref(
404      prefs::kWebKitInspectorSettings,
405      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
406  registry->RegisterBooleanPref(
407      prefs::kWebKitTextAreasAreResizable,
408      pref_defaults.text_areas_are_resizable,
409      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
410  registry->RegisterBooleanPref(
411      prefs::kWebKitJavaEnabled,
412      pref_defaults.java_enabled,
413      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
414  registry->RegisterBooleanPref(
415      prefs::kWebkitTabsToLinks,
416      pref_defaults.tabs_to_links,
417      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
418  registry->RegisterBooleanPref(
419      prefs::kWebKitAllowRunningInsecureContent,
420      false,
421      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
422  registry->RegisterBooleanPref(
423      prefs::kWebKitAllowDisplayingInsecureContent,
424      true,
425      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
426  registry->RegisterBooleanPref(
427      prefs::kEnableReferrers,
428      true,
429      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
430#if defined(OS_ANDROID)
431  registry->RegisterDoublePref(
432      prefs::kWebKitFontScaleFactor,
433      1.0,
434      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
435  registry->RegisterBooleanPref(
436      prefs::kWebKitForceEnableZoom,
437      pref_defaults.force_enable_zoom,
438      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
439  registry->RegisterBooleanPref(
440      prefs::kWebKitPasswordEchoEnabled,
441      pref_defaults.password_echo_enabled,
442      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
443#endif
444  registry->RegisterLocalizedStringPref(
445      prefs::kAcceptLanguages,
446      IDS_ACCEPT_LANGUAGES,
447      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
448  registry->RegisterLocalizedStringPref(
449      prefs::kDefaultCharset,
450      IDS_DEFAULT_ENCODING,
451      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
452
453  // Register font prefs that have defaults.
454  std::set<std::string> fonts_with_defaults;
455  UScriptCode browser_script = GetScriptOfBrowserLocale();
456  for (size_t i = 0; i < kFontDefaultsLength; ++i) {
457    const FontDefault& pref = kFontDefaults[i];
458    UScriptCode pref_script = GetScriptOfFontPref(pref.pref_name);
459
460    // Suppress this default font pref value if it is for the primary script of
461    // the browser's UI locale.  For example, if the pref is for the sans-serif
462    // font for the Cyrillic script, and the browser locale is "ru" (Russian),
463    // the default is suppressed.  Otherwise, the default would override the
464    // user's font preferences when viewing pages in their native language.
465    // This is because users have no way yet of customizing their per-script
466    // font preferences.  The font prefs accessible in the options UI are for
467    // the default, unknown script; these prefs have less priority than the
468    // per-script font prefs when the script of the content is known.  This code
469    // can possibly be removed later if users can easily access per-script font
470    // prefs (e.g., via the extensions workflow), or the problem turns out to
471    // not be really critical after all.
472    if (browser_script != pref_script) {
473      registry->RegisterLocalizedStringPref(
474          pref.pref_name,
475          pref.resource_id,
476          user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
477      fonts_with_defaults.insert(pref.pref_name);
478    }
479  }
480
481  // Register per-script font prefs that don't have defaults.
482#if !defined(OS_ANDROID)
483  RegisterFontFamilyPrefs(registry, fonts_with_defaults);
484#endif
485
486  registry->RegisterLocalizedIntegerPref(
487      prefs::kWebKitDefaultFontSize,
488      IDS_DEFAULT_FONT_SIZE,
489      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
490  registry->RegisterLocalizedIntegerPref(
491      prefs::kWebKitDefaultFixedFontSize,
492      IDS_DEFAULT_FIXED_FONT_SIZE,
493      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
494  registry->RegisterLocalizedIntegerPref(
495      prefs::kWebKitMinimumFontSize,
496      IDS_MINIMUM_FONT_SIZE,
497      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
498  registry->RegisterLocalizedIntegerPref(
499      prefs::kWebKitMinimumLogicalFontSize,
500      IDS_MINIMUM_LOGICAL_FONT_SIZE,
501      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
502  registry->RegisterLocalizedBooleanPref(
503      prefs::kWebKitUsesUniversalDetector,
504      IDS_USES_UNIVERSAL_DETECTOR,
505      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
506  registry->RegisterLocalizedStringPref(
507      prefs::kStaticEncodings,
508      IDS_STATIC_ENCODING_LIST,
509      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
510  registry->RegisterStringPref(
511      prefs::kRecentlySelectedEncoding,
512      std::string(),
513      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
514}
515
516void PrefsTabHelper::Observe(int type,
517                             const content::NotificationSource& source,
518                             const content::NotificationDetails& details) {
519#if defined(OS_POSIX) && !defined(OS_MACOSX) && defined(ENABLE_THEMES)
520  if (type == chrome::NOTIFICATION_BROWSER_THEME_CHANGED) {
521    UpdateRendererPreferences();
522    return;
523  }
524#endif
525
526#if defined(USE_AURA)
527  if (type == chrome::NOTIFICATION_BROWSER_FLING_CURVE_PARAMETERS_CHANGED) {
528    UpdateRendererPreferences();
529    return;
530  }
531#endif  // defined(USE_AURA)
532
533  NOTREACHED();
534}
535
536void PrefsTabHelper::UpdateWebPreferences() {
537  web_contents_->GetRenderViewHost()->UpdateWebkitPreferences(
538      web_contents_->GetRenderViewHost()->GetWebkitPreferences());
539}
540
541void PrefsTabHelper::UpdateRendererPreferences() {
542  renderer_preferences_util::UpdateFromSystemSettings(
543      web_contents_->GetMutableRendererPrefs(), GetProfile());
544  web_contents_->GetRenderViewHost()->SyncRendererPrefs();
545}
546
547Profile* PrefsTabHelper::GetProfile() {
548  return Profile::FromBrowserContext(web_contents_->GetBrowserContext());
549}
550
551void PrefsTabHelper::OnWebPrefChanged(const std::string& pref_name) {
552  // When a font family pref's value goes from non-empty to the empty string, we
553  // must add it to the usual WebPreferences struct passed to the renderer.
554  //
555  // The empty string means to fall back to the pref for the Common script
556  // ("Zyyy").  For example, if chrome.fonts.serif.Cyrl is the empty string, it
557  // means to use chrome.fonts.serif.Zyyy for Cyrillic script. Prefs that are
558  // the empty string are normally not passed to WebKit, since there are so many
559  // of them that it would cause a performance regression. Not passing the pref
560  // is normally okay since WebKit does the desired fallback behavior regardless
561  // of whether the empty string is passed or the pref is not passed at all. But
562  // if the pref has changed from non-empty to the empty string, we must let
563  // WebKit know.
564  std::string generic_family;
565  std::string script;
566  if (pref_names_util::ParseFontNamePrefPath(pref_name,
567                                             &generic_family,
568                                             &script)) {
569    PrefService* prefs = GetProfile()->GetPrefs();
570    std::string pref_value = prefs->GetString(pref_name.c_str());
571    if (pref_value.empty()) {
572      WebPreferences web_prefs =
573          web_contents_->GetRenderViewHost()->GetWebkitPreferences();
574      OverrideFontFamily(&web_prefs, generic_family, script, std::string());
575      web_contents_->GetRenderViewHost()->UpdateWebkitPreferences(web_prefs);
576      return;
577    }
578  }
579
580  UpdateWebPreferences();
581}
582