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