text: // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "chrome/browser/ui/prefs/prefs_tab_helper.h"
  
  #include <stddef.h>
  #include <stdint.h>
  
  #include <set>
  #include <string>
  
  #include "base/command_line.h"
  #include "base/macros.h"
  #include "base/memory/singleton.h"
  #include "base/strings/string_number_conversions.h"
  #include "base/strings/string_util.h"
  #include "base/strings/stringprintf.h"
  #include "base/strings/utf_string_conversions.h"
  #include "base/threading/thread_task_runner_handle.h"
  #include "build/build_config.h"
  #include "chrome/browser/browser_process.h"
  #include "chrome/browser/chrome_notification_types.h"
  #include "chrome/browser/font_pref_change_notifier_factory.h"
  #include "chrome/browser/profiles/incognito_helpers.h"
  #include "chrome/browser/profiles/profile.h"
  #include "chrome/browser/renderer_preferences_util.h"
  #include "chrome/common/pref_font_webkit_names.h"
  #include "chrome/common/pref_names.h"
  #include "chrome/common/pref_names_util.h"
  #include "chrome/grit/platform_locale_settings.h"
  #include "components/keyed_service/content/browser_context_dependency_manager.h"
  #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
  #include "components/keyed_service/core/keyed_service.h"
  #include "components/pref_registry/pref_registry_syncable.h"
  #include "components/prefs/overlay_user_pref_store.h"
  #include "components/prefs/pref_change_registrar.h"
  #include "components/prefs/pref_service.h"
  #include "components/proxy_config/proxy_config_pref_names.h"
  #include "components/strings/grit/components_locale_settings.h"
  #include "content/public/browser/notification_details.h"
  #include "content/public/browser/notification_service.h"
  #include "content/public/browser/render_view_host.h"
  #include "content/public/browser/web_contents.h"
  #include "content/public/common/renderer_preferences.h"
  #include "content/public/common/web_preferences.h"
  #include "extensions/buildflags/buildflags.h"
  #include "media/media_buildflags.h"
  #include "third_party/icu/source/common/unicode/uchar.h"
  #include "third_party/icu/source/common/unicode/uscript.h"
  #include "ui/base/l10n/l10n_util.h"
  
  #if !defined(OS_ANDROID)
  #include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h"
  #endif
  
  #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
  #include "chrome/browser/themes/theme_service.h"
  #include "chrome/browser/themes/theme_service_factory.h"
  #endif
  
  using content::WebContents;
  using content::WebPreferences;
  
  DEFINE_WEB_CONTENTS_USER_DATA_KEY(PrefsTabHelper);
  
  namespace {
  
  // The list of prefs we want to observe.
  const char* const kWebPrefsToObserve[] = {
  #if BUILDFLAG(ENABLE_EXTENSIONS)
    prefs::kAnimationPolicy,
  #endif
    prefs::kDataSaverEnabled,
    prefs::kDefaultCharset,
    prefs::kDisable3DAPIs,
    prefs::kEnableHyperlinkAuditing,
    prefs::kWebKitAllowRunningInsecureContent,
    prefs::kWebKitDefaultFixedFontSize,
    prefs::kWebKitDefaultFontSize,
    prefs::kWebKitDomPasteEnabled,
  #if defined(OS_ANDROID)
    prefs::kWebKitFontScaleFactor,
    prefs::kWebKitNightModeFactor,
    prefs::kWebKitNightModeEnabled,
    prefs::kWebKitNightModeGrayscaleEnabled,
    prefs::kWebKitForceEnableZoom,
    prefs::kWebKitPasswordEchoEnabled,
  #endif
    prefs::kWebKitJavascriptEnabled,
    prefs::kWebKitLoadsImagesAutomatically,
    prefs::kWebKitMinimumFontSize,
    prefs::kWebKitMinimumLogicalFontSize,
    prefs::kWebKitPluginsEnabled,
    prefs::kWebkitTabsToLinks,
    prefs::kWebKitTextAreasAreResizable,
    prefs::kWebKitWebSecurityEnabled,
  };
  
  const int kWebPrefsToObserveLength = arraysize(kWebPrefsToObserve);
  
  #if !defined(OS_ANDROID)
  // Registers a preference under the path |pref_name| for each script used for
  // per-script font prefs.
  // For example, for WEBKIT_WEBPREFS_FONTS_SERIF ("fonts.serif"):
  // "fonts.serif.Arab", "fonts.serif.Hang", etc. are registered.
  // |fonts_with_defaults| contains all |pref_names| already registered since they
  // have a specified default value.
  // On Android there are no default values for these properties and there is no
  // way to set them (because extensions are not supported so the Font Settings
  // API cannot be used), so we can avoid registering them altogether.
  void RegisterFontFamilyPrefs(user_prefs::PrefRegistrySyncable* registry,
                               const std::set<std::string>& fonts_with_defaults) {
    // Expand the font concatenated with script name so this stays at RO memory
    // rather than allocated in heap.
    static const char* const kFontFamilyMap[] = {
  #define EXPAND_SCRIPT_FONT(map_name, script_name) map_name "." script_name,
  
  #include "chrome/common/pref_font_script_names-inl.h"
  ALL_FONT_SCRIPTS(WEBKIT_WEBPREFS_FONTS_CURSIVE)
  ALL_FONT_SCRIPTS(WEBKIT_WEBPREFS_FONTS_FANTASY)
  ALL_FONT_SCRIPTS(WEBKIT_WEBPREFS_FONTS_FIXED)
  ALL_FONT_SCRIPTS(WEBKIT_WEBPREFS_FONTS_PICTOGRAPH)
  ALL_FONT_SCRIPTS(WEBKIT_WEBPREFS_FONTS_SANSERIF)
  ALL_FONT_SCRIPTS(WEBKIT_WEBPREFS_FONTS_SERIF)
  ALL_FONT_SCRIPTS(WEBKIT_WEBPREFS_FONTS_STANDARD)
  
  #undef EXPAND_SCRIPT_FONT
    };
  
    for (size_t i = 0; i < arraysize(kFontFamilyMap); ++i) {
      const char* pref_name = kFontFamilyMap[i];
      if (fonts_with_defaults.find(pref_name) == fonts_with_defaults.end()) {
        // We haven't already set a default value for this font preference, so set
        // an empty string as the default.
        registry->RegisterStringPref(pref_name, std::string());
      }
    }
  }
  #endif  // !defined(OS_ANDROID)
  
  #if defined(OS_WIN)
  // On Windows with antialising we want to use an alternate fixed font like
  // Consolas, which looks much better than Courier New.
  bool ShouldUseAlternateDefaultFixedFont(const std::string& script) {
    if (!base::StartsWith(script, "courier",
                          base::CompareCase::INSENSITIVE_ASCII))
      return false;
    UINT smooth_type = 0;
    SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smooth_type, 0);
    return smooth_type == FE_FONTSMOOTHINGCLEARTYPE;
  }
  #endif
  
  struct FontDefault {
    const char* pref_name;
    int resource_id;
  };
  
  // Font pref defaults.  The prefs that have defaults vary by platform, since not
  // all platforms have fonts for all scripts for all generic families.
  // TODO(falken): add proper defaults when possible for all
  // platforms/scripts/generic families.
  const FontDefault kFontDefaults[] = {
      {prefs::kWebKitStandardFontFamily, IDS_STANDARD_FONT_FAMILY},
      {prefs::kWebKitFixedFontFamily, IDS_FIXED_FONT_FAMILY},
      {prefs::kWebKitSerifFontFamily, IDS_SERIF_FONT_FAMILY},
      {prefs::kWebKitSansSerifFontFamily, IDS_SANS_SERIF_FONT_FAMILY},
      {prefs::kWebKitCursiveFontFamily, IDS_CURSIVE_FONT_FAMILY},
      {prefs::kWebKitFantasyFontFamily, IDS_FANTASY_FONT_FAMILY},
      {prefs::kWebKitPictographFontFamily, IDS_PICTOGRAPH_FONT_FAMILY},
  #if defined(OS_CHROMEOS) || defined(OS_MACOSX) || defined(OS_WIN)
      {prefs::kWebKitStandardFontFamilyJapanese,
       IDS_STANDARD_FONT_FAMILY_JAPANESE},
      {prefs::kWebKitFixedFontFamilyJapanese, IDS_FIXED_FONT_FAMILY_JAPANESE},
      {prefs::kWebKitSerifFontFamilyJapanese, IDS_SERIF_FONT_FAMILY_JAPANESE},
      {prefs::kWebKitSansSerifFontFamilyJapanese,
       IDS_SANS_SERIF_FONT_FAMILY_JAPANESE},
      {prefs::kWebKitStandardFontFamilyKorean, IDS_STANDARD_FONT_FAMILY_KOREAN},
      {prefs::kWebKitSerifFontFamilyKorean, IDS_SERIF_FONT_FAMILY_KOREAN},
      {prefs::kWebKitSansSerifFontFamilyKorean,
       IDS_SANS_SERIF_FONT_FAMILY_KOREAN},
      {prefs::kWebKitStandardFontFamilySimplifiedHan,
       IDS_STANDARD_FONT_FAMILY_SIMPLIFIED_HAN},
      {prefs::kWebKitSerifFontFamilySimplifiedHan,
       IDS_SERIF_FONT_FAMILY_SIMPLIFIED_HAN},
      {prefs::kWebKitSansSerifFontFamilySimplifiedHan,
       IDS_SANS_SERIF_FONT_FAMILY_SIMPLIFIED_HAN},
      {prefs::kWebKitStandardFontFamilyTraditionalHan,
       IDS_STANDARD_FONT_FAMILY_TRADITIONAL_HAN},
      {prefs::kWebKitSerifFontFamilyTraditionalHan,
       IDS_SERIF_FONT_FAMILY_TRADITIONAL_HAN},
      {prefs::kWebKitSansSerifFontFamilyTraditionalHan,
       IDS_SANS_SERIF_FONT_FAMILY_TRADITIONAL_HAN},
  #endif
  #if defined(OS_MACOSX) || defined(OS_WIN)
      {prefs::kWebKitCursiveFontFamilySimplifiedHan,
       IDS_CURSIVE_FONT_FAMILY_SIMPLIFIED_HAN},
      {prefs::kWebKitCursiveFontFamilyTraditionalHan,
       IDS_CURSIVE_FONT_FAMILY_TRADITIONAL_HAN},
  #endif
  #if defined(OS_CHROMEOS)
      {prefs::kWebKitStandardFontFamilyArabic, IDS_STANDARD_FONT_FAMILY_ARABIC},
      {prefs::kWebKitSerifFontFamilyArabic, IDS_SERIF_FONT_FAMILY_ARABIC},
      {prefs::kWebKitSansSerifFontFamilyArabic,
       IDS_SANS_SERIF_FONT_FAMILY_ARABIC},
      {prefs::kWebKitFixedFontFamilyKorean, IDS_FIXED_FONT_FAMILY_KOREAN},
      {prefs::kWebKitFixedFontFamilySimplifiedHan,
       IDS_FIXED_FONT_FAMILY_SIMPLIFIED_HAN},
      {prefs::kWebKitFixedFontFamilyTraditionalHan,
       IDS_FIXED_FONT_FAMILY_TRADITIONAL_HAN},
  #elif defined(OS_WIN)
      {prefs::kWebKitFixedFontFamilyArabic, IDS_FIXED_FONT_FAMILY_ARABIC},
      {prefs::kWebKitSansSerifFontFamilyArabic,
       IDS_SANS_SERIF_FONT_FAMILY_ARABIC},
      {prefs::kWebKitStandardFontFamilyCyrillic,
       IDS_STANDARD_FONT_FAMILY_CYRILLIC},
      {prefs::kWebKitFixedFontFamilyCyrillic, IDS_FIXED_FONT_FAMILY_CYRILLIC},
      {prefs::kWebKitSerifFontFamilyCyrillic, IDS_SERIF_FONT_FAMILY_CYRILLIC},
      {prefs::kWebKitSansSerifFontFamilyCyrillic,
       IDS_SANS_SERIF_FONT_FAMILY_CYRILLIC},
      {prefs::kWebKitStandardFontFamilyGreek, IDS_STANDARD_FONT_FAMILY_GREEK},
      {prefs::kWebKitFixedFontFamilyGreek, IDS_FIXED_FONT_FAMILY_GREEK},
      {prefs::kWebKitSerifFontFamilyGreek, IDS_SERIF_FONT_FAMILY_GREEK},
      {prefs::kWebKitSansSerifFontFamilyGreek, IDS_SANS_SERIF_FONT_FAMILY_GREEK},
      {prefs::kWebKitFixedFontFamilyKorean, IDS_FIXED_FONT_FAMILY_KOREAN},
      {prefs::kWebKitCursiveFontFamilyKorean, IDS_CURSIVE_FONT_FAMILY_KOREAN},
      {prefs::kWebKitFixedFontFamilySimplifiedHan,
       IDS_FIXED_FONT_FAMILY_SIMPLIFIED_HAN},
      {prefs::kWebKitFixedFontFamilyTraditionalHan,
       IDS_FIXED_FONT_FAMILY_TRADITIONAL_HAN},
  #endif
  };
  
  const size_t kFontDefaultsLength = arraysize(kFontDefaults);
  
  // Returns the script of the font pref |pref_name|.  For example, suppose
  // |pref_name| is "webkit.webprefs.fonts.serif.Hant".  Since the script code for
  // the script name "Hant" is USCRIPT_TRADITIONAL_HAN, the function returns
  // USCRIPT_TRADITIONAL_HAN.  |pref_name| must be a valid font pref name.
  UScriptCode GetScriptOfFontPref(const char* pref_name) {
    // ICU script names are four letters.
    static const size_t kScriptNameLength = 4;
  
    size_t len = strlen(pref_name);
    DCHECK_GT(len, kScriptNameLength);
    const char* scriptName = &pref_name[len - kScriptNameLength];
    int32_t code = u_getPropertyValueEnum(UCHAR_SCRIPT, scriptName);
    DCHECK(code >= 0 && code < USCRIPT_CODE_LIMIT);
    return static_cast<UScriptCode>(code);
  }
  
  // Returns the primary script used by the browser's UI locale.  For example, if
  // the locale is "ru", the function returns USCRIPT_CYRILLIC, and if the locale
  // is "en", the function returns USCRIPT_LATIN.
  UScriptCode GetScriptOfBrowserLocale() {
    std::string locale = g_browser_process->GetApplicationLocale();
  
    // For Chinese locales, uscript_getCode() just returns USCRIPT_HAN but our
    // per-script fonts are for USCRIPT_SIMPLIFIED_HAN and
    // USCRIPT_TRADITIONAL_HAN.
    if (locale == "zh-CN")
      return USCRIPT_SIMPLIFIED_HAN;
    if (locale == "zh-TW")
      return USCRIPT_TRADITIONAL_HAN;
    // For Korean and Japanese, multiple scripts are returned by
    // |uscript_getCode|, but we're passing a one entry buffer leading
    // the buffer to be filled by USCRIPT_INVALID_CODE. We need to
    // hard-code the results for them.
    if (locale == "ko")
      return USCRIPT_HANGUL;
    if (locale == "ja")
      return USCRIPT_JAPANESE;
  
    UScriptCode code = USCRIPT_INVALID_CODE;
    UErrorCode err = U_ZERO_ERROR;
    uscript_getCode(locale.c_str(), &code, 1, &err);
  
    if (U_FAILURE(err))
      code = USCRIPT_INVALID_CODE;
    return code;
  }
  
  // Sets a font family pref in |prefs| to |pref_value|.
  void OverrideFontFamily(WebPreferences* prefs,
                          const std::string& generic_family,
                          const std::string& script,
                          const std::string& pref_value) {
    content::ScriptFontFamilyMap* map = NULL;
    if (generic_family == "standard")
      map = &prefs->standard_font_family_map;
    else if (generic_family == "fixed")
      map = &prefs->fixed_font_family_map;
    else if (generic_family == "serif")
      map = &prefs->serif_font_family_map;
    else if (generic_family == "sansserif")
      map = &prefs->sans_serif_font_family_map;
    else if (generic_family == "cursive")
      map = &prefs->cursive_font_family_map;
    else if (generic_family == "fantasy")
      map = &prefs->fantasy_font_family_map;
    else if (generic_family == "pictograph")
      map = &prefs->pictograph_font_family_map;
    else
      NOTREACHED() << "Unknown generic font family: " << generic_family;
    (*map)[script] = base::UTF8ToUTF16(pref_value);
  }
  
  #if !defined(OS_ANDROID)
  void RegisterLocalizedFontPref(user_prefs::PrefRegistrySyncable* registry,
                                 const char* path,
                                 int default_message_id) {
    int val = 0;
    bool success = base::StringToInt(l10n_util::GetStringUTF8(
        default_message_id), &val);
    DCHECK(success);
    registry->RegisterIntegerPref(path, val);
  }
  #endif
  
  }  // namespace
  
  // Watching all these settings per tab is slow when a user has a lot of tabs and
  // and they use session restore. So watch them once per profile.
  // http://crbug.com/452693
  class PrefWatcher : public KeyedService {
   public:
    explicit PrefWatcher(Profile* profile) : profile_(profile) {
      pref_change_registrar_.Init(profile_->GetPrefs());
  
      base::Closure renderer_callback = base::Bind(
          &PrefWatcher::UpdateRendererPreferences, base::Unretained(this));
      pref_change_registrar_.Add(prefs::kAcceptLanguages, renderer_callback);
      pref_change_registrar_.Add(prefs::kEnableDoNotTrack, renderer_callback);
      pref_change_registrar_.Add(prefs::kEnableReferrers, renderer_callback);
      pref_change_registrar_.Add(prefs::kEnableEncryptedMedia, renderer_callback);
      pref_change_registrar_.Add(prefs::kWebRTCMultipleRoutesEnabled,
                                 renderer_callback);
      pref_change_registrar_.Add(prefs::kWebRTCNonProxiedUdpEnabled,
                                 renderer_callback);
      pref_change_registrar_.Add(prefs::kWebRTCIPHandlingPolicy,
                                 renderer_callback);
      pref_change_registrar_.Add(prefs::kWebRTCUDPPortRange, renderer_callback);
  
  #if !defined(OS_MACOSX)
      pref_change_registrar_.Add(prefs::kFullscreenAllowed, renderer_callback);
  #endif
  
      PrefChangeRegistrar::NamedChangeCallback webkit_callback = base::Bind(
          &PrefWatcher::OnWebPrefChanged, base::Unretained(this));
      for (int i = 0; i < kWebPrefsToObserveLength; ++i) {
        const char* pref_name = kWebPrefsToObserve[i];
        pref_change_registrar_.Add(pref_name, webkit_callback);
      }
    }
  
    static PrefWatcher* Get(Profile* profile);
  
    void RegisterHelper(PrefsTabHelper* helper) {
      helpers_.insert(helper);
    }
  
    void UnregisterHelper(PrefsTabHelper* helper) {
      helpers_.erase(helper);
    }
  
   private:
    // KeyedService overrides:
    void Shutdown() override {
      pref_change_registrar_.RemoveAll();
    }
  
    void UpdateRendererPreferences() {
      for (auto* helper : helpers_)
        helper->UpdateRendererPreferences();
    }
  
    void OnWebPrefChanged(const std::string& pref_name) {
      for (auto* helper : helpers_)
        helper->OnWebPrefChanged(pref_name);
    }
  
    Profile* profile_;
    PrefChangeRegistrar pref_change_registrar_;
    std::set<PrefsTabHelper*> helpers_;
  };
  
  class PrefWatcherFactory : public BrowserContextKeyedServiceFactory {
   public:
    static PrefWatcher* GetForProfile(Profile* profile) {
      return static_cast<PrefWatcher*>(
          GetInstance()->GetServiceForBrowserContext(profile, true));
    }
  
    static PrefWatcherFactory* GetInstance() {
      return base::Singleton<PrefWatcherFactory>::get();
    }
  
   private:
    friend struct base::DefaultSingletonTraits<PrefWatcherFactory>;
  
    PrefWatcherFactory() : BrowserContextKeyedServiceFactory(
        "PrefWatcher",
        BrowserContextDependencyManager::GetInstance()) {
    }
  
    ~PrefWatcherFactory() override {}
  
    // BrowserContextKeyedServiceFactory:
    KeyedService* BuildServiceInstanceFor(
        content::BrowserContext* browser_context) const override {
      return new PrefWatcher(Profile::FromBrowserContext(browser_context));
    }
  
    content::BrowserContext* GetBrowserContextToUse(
        content::BrowserContext* context) const override {
      return chrome::GetBrowserContextOwnInstanceInIncognito(context);
    }
  };
  
  // static
  PrefWatcher* PrefWatcher::Get(Profile* profile) {
    return PrefWatcherFactory::GetForProfile(profile);
  }
  
  PrefsTabHelper::PrefsTabHelper(WebContents* contents)
      : web_contents_(contents),
        profile_(Profile::FromBrowserContext(web_contents_->GetBrowserContext())),
        weak_ptr_factory_(this) {
    PrefService* prefs = profile_->GetPrefs();
    if (prefs) {
  #if !defined(OS_ANDROID)
      // If the tab is in an incognito profile, we track changes in the default
      // zoom level of the parent profile instead.
      Profile* profile_to_track = profile_->GetOriginalProfile();
      ChromeZoomLevelPrefs* zoom_level_prefs =
          profile_to_track->GetZoomLevelPrefs();
  
      base::Closure renderer_callback = base::Bind(
          &PrefsTabHelper::UpdateRendererPreferences, base::Unretained(this));
      // Tests should not need to create a ZoomLevelPrefs.
      if (zoom_level_prefs) {
        default_zoom_level_subscription_ =
            zoom_level_prefs->RegisterDefaultZoomLevelCallback(renderer_callback);
      }
  
      // Unretained is safe because the registrar will be scoped to this class.
      font_change_registrar_.Register(
          FontPrefChangeNotifierFactory::GetForProfile(profile_),
          base::Bind(&PrefsTabHelper::OnWebPrefChanged, base::Unretained(this)));
  #endif  // !defined(OS_ANDROID)
  
      PrefWatcher::Get(profile_)->RegisterHelper(this);
    }
  
    content::RendererPreferences* render_prefs =
        web_contents_->GetMutableRendererPrefs();
    renderer_preferences_util::UpdateFromSystemSettings(render_prefs,
                                                        profile_,
                                                        web_contents_);
  
  #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
    registrar_.Add(this,
                   chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
                   content::Source<ThemeService>(
                       ThemeServiceFactory::GetForProfile(profile_)));
  #endif
  }
  
  PrefsTabHelper::~PrefsTabHelper() {
    PrefWatcher::Get(profile_)->UnregisterHelper(this);
  }
  
  // static
  void PrefsTabHelper::RegisterProfilePrefs(
      user_prefs::PrefRegistrySyncable* registry) {
    WebPreferences pref_defaults;
    registry->RegisterBooleanPref(prefs::kWebKitJavascriptEnabled,
                                  pref_defaults.javascript_enabled);
    registry->RegisterBooleanPref(prefs::kWebKitWebSecurityEnabled,
                                  pref_defaults.web_security_enabled);
    registry->RegisterBooleanPref(prefs::kWebKitLoadsImagesAutomatically,
                                  pref_defaults.loads_images_automatically);
    registry->RegisterBooleanPref(prefs::kWebKitPluginsEnabled,
                                  pref_defaults.plugins_enabled);
    registry->RegisterBooleanPref(prefs::kWebKitDomPasteEnabled,
                                  pref_defaults.dom_paste_enabled);
    registry->RegisterBooleanPref(prefs::kWebKitTextAreasAreResizable,
                                  pref_defaults.text_areas_are_resizable);
    registry->RegisterBooleanPref(prefs::kWebKitJavascriptCanAccessClipboard,
                                  pref_defaults.javascript_can_access_clipboard);
    registry->RegisterBooleanPref(prefs::kWebkitTabsToLinks,
                                  pref_defaults.tabs_to_links);
    registry->RegisterBooleanPref(prefs::kWebKitAllowRunningInsecureContent,
                                  false);
    registry->RegisterBooleanPref(prefs::kEnableReferrers, true);
    registry->RegisterBooleanPref(prefs::kEnableEncryptedMedia, true);
  #if defined(OS_ANDROID)
    registry->RegisterDoublePref(prefs::kWebKitFontScaleFactor, 1.0);
    registry->RegisterDoublePref(prefs::kWebKitNightModeFactor, 0.0);
    registry->RegisterBooleanPref(prefs::kWebKitNightModeEnabled, false);
    registry->RegisterBooleanPref(prefs::kWebKitNightModeGrayscaleEnabled, false);
    registry->RegisterBooleanPref(prefs::kWebKitForceEnableZoom,
                                  pref_defaults.force_enable_zoom);
    registry->RegisterBooleanPref(prefs::kWebKitPasswordEchoEnabled,
                                  pref_defaults.password_echo_enabled);
  #endif
    registry->RegisterStringPref(
        prefs::kAcceptLanguages,
        l10n_util::GetStringUTF8(IDS_ACCEPT_LANGUAGES),
        user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
    registry->RegisterStringPref(
        prefs::kDefaultCharset,
        l10n_util::GetStringUTF8(IDS_DEFAULT_ENCODING),
        user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
  
    // Register font prefs that have defaults.
    std::set<std::string> fonts_with_defaults;
    UScriptCode browser_script = GetScriptOfBrowserLocale();
    for (size_t i = 0; i < kFontDefaultsLength; ++i) {
      FontDefault pref = kFontDefaults[i];
  
  #if defined(OS_WIN)
      if (pref.pref_name == prefs::kWebKitFixedFontFamily) {
        if (ShouldUseAlternateDefaultFixedFont(
                l10n_util::GetStringUTF8(pref.resource_id)))
          pref.resource_id = IDS_FIXED_FONT_FAMILY_ALT_WIN;
      }
  #endif
  
      UScriptCode pref_script = GetScriptOfFontPref(pref.pref_name);
  
      // Suppress this default font pref value if it is for the primary script of
      // the browser's UI locale.  For example, if the pref is for the sans-serif
      // font for the Cyrillic script, and the browser locale is "ru" (Russian),
      // the default is suppressed.  Otherwise, the default would override the
      // user's font preferences when viewing pages in their native language.
      // This is because users have no way yet of customizing their per-script
      // font preferences.  The font prefs accessible in the options UI are for
      // the default, unknown script; these prefs have less priority than the
      // per-script font prefs when the script of the content is known.  This code
      // can possibly be removed later if users can easily access per-script font
      // prefs (e.g., via the extensions workflow), or the problem turns out to
      // not be really critical after all.
      if (browser_script != pref_script) {
        registry->RegisterStringPref(pref.pref_name,
                                     l10n_util::GetStringUTF8(pref.resource_id));
        fonts_with_defaults.insert(pref.pref_name);
      }
    }
  
  // Register font prefs.  This is only configurable on desktop Chrome.
  #if !defined(OS_ANDROID)
    RegisterFontFamilyPrefs(registry, fonts_with_defaults);
  
    RegisterLocalizedFontPref(registry, prefs::kWebKitDefaultFontSize,
                              IDS_DEFAULT_FONT_SIZE);
    RegisterLocalizedFontPref(registry, prefs::kWebKitDefaultFixedFontSize,
                              IDS_DEFAULT_FIXED_FONT_SIZE);
    RegisterLocalizedFontPref(registry, prefs::kWebKitMinimumFontSize,
                              IDS_MINIMUM_FONT_SIZE);
    RegisterLocalizedFontPref(registry, prefs::kWebKitMinimumLogicalFontSize,
                              IDS_MINIMUM_LOGICAL_FONT_SIZE);
  #endif
  }
  
  // static
  void PrefsTabHelper::GetServiceInstance() {
    PrefWatcherFactory::GetInstance();
  }
  
  void PrefsTabHelper::Observe(int type,
                               const content::NotificationSource& source,
                               const content::NotificationDetails& details) {
  #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
    if (type == chrome::NOTIFICATION_BROWSER_THEME_CHANGED) {
      UpdateRendererPreferences();
      return;
    }
  #endif
  
    NOTREACHED();
  }
  
  void PrefsTabHelper::UpdateWebPreferences() {
    web_contents_->GetRenderViewHost()->UpdateWebkitPreferences(
        web_contents_->GetRenderViewHost()->GetWebkitPreferences());
  }
  
  void PrefsTabHelper::UpdateRendererPreferences() {
    content::RendererPreferences* prefs =
        web_contents_->GetMutableRendererPrefs();
    renderer_preferences_util::UpdateFromSystemSettings(
        prefs, profile_, web_contents_);
    web_contents_->GetRenderViewHost()->SyncRendererPrefs();
  }
  
  void PrefsTabHelper::OnFontFamilyPrefChanged(const std::string& pref_name) {
    // When a font family pref's value goes from non-empty to the empty string, we
    // must add it to the usual WebPreferences struct passed to the renderer.
    //
    // The empty string means to fall back to the pref for the Common script
    // ("Zyyy").  For example, if chrome.fonts.serif.Cyrl is the empty string, it
    // means to use chrome.fonts.serif.Zyyy for Cyrillic script. Prefs that are
    // the empty string are normally not passed to WebKit, since there are so many
    // of them that it would cause a performance regression. Not passing the pref
    // is normally okay since WebKit does the desired fallback behavior regardless
    // of whether the empty string is passed or the pref is not passed at all. But
    // if the pref has changed from non-empty to the empty string, we must let
    // WebKit know.
    std::string generic_family;
    std::string script;
    if (pref_names_util::ParseFontNamePrefPath(pref_name,
                                               &generic_family,
                                               &script)) {
      PrefService* prefs = profile_->GetPrefs();
      std::string pref_value = prefs->GetString(pref_name);
      if (pref_value.empty()) {
        WebPreferences web_prefs =
            web_contents_->GetRenderViewHost()->GetWebkitPreferences();
        OverrideFontFamily(&web_prefs, generic_family, script, std::string());
        web_contents_->GetRenderViewHost()->UpdateWebkitPreferences(web_prefs);
        return;
      }
    }
  }
  
  void PrefsTabHelper::OnWebPrefChanged(const std::string& pref_name) {
    // Use PostTask to dispatch the OnWebkitPreferencesChanged notification to
    // give other observers (particularly the FontFamilyCache) a chance to react
    // to the pref change.
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE, base::BindOnce(&PrefsTabHelper::NotifyWebkitPreferencesChanged,
                                  weak_ptr_factory_.GetWeakPtr(), pref_name));
  }
  
  void PrefsTabHelper::NotifyWebkitPreferencesChanged(
      const std::string& pref_name) {
  #if !defined(OS_ANDROID)
    OnFontFamilyPrefChanged(pref_name);
  #endif
  
    web_contents_->GetRenderViewHost()->OnWebkitPreferencesChanged();
  }
  