Refactor HpackDecoder's public API to ease integration into SpdyFramer.
[chromium-blink-merge.git] / ui / gfx / font_fallback_win.cc
blob4426718959b3be04a65160f23b808036d94dc64d
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.
5 #include "ui/gfx/font_fallback_win.h"
7 #include <map>
9 #include "base/memory/singleton.h"
10 #include "base/strings/string_split.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/win/registry.h"
14 #include "ui/gfx/font.h"
16 namespace gfx {
18 namespace {
20 // Queries the registry to get a mapping from font filenames to font names.
21 void QueryFontsFromRegistry(std::map<std::string, std::string>* map) {
22 const wchar_t* kFonts =
23 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
25 base::win::RegistryValueIterator it(HKEY_LOCAL_MACHINE, kFonts);
26 for (; it.Valid(); ++it) {
27 const std::string filename =
28 StringToLowerASCII(base::WideToUTF8(it.Value()));
29 (*map)[filename] = base::WideToUTF8(it.Name());
33 // Fills |font_names| with a list of font families found in the font file at
34 // |filename|. Takes in a |font_map| from font filename to font families, which
35 // is filled-in by querying the registry, if empty.
36 void GetFontNamesFromFilename(const std::string& filename,
37 std::map<std::string, std::string>* font_map,
38 std::vector<std::string>* font_names) {
39 if (font_map->empty())
40 QueryFontsFromRegistry(font_map);
42 std::map<std::string, std::string>::const_iterator it =
43 font_map->find(StringToLowerASCII(filename));
44 if (it == font_map->end())
45 return;
47 internal::ParseFontFamilyString(it->second, font_names);
50 // Returns true if |text| contains only ASCII digits.
51 bool ContainsOnlyDigits(const std::string& text) {
52 return text.find_first_not_of("0123456789") == base::string16::npos;
55 // Appends a Font with the given |name| and |size| to |fonts| unless the last
56 // entry is already a font with that name.
57 void AppendFont(const std::string& name, int size, std::vector<Font>* fonts) {
58 if (fonts->empty() || fonts->back().GetFontName() != name)
59 fonts->push_back(Font(name, size));
62 // Queries the registry to get a list of linked fonts for |font|.
63 void QueryLinkedFontsFromRegistry(const Font& font,
64 std::map<std::string, std::string>* font_map,
65 std::vector<Font>* linked_fonts) {
66 const wchar_t* kSystemLink =
67 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink";
69 base::win::RegKey key;
70 if (FAILED(key.Open(HKEY_LOCAL_MACHINE, kSystemLink, KEY_READ)))
71 return;
73 const std::wstring original_font_name = base::UTF8ToWide(font.GetFontName());
74 std::vector<std::wstring> values;
75 if (FAILED(key.ReadValues(original_font_name.c_str(), &values))) {
76 key.Close();
77 return;
80 std::string filename;
81 std::string font_name;
82 for (size_t i = 0; i < values.size(); ++i) {
83 internal::ParseFontLinkEntry(
84 base::WideToUTF8(values[i]), &filename, &font_name);
85 // If the font name is present, add that directly, otherwise add the
86 // font names corresponding to the filename.
87 if (!font_name.empty()) {
88 AppendFont(font_name, font.GetFontSize(), linked_fonts);
89 } else if (!filename.empty()) {
90 std::vector<std::string> font_names;
91 GetFontNamesFromFilename(filename, font_map, &font_names);
92 for (size_t i = 0; i < font_names.size(); ++i)
93 AppendFont(font_names[i], font.GetFontSize(), linked_fonts);
97 key.Close();
100 // CachedFontLinkSettings is a singleton cache of the Windows font settings
101 // from the registry. It maintains a cached view of the registry's list of
102 // system fonts and their font link chains.
103 class CachedFontLinkSettings {
104 public:
105 static CachedFontLinkSettings* GetInstance();
107 // Returns the linked fonts list correspond to |font|. Returned value will
108 // never be null.
109 const std::vector<Font>* GetLinkedFonts(const Font& font);
111 private:
112 friend struct DefaultSingletonTraits<CachedFontLinkSettings>;
114 CachedFontLinkSettings();
115 virtual ~CachedFontLinkSettings();
117 // Map of system fonts, from file names to font families.
118 std::map<std::string, std::string> cached_system_fonts_;
120 // Map from font names to vectors of linked fonts.
121 std::map<std::string, std::vector<Font> > cached_linked_fonts_;
123 DISALLOW_COPY_AND_ASSIGN(CachedFontLinkSettings);
126 // static
127 CachedFontLinkSettings* CachedFontLinkSettings::GetInstance() {
128 return Singleton<CachedFontLinkSettings,
129 LeakySingletonTraits<CachedFontLinkSettings> >::get();
132 const std::vector<Font>* CachedFontLinkSettings::GetLinkedFonts(
133 const Font& font) {
134 const std::string& font_name = font.GetFontName();
135 std::map<std::string, std::vector<Font> >::const_iterator it =
136 cached_linked_fonts_.find(font_name);
137 if (it != cached_linked_fonts_.end())
138 return &it->second;
140 cached_linked_fonts_[font_name] = std::vector<Font>();
141 std::vector<Font>* linked_fonts = &cached_linked_fonts_[font_name];
142 QueryLinkedFontsFromRegistry(font, &cached_system_fonts_, linked_fonts);
143 return linked_fonts;
146 CachedFontLinkSettings::CachedFontLinkSettings() {
149 CachedFontLinkSettings::~CachedFontLinkSettings() {
152 } // namespace
154 namespace internal {
156 void ParseFontLinkEntry(const std::string& entry,
157 std::string* filename,
158 std::string* font_name) {
159 std::vector<std::string> parts;
160 base::SplitString(entry, ',', &parts);
161 filename->clear();
162 font_name->clear();
163 if (parts.size() > 0)
164 *filename = parts[0];
165 // The second entry may be the font name or the first scaling factor, if the
166 // entry does not contain a font name. If it contains only digits, assume it
167 // is a scaling factor.
168 if (parts.size() > 1 && !ContainsOnlyDigits(parts[1]))
169 *font_name = parts[1];
172 void ParseFontFamilyString(const std::string& family,
173 std::vector<std::string>* font_names) {
174 // The entry is comma separated, having the font filename as the first value
175 // followed optionally by the font family name and a pair of integer scaling
176 // factors.
177 // TODO(asvitkine): Should we support these scaling factors?
178 base::SplitString(family, '&', font_names);
179 if (!font_names->empty()) {
180 const size_t index = font_names->back().find('(');
181 if (index != std::string::npos) {
182 font_names->back().resize(index);
183 base::TrimWhitespace(font_names->back(), base::TRIM_TRAILING,
184 &font_names->back());
189 } // namespace internal
191 LinkedFontsIterator::LinkedFontsIterator(Font font)
192 : original_font_(font),
193 next_font_set_(false),
194 linked_fonts_(NULL),
195 linked_font_index_(0) {
196 SetNextFont(original_font_);
199 LinkedFontsIterator::~LinkedFontsIterator() {
202 void LinkedFontsIterator::SetNextFont(Font font) {
203 next_font_ = font;
204 next_font_set_ = true;
207 bool LinkedFontsIterator::NextFont(Font* font) {
208 if (next_font_set_) {
209 next_font_set_ = false;
210 current_font_ = next_font_;
211 *font = current_font_;
212 return true;
215 // First time through, get the linked fonts list.
216 if (linked_fonts_ == NULL)
217 linked_fonts_ = GetLinkedFonts();
219 if (linked_font_index_ == linked_fonts_->size())
220 return false;
222 current_font_ = linked_fonts_->at(linked_font_index_++);
223 *font = current_font_;
224 return true;
227 const std::vector<Font>* LinkedFontsIterator::GetLinkedFonts() const {
228 CachedFontLinkSettings* font_link = CachedFontLinkSettings::GetInstance();
230 // First, try to get the list for the original font.
231 const std::vector<Font>* fonts = font_link->GetLinkedFonts(original_font_);
233 // If there are no linked fonts for the original font, try querying the
234 // ones for the current font. This may happen if the first font is a custom
235 // font that has no linked fonts in the registry.
237 // Note: One possibility would be to always merge both lists of fonts,
238 // but it is not clear whether there are any real world scenarios
239 // where this would actually help.
240 if (fonts->empty())
241 fonts = font_link->GetLinkedFonts(current_font_);
243 return fonts;
246 } // namespace gfx