font_family_cache.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. // Copyright 2014 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. #include "chrome/browser/font_family_cache.h"
  5. #include <stddef.h>
  6. #include <map>
  7. #include "base/bind.h"
  8. #include "base/memory/ptr_util.h"
  9. #include "base/strings/stringprintf.h"
  10. #include "base/strings/utf_string_conversions.h"
  11. #include "chrome/browser/font_pref_change_notifier_factory.h"
  12. #include "chrome/browser/profiles/profile.h"
  13. #include "chrome/common/pref_font_webkit_names.h"
  14. #include "chrome/common/pref_names.h"
  15. #include "components/prefs/pref_service.h"
  16. // Identifies the user data on the profile.
  17. const char kFontFamilyCacheKey[] = "FontFamilyCacheKey";
  18. FontFamilyCache::FontFamilyCache(Profile* profile)
  19. : prefs_(profile->GetPrefs()) {
  20. font_change_registrar_.Register(
  21. FontPrefChangeNotifierFactory::GetForProfile(profile),
  22. base::BindRepeating(&FontFamilyCache::OnPrefsChanged,
  23. base::Unretained(this)));
  24. }
  25. FontFamilyCache::~FontFamilyCache() = default;
  26. void FontFamilyCache::FillFontFamilyMap(
  27. Profile* profile,
  28. const char* map_name,
  29. blink::web_pref::ScriptFontFamilyMap* map) {
  30. FontFamilyCache* cache =
  31. static_cast<FontFamilyCache*>(profile->GetUserData(&kFontFamilyCacheKey));
  32. if (!cache) {
  33. cache = new FontFamilyCache(profile);
  34. profile->SetUserData(&kFontFamilyCacheKey, base::WrapUnique(cache));
  35. }
  36. cache->FillFontFamilyMap(map_name, map);
  37. }
  38. void FontFamilyCache::FillFontFamilyMap(
  39. const char* map_name,
  40. blink::web_pref::ScriptFontFamilyMap* map) {
  41. // TODO(falken): Get rid of the brute-force scan over possible
  42. // (font family / script) combinations - see http://crbug.com/308095.
  43. for (size_t i = 0; i < prefs::kWebKitScriptsForFontFamilyMapsLength; ++i) {
  44. const char* script = prefs::kWebKitScriptsForFontFamilyMaps[i];
  45. std::u16string result = FetchAndCacheFont(script, map_name);
  46. if (!result.empty())
  47. (*map)[script] = result;
  48. }
  49. }
  50. std::u16string FontFamilyCache::FetchFont(const char* script,
  51. const char* map_name) {
  52. std::string pref_name = base::StringPrintf("%s.%s", map_name, script);
  53. std::string font = prefs_->GetString(pref_name.c_str());
  54. std::u16string font16 = base::UTF8ToUTF16(font);
  55. // Lazily constructs the map if it doesn't already exist.
  56. ScriptFontMap& map = font_family_map_[map_name];
  57. map[script] = font16;
  58. return font16;
  59. }
  60. std::u16string FontFamilyCache::FetchAndCacheFont(const char* script,
  61. const char* map_name) {
  62. FontFamilyMap::const_iterator it = font_family_map_.find(map_name);
  63. if (it != font_family_map_.end()) {
  64. auto it2 = it->second.find(script);
  65. if (it2 != it->second.end())
  66. return it2->second;
  67. }
  68. return FetchFont(script, map_name);
  69. }
  70. // There are ~1000 entries in the cache. Avoid unnecessary object construction,
  71. // including std::string.
  72. void FontFamilyCache::OnPrefsChanged(const std::string& pref_name) {
  73. const size_t delimiter_length = 1;
  74. const char delimiter = '.';
  75. for (auto& it : font_family_map_) {
  76. const char* map_name = it.first;
  77. size_t map_name_length = strlen(map_name);
  78. // If the map name doesn't match, move on.
  79. if (pref_name.compare(0, map_name_length, map_name) != 0)
  80. continue;
  81. ScriptFontMap& map = it.second;
  82. for (auto it2 = map.begin(); it2 != map.end(); ++it2) {
  83. const char* script = it2->first;
  84. size_t script_length = strlen(script);
  85. // If the length doesn't match, move on.
  86. if (pref_name.size() !=
  87. map_name_length + script_length + delimiter_length)
  88. continue;
  89. // If the script doesn't match, move on.
  90. if (pref_name.compare(
  91. map_name_length + delimiter_length, script_length, script) != 0)
  92. continue;
  93. // If the delimiter doesn't match, move on.
  94. if (pref_name[map_name_length] != delimiter)
  95. continue;
  96. // Clear the cache.
  97. map.erase(it2);
  98. break;
  99. }
  100. }
  101. }