OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/font_fallback_win.h" | 5 #include "ui/gfx/font_fallback_win.h" |
6 | 6 |
7 #include <usp10.h> | |
8 | |
7 #include <map> | 9 #include <map> |
8 | 10 |
9 #include "base/memory/singleton.h" | 11 #include "base/memory/singleton.h" |
10 #include "base/strings/string_split.h" | 12 #include "base/strings/string_split.h" |
11 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
12 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
13 #include "base/win/registry.h" | 15 #include "base/win/registry.h" |
14 #include "ui/gfx/font.h" | 16 #include "ui/gfx/font.h" |
17 #include "ui/gfx/font_fallback.h" | |
15 | 18 |
16 namespace gfx { | 19 namespace gfx { |
17 | 20 |
18 namespace { | 21 namespace { |
19 | 22 |
20 // Queries the registry to get a mapping from font filenames to font names. | 23 // Queries the registry to get a mapping from font filenames to font names. |
21 void QueryFontsFromRegistry(std::map<std::string, std::string>* map) { | 24 void QueryFontsFromRegistry(std::map<std::string, std::string>* map) { |
22 const wchar_t* kFonts = | 25 const wchar_t* kFonts = |
23 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; | 26 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; |
24 | 27 |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
142 QueryLinkedFontsFromRegistry(font, &cached_system_fonts_, linked_fonts); | 145 QueryLinkedFontsFromRegistry(font, &cached_system_fonts_, linked_fonts); |
143 return linked_fonts; | 146 return linked_fonts; |
144 } | 147 } |
145 | 148 |
146 CachedFontLinkSettings::CachedFontLinkSettings() { | 149 CachedFontLinkSettings::CachedFontLinkSettings() { |
147 } | 150 } |
148 | 151 |
149 CachedFontLinkSettings::~CachedFontLinkSettings() { | 152 CachedFontLinkSettings::~CachedFontLinkSettings() { |
150 } | 153 } |
151 | 154 |
155 // Callback to |EnumEnhMetaFile()| to intercept font creation. | |
156 int CALLBACK MetaFileEnumProc(HDC hdc, | |
157 HANDLETABLE* table, | |
158 CONST ENHMETARECORD* record, | |
159 int table_entries, | |
160 LPARAM log_font) { | |
161 if (record->iType == EMR_EXTCREATEFONTINDIRECTW) { | |
162 const EMREXTCREATEFONTINDIRECTW* create_font_record = | |
163 reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record); | |
164 *reinterpret_cast<LOGFONT*>(log_font) = create_font_record->elfw.elfLogFont; | |
165 } | |
166 return 1; | |
167 } | |
168 | |
152 } // namespace | 169 } // namespace |
153 | 170 |
154 namespace internal { | 171 namespace internal { |
155 | 172 |
156 void ParseFontLinkEntry(const std::string& entry, | 173 void ParseFontLinkEntry(const std::string& entry, |
157 std::string* filename, | 174 std::string* filename, |
158 std::string* font_name) { | 175 std::string* font_name) { |
159 std::vector<std::string> parts; | 176 std::vector<std::string> parts; |
160 base::SplitString(entry, ',', &parts); | 177 base::SplitString(entry, ',', &parts); |
161 filename->clear(); | 178 filename->clear(); |
(...skipping 17 matching lines...) Expand all Loading... | |
179 if (!font_names->empty()) { | 196 if (!font_names->empty()) { |
180 const size_t index = font_names->back().find('('); | 197 const size_t index = font_names->back().find('('); |
181 if (index != std::string::npos) { | 198 if (index != std::string::npos) { |
182 font_names->back().resize(index); | 199 font_names->back().resize(index); |
183 base::TrimWhitespace(font_names->back(), base::TRIM_TRAILING, | 200 base::TrimWhitespace(font_names->back(), base::TRIM_TRAILING, |
184 &font_names->back()); | 201 &font_names->back()); |
185 } | 202 } |
186 } | 203 } |
187 } | 204 } |
188 | 205 |
189 } // namespace internal | |
190 | |
191 LinkedFontsIterator::LinkedFontsIterator(Font font) | 206 LinkedFontsIterator::LinkedFontsIterator(Font font) |
192 : original_font_(font), | 207 : original_font_(font), |
193 next_font_set_(false), | 208 next_font_set_(false), |
194 linked_fonts_(NULL), | 209 linked_fonts_(NULL), |
195 linked_font_index_(0) { | 210 linked_font_index_(0) { |
196 SetNextFont(original_font_); | 211 SetNextFont(original_font_); |
197 } | 212 } |
198 | 213 |
199 LinkedFontsIterator::~LinkedFontsIterator() { | 214 LinkedFontsIterator::~LinkedFontsIterator() { |
200 } | 215 } |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
236 // | 251 // |
237 // Note: One possibility would be to always merge both lists of fonts, | 252 // 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 | 253 // but it is not clear whether there are any real world scenarios |
239 // where this would actually help. | 254 // where this would actually help. |
240 if (fonts->empty()) | 255 if (fonts->empty()) |
241 fonts = font_link->GetLinkedFonts(current_font_); | 256 fonts = font_link->GetLinkedFonts(current_font_); |
242 | 257 |
243 return fonts; | 258 return fonts; |
244 } | 259 } |
245 | 260 |
261 } // namespace internal | |
262 | |
263 std::vector<std::string> GetFallbackFontFamilies( | |
264 const std::string& font_family) { | |
265 internal::LinkedFontsIterator linked_fonts(Font(font_family, 10)); | |
Alexei Svitkine (slow)
2014/07/17 21:22:00
Please add a comment about the hard-coded 10.
ckocagil
2014/07/17 23:12:00
Done.
| |
266 std::vector<std::string> fallback_fonts; | |
267 Font current; | |
268 while (linked_fonts.NextFont(¤t)) | |
269 fallback_fonts.push_back(current.GetFontName()); | |
270 return fallback_fonts; | |
271 } | |
272 | |
273 // Adapted from WebKit's |FontCache::GetFontDataForCharacters()|. | |
274 // Uniscribe doesn't expose a method to query fallback fonts, so this works by | |
275 // drawing the text to an EMF object with Uniscribe's ScriptStringOut and then | |
276 // inspecting the EMF object to figure out which font Uniscribe used. | |
277 // | |
278 // DirectWrite in Windows 8.1 provides a cleaner alternative: | |
279 // http://msdn.microsoft.com/en-us/library/windows/desktop/dn280480.aspx | |
Alexei Svitkine (slow)
2014/07/17 21:22:00
This comment should either be in the header or wit
ckocagil
2014/07/17 23:12:00
Done, moved into the body.
| |
280 bool GetUniscribeFallbackFont(const Font& font, | |
281 const wchar_t* text, | |
282 int text_length, | |
283 Font* result) { | |
284 static HDC hdc = NULL; | |
285 if (hdc == NULL) { | |
286 hdc = CreateCompatibleDC(NULL); | |
msw
2014/07/17 00:08:04
nit: can you inline this with the static decl?
ckocagil
2014/07/17 00:10:49
Wouldn't that cause a static initializer to be add
msw
2014/07/17 00:15:35
I thought this was okay for function-scoped static
Daniel Erat
2014/07/17 02:22:24
function-scoped static initializers are fine, per
ckocagil
2014/07/17 23:12:00
Oh, now I read the thread and came to the same con
| |
287 DCHECK(hdc) << GetLastError(); | |
288 } | |
289 | |
290 // Use a meta file to intercept the fallback font chosen by Uniscribe. | |
291 HDC meta_file_dc = CreateEnhMetaFile(hdc, NULL, NULL, NULL); | |
292 if (!meta_file_dc) | |
293 return false; | |
294 | |
295 SelectObject(meta_file_dc, font.GetNativeFont()); | |
296 | |
297 SCRIPT_STRING_ANALYSIS script_analysis; | |
298 HRESULT hresult = | |
299 ScriptStringAnalyse(meta_file_dc, text, text_length, 0, -1, | |
300 SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK, | |
301 0, NULL, NULL, NULL, NULL, NULL, &script_analysis); | |
302 | |
303 if (SUCCEEDED(hresult)) { | |
304 hresult = ScriptStringOut(script_analysis, 0, 0, 0, NULL, 0, 0, FALSE); | |
305 ScriptStringFree(&script_analysis); | |
306 } | |
307 | |
308 bool found_fallback = false; | |
309 HENHMETAFILE meta_file = CloseEnhMetaFile(meta_file_dc); | |
310 if (SUCCEEDED(hresult)) { | |
311 LOGFONT log_font; | |
312 log_font.lfFaceName[0] = 0; | |
313 EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL); | |
314 if (log_font.lfFaceName[0]) { | |
315 *result = Font(base::UTF16ToUTF8(log_font.lfFaceName), | |
316 font.GetFontSize()); | |
317 found_fallback = true; | |
318 } | |
319 } | |
320 DeleteEnhMetaFile(meta_file); | |
321 | |
322 return found_fallback; | |
323 } | |
324 | |
246 } // namespace gfx | 325 } // namespace gfx |
OLD | NEW |