| 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 // LinkedFontsIterator doesn't care about the font size, so we always pass 10. |
| 266 internal::LinkedFontsIterator linked_fonts(Font(font_family, 10)); |
| 267 std::vector<std::string> fallback_fonts; |
| 268 Font current; |
| 269 while (linked_fonts.NextFont(¤t)) |
| 270 fallback_fonts.push_back(current.GetFontName()); |
| 271 return fallback_fonts; |
| 272 } |
| 273 |
| 274 bool GetUniscribeFallbackFont(const Font& font, |
| 275 const wchar_t* text, |
| 276 int text_length, |
| 277 Font* result) { |
| 278 // Adapted from WebKit's |FontCache::GetFontDataForCharacters()|. |
| 279 // Uniscribe doesn't expose a method to query fallback fonts, so this works by |
| 280 // drawing the text to an EMF object with Uniscribe's ScriptStringOut and then |
| 281 // inspecting the EMF object to figure out which font Uniscribe used. |
| 282 // |
| 283 // DirectWrite in Windows 8.1 provides a cleaner alternative: |
| 284 // http://msdn.microsoft.com/en-us/library/windows/desktop/dn280480.aspx |
| 285 |
| 286 static HDC hdc = CreateCompatibleDC(NULL); |
| 287 |
| 288 // Use a meta file to intercept the fallback font chosen by Uniscribe. |
| 289 HDC meta_file_dc = CreateEnhMetaFile(hdc, NULL, NULL, NULL); |
| 290 if (!meta_file_dc) |
| 291 return false; |
| 292 |
| 293 SelectObject(meta_file_dc, font.GetNativeFont()); |
| 294 |
| 295 SCRIPT_STRING_ANALYSIS script_analysis; |
| 296 HRESULT hresult = |
| 297 ScriptStringAnalyse(meta_file_dc, text, text_length, 0, -1, |
| 298 SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK, |
| 299 0, NULL, NULL, NULL, NULL, NULL, &script_analysis); |
| 300 |
| 301 if (SUCCEEDED(hresult)) { |
| 302 hresult = ScriptStringOut(script_analysis, 0, 0, 0, NULL, 0, 0, FALSE); |
| 303 ScriptStringFree(&script_analysis); |
| 304 } |
| 305 |
| 306 bool found_fallback = false; |
| 307 HENHMETAFILE meta_file = CloseEnhMetaFile(meta_file_dc); |
| 308 if (SUCCEEDED(hresult)) { |
| 309 LOGFONT log_font; |
| 310 log_font.lfFaceName[0] = 0; |
| 311 EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL); |
| 312 if (log_font.lfFaceName[0]) { |
| 313 *result = Font(base::UTF16ToUTF8(log_font.lfFaceName), |
| 314 font.GetFontSize()); |
| 315 found_fallback = true; |
| 316 } |
| 317 } |
| 318 DeleteEnhMetaFile(meta_file); |
| 319 |
| 320 return found_fallback; |
| 321 } |
| 322 |
| 246 } // namespace gfx | 323 } // namespace gfx |
| OLD | NEW |