blob: bbef3796febeb4a17f11ae7b75d1857277eb1ebc [file] [log] [blame]
[email protected]354de9e2014-08-07 03:27:191// 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
5#include "chrome/browser/font_family_cache.h"
6
avi6846aef2015-12-26 01:09:387#include <stddef.h>
8
[email protected]354de9e2014-08-07 03:27:199#include <map>
10
Sebastien Marchandf1349f52019-01-25 03:16:4111#include "base/bind.h"
avi284ec612017-05-03 01:52:2312#include "base/memory/ptr_util.h"
[email protected]354de9e2014-08-07 03:27:1913#include "base/strings/stringprintf.h"
14#include "base/strings/utf_string_conversions.h"
15#include "chrome/browser/chrome_notification_types.h"
Brett Wilson21cf626a2017-09-07 00:30:2016#include "chrome/browser/font_pref_change_notifier_factory.h"
[email protected]354de9e2014-08-07 03:27:1917#include "chrome/browser/profiles/profile.h"
18#include "chrome/common/pref_font_webkit_names.h"
19#include "chrome/common/pref_names.h"
brettwb1fc1b82016-02-02 00:19:0820#include "components/prefs/pref_service.h"
[email protected]354de9e2014-08-07 03:27:1921#include "content/public/browser/notification_source.h"
22
23// Identifies the user data on the profile.
24const char kFontFamilyCacheKey[] = "FontFamilyCacheKey";
25
26FontFamilyCache::FontFamilyCache(Profile* profile)
27 : prefs_(profile->GetPrefs()) {
[email protected]354de9e2014-08-07 03:27:1928 notification_registrar_.Add(this,
29 chrome::NOTIFICATION_PROFILE_DESTROYED,
30 content::Source<Profile>(profile));
Brett Wilson21cf626a2017-09-07 00:30:2031
32 // Safe to use Unretained here since the registrar is scoped to this class.
33 font_change_registrar_.Register(
34 FontPrefChangeNotifierFactory::GetForProfile(profile),
35 base::Bind(&FontFamilyCache::OnPrefsChanged, base::Unretained(this)));
[email protected]354de9e2014-08-07 03:27:1936}
37
38FontFamilyCache::~FontFamilyCache() {
39}
40
41void FontFamilyCache::FillFontFamilyMap(Profile* profile,
42 const char* map_name,
43 content::ScriptFontFamilyMap* map) {
44 FontFamilyCache* cache =
45 static_cast<FontFamilyCache*>(profile->GetUserData(&kFontFamilyCacheKey));
46 if (!cache) {
47 cache = new FontFamilyCache(profile);
avi284ec612017-05-03 01:52:2348 profile->SetUserData(&kFontFamilyCacheKey, base::WrapUnique(cache));
[email protected]354de9e2014-08-07 03:27:1949 }
50
51 cache->FillFontFamilyMap(map_name, map);
52}
53
54void FontFamilyCache::FillFontFamilyMap(const char* map_name,
55 content::ScriptFontFamilyMap* map) {
56 // TODO(falken): Get rid of the brute-force scan over possible
57 // (font family / script) combinations - see http://crbug.com/308095.
58 for (size_t i = 0; i < prefs::kWebKitScriptsForFontFamilyMapsLength; ++i) {
59 const char* script = prefs::kWebKitScriptsForFontFamilyMaps[i];
60 base::string16 result = FetchAndCacheFont(script, map_name);
61 if (!result.empty())
62 (*map)[script] = result;
63 }
64}
65
66base::string16 FontFamilyCache::FetchFont(const char* script,
67 const char* map_name) {
68 std::string pref_name = base::StringPrintf("%s.%s", map_name, script);
69 std::string font = prefs_->GetString(pref_name.c_str());
70 base::string16 font16 = base::UTF8ToUTF16(font);
71
72 // Lazily constructs the map if it doesn't already exist.
73 ScriptFontMap& map = font_family_map_[map_name];
74 map[script] = font16;
[email protected]354de9e2014-08-07 03:27:1975 return font16;
76}
77
78base::string16 FontFamilyCache::FetchAndCacheFont(const char* script,
79 const char* map_name) {
80 FontFamilyMap::const_iterator it = font_family_map_.find(map_name);
81 if (it != font_family_map_.end()) {
jdoerrie2f1af512018-10-03 00:59:3782 auto it2 = it->second.find(script);
[email protected]354de9e2014-08-07 03:27:1983 if (it2 != it->second.end())
84 return it2->second;
85 }
86
87 return FetchFont(script, map_name);
88}
89
90// There are ~1000 entries in the cache. Avoid unnecessary object construction,
91// including std::string.
92void FontFamilyCache::OnPrefsChanged(const std::string& pref_name) {
93 const size_t delimiter_length = 1;
94 const char delimiter = '.';
brettw84cff3f2017-06-29 18:26:5095 for (auto& it : font_family_map_) {
96 const char* map_name = it.first;
[email protected]354de9e2014-08-07 03:27:1997 size_t map_name_length = strlen(map_name);
98
99 // If the map name doesn't match, move on.
100 if (pref_name.compare(0, map_name_length, map_name) != 0)
101 continue;
102
brettw84cff3f2017-06-29 18:26:50103 ScriptFontMap& map = it.second;
jdoerrie2f1af512018-10-03 00:59:37104 for (auto it2 = map.begin(); it2 != map.end(); ++it2) {
[email protected]354de9e2014-08-07 03:27:19105 const char* script = it2->first;
106 size_t script_length = strlen(script);
107
108 // If the length doesn't match, move on.
109 if (pref_name.size() !=
110 map_name_length + script_length + delimiter_length)
111 continue;
112
113 // If the script doesn't match, move on.
114 if (pref_name.compare(
115 map_name_length + delimiter_length, script_length, script) != 0)
116 continue;
117
118 // If the delimiter doesn't match, move on.
119 if (pref_name[map_name_length] != delimiter)
120 continue;
121
Brett Wilson21cf626a2017-09-07 00:30:20122 // Clear the cache.
[email protected]354de9e2014-08-07 03:27:19123 map.erase(it2);
[email protected]354de9e2014-08-07 03:27:19124 break;
125 }
126 }
127}
128
129void FontFamilyCache::Observe(int type,
130 const content::NotificationSource& source,
131 const content::NotificationDetails& details) {
132 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type);
Brett Wilson21cf626a2017-09-07 00:30:20133 font_change_registrar_.Unregister();
[email protected]354de9e2014-08-07 03:27:19134}