Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1060)

Side by Side Diff: ui/gfx/render_text_win.cc

Issue 331713003: RenderTextHarfBuzz: Implement font fallback for Win and Linux (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: gyp -> gn Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/render_text_win.h" 5 #include "ui/gfx/render_text_win.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/i18n/break_iterator.h" 9 #include "base/i18n/break_iterator.h"
10 #include "base/i18n/char_iterator.h" 10 #include "base/i18n/char_iterator.h"
(...skipping 19 matching lines...) Expand all
30 const size_t kMaxUniscribeTextLength = 10000; 30 const size_t kMaxUniscribeTextLength = 10000;
31 31
32 // The initial guess and maximum supported number of runs; arbitrary values. 32 // The initial guess and maximum supported number of runs; arbitrary values.
33 // TODO(msw): Support more runs, determine a better initial guess, etc. 33 // TODO(msw): Support more runs, determine a better initial guess, etc.
34 const int kGuessRuns = 100; 34 const int kGuessRuns = 100;
35 const size_t kMaxRuns = 10000; 35 const size_t kMaxRuns = 10000;
36 36
37 // The maximum number of glyphs per run; ScriptShape fails on larger values. 37 // The maximum number of glyphs per run; ScriptShape fails on larger values.
38 const size_t kMaxGlyphs = 65535; 38 const size_t kMaxGlyphs = 65535;
39 39
40 // Callback to |EnumEnhMetaFile()| to intercept font creation.
41 int CALLBACK MetaFileEnumProc(HDC hdc,
42 HANDLETABLE* table,
43 CONST ENHMETARECORD* record,
44 int table_entries,
45 LPARAM log_font) {
46 if (record->iType == EMR_EXTCREATEFONTINDIRECTW) {
47 const EMREXTCREATEFONTINDIRECTW* create_font_record =
48 reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record);
49 *reinterpret_cast<LOGFONT*>(log_font) = create_font_record->elfw.elfLogFont;
50 }
51 return 1;
52 }
53
54 // Finds a fallback font to use to render the specified |text| with respect to
55 // an initial |font|. Returns the resulting font via out param |result|. Returns
56 // |true| if a fallback font was found.
57 // Adapted from WebKit's |FontCache::GetFontDataForCharacters()|.
58 // TODO(asvitkine): This should be moved to font_fallback_win.cc.
59 bool ChooseFallbackFont(HDC hdc,
60 const Font& font,
61 const wchar_t* text,
62 int text_length,
63 Font* result) {
64 // Use a meta file to intercept the fallback font chosen by Uniscribe.
65 HDC meta_file_dc = CreateEnhMetaFile(hdc, NULL, NULL, NULL);
66 if (!meta_file_dc)
67 return false;
68
69 SelectObject(meta_file_dc, font.GetNativeFont());
70
71 SCRIPT_STRING_ANALYSIS script_analysis;
72 HRESULT hresult =
73 ScriptStringAnalyse(meta_file_dc, text, text_length, 0, -1,
74 SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK,
75 0, NULL, NULL, NULL, NULL, NULL, &script_analysis);
76
77 if (SUCCEEDED(hresult)) {
78 hresult = ScriptStringOut(script_analysis, 0, 0, 0, NULL, 0, 0, FALSE);
79 ScriptStringFree(&script_analysis);
80 }
81
82 bool found_fallback = false;
83 HENHMETAFILE meta_file = CloseEnhMetaFile(meta_file_dc);
84 if (SUCCEEDED(hresult)) {
85 LOGFONT log_font;
86 log_font.lfFaceName[0] = 0;
87 EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL);
88 if (log_font.lfFaceName[0]) {
89 *result = Font(base::UTF16ToUTF8(log_font.lfFaceName),
90 font.GetFontSize());
91 found_fallback = true;
92 }
93 }
94 DeleteEnhMetaFile(meta_file);
95
96 return found_fallback;
97 }
98
99 // Changes |font| to have the specified |font_size| (or |font_height| on Windows 40 // Changes |font| to have the specified |font_size| (or |font_height| on Windows
100 // XP) and |font_style| if it is not the case already. Only considers bold and 41 // XP) and |font_style| if it is not the case already. Only considers bold and
101 // italic styles, since the underlined style has no effect on glyph shaping. 42 // italic styles, since the underlined style has no effect on glyph shaping.
102 void DeriveFontIfNecessary(int font_size, 43 void DeriveFontIfNecessary(int font_size,
103 int font_height, 44 int font_height,
104 int font_style, 45 int font_style,
105 Font* font) { 46 Font* font) {
106 const int kStyleMask = (Font::BOLD | Font::ITALIC); 47 const int kStyleMask = (Font::BOLD | Font::ITALIC);
107 const int target_style = (font_style & kStyleMask); 48 const int target_style = (font_style & kStyleMask);
108 49
(...skipping 939 matching lines...) Expand 10 before | Expand all | Expand 10 after
1048 run->width = abc.abcA + abc.abcB + abc.abcC; 989 run->width = abc.abcA + abc.abcB + abc.abcC;
1049 preceding_run_widths += run->width; 990 preceding_run_widths += run->width;
1050 } 991 }
1051 string_width_ = preceding_run_widths; 992 string_width_ = preceding_run_widths;
1052 } 993 }
1053 994
1054 void RenderTextWin::LayoutTextRun(internal::TextRun* run) { 995 void RenderTextWin::LayoutTextRun(internal::TextRun* run) {
1055 const size_t run_length = run->range.length(); 996 const size_t run_length = run->range.length();
1056 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]); 997 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]);
1057 Font original_font = run->font; 998 Font original_font = run->font;
1058 LinkedFontsIterator fonts(original_font);
1059 999
1060 run->logical_clusters.reset(new WORD[run_length]); 1000 run->logical_clusters.reset(new WORD[run_length]);
1061 1001
1062 // Try to shape with the first font in the fallback list, which is 1002 // Try shaping with |original_font|.
1063 // |original_font|. 1003 Font current_font = original_font;
1064 Font current_font;
1065 fonts.NextFont(&current_font);
1066 int missing_count = CountCharsWithMissingGlyphs(run, 1004 int missing_count = CountCharsWithMissingGlyphs(run,
1067 ShapeTextRunWithFont(run, current_font)); 1005 ShapeTextRunWithFont(run, current_font));
1068 if (missing_count == 0) 1006 if (missing_count == 0)
1069 return; 1007 return;
1070 1008
1071 // Keep track of the font that is able to display the greatest number of 1009 // Keep track of the font that is able to display the greatest number of
1072 // characters for which ScriptShape() returned S_OK. This font will be used 1010 // characters for which ScriptShape() returned S_OK. This font will be used
1073 // in the case where no font is able to display the entire run. 1011 // in the case where no font is able to display the entire run.
1074 int best_partial_font_missing_char_count = missing_count; 1012 int best_partial_font_missing_char_count = missing_count;
1075 Font best_partial_font = current_font; 1013 Font best_partial_font = current_font;
1076 1014
1077 // Try to shape with the cached font from previous runs, if any. 1015 // Try to shape with the cached font from previous runs, if any.
1078 std::map<std::string, Font>::const_iterator it = 1016 std::map<std::string, Font>::const_iterator it =
1079 successful_substitute_fonts_.find(original_font.GetFontName()); 1017 successful_substitute_fonts_.find(original_font.GetFontName());
1080 if (it != successful_substitute_fonts_.end()) { 1018 if (it != successful_substitute_fonts_.end()) {
1081 current_font = it->second; 1019 current_font = it->second;
1082 missing_count = CountCharsWithMissingGlyphs(run, 1020 missing_count = CountCharsWithMissingGlyphs(run,
1083 ShapeTextRunWithFont(run, current_font)); 1021 ShapeTextRunWithFont(run, current_font));
1084 if (missing_count == 0) 1022 if (missing_count == 0)
1085 return; 1023 return;
1086 if (missing_count < best_partial_font_missing_char_count) { 1024 if (missing_count < best_partial_font_missing_char_count) {
1087 best_partial_font_missing_char_count = missing_count; 1025 best_partial_font_missing_char_count = missing_count;
1088 best_partial_font = current_font; 1026 best_partial_font = current_font;
1089 } 1027 }
1090 } 1028 }
1091 1029
1092 // Try finding a fallback font using a meta file. 1030 // Try finding a fallback font using a meta file.
1093 // TODO(msw|asvitkine): Support RenderText's font_list()? 1031 // TODO(msw|asvitkine): Support RenderText's font_list()?
1094 if (ChooseFallbackFont(cached_hdc_, run->font, run_text, run_length, 1032 if (GetUniscribeFallbackFont(original_font, run_text, run_length,
1095 &current_font)) { 1033 &current_font)) {
1096 missing_count = CountCharsWithMissingGlyphs(run, 1034 missing_count = CountCharsWithMissingGlyphs(run,
1097 ShapeTextRunWithFont(run, current_font)); 1035 ShapeTextRunWithFont(run, current_font));
1098 if (missing_count == 0) { 1036 if (missing_count == 0) {
1099 successful_substitute_fonts_[original_font.GetFontName()] = current_font; 1037 successful_substitute_fonts_[original_font.GetFontName()] = current_font;
1100 return; 1038 return;
1101 } 1039 }
1102 if (missing_count < best_partial_font_missing_char_count) { 1040 if (missing_count < best_partial_font_missing_char_count) {
1103 best_partial_font_missing_char_count = missing_count; 1041 best_partial_font_missing_char_count = missing_count;
1104 best_partial_font = current_font; 1042 best_partial_font = current_font;
1105 } 1043 }
1106 } 1044 }
1107 1045
1108 // Try the rest of fonts in the fallback list. 1046 // Try fonts in the fallback list except the first, which is |original_font|.
1109 while (fonts.NextFont(&current_font)) { 1047 std::vector<std::string> fonts =
1048 GetFallbackFontFamilies(original_font.GetFontName());
1049 for (size_t i = 1; i < fonts.size(); ++i) {
1110 missing_count = CountCharsWithMissingGlyphs(run, 1050 missing_count = CountCharsWithMissingGlyphs(run,
1111 ShapeTextRunWithFont(run, current_font)); 1051 ShapeTextRunWithFont(run, Font(fonts[i], original_font.GetFontSize())));
1112 if (missing_count == 0) { 1052 if (missing_count == 0) {
1113 successful_substitute_fonts_[original_font.GetFontName()] = current_font; 1053 successful_substitute_fonts_[original_font.GetFontName()] = current_font;
1114 return; 1054 return;
1115 } 1055 }
1116 if (missing_count < best_partial_font_missing_char_count) { 1056 if (missing_count < best_partial_font_missing_char_count) {
1117 best_partial_font_missing_char_count = missing_count; 1057 best_partial_font_missing_char_count = missing_count;
1118 best_partial_font = current_font; 1058 best_partial_font = current_font;
1119 } 1059 }
1120 } 1060 }
1121 1061
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
1281 size_t position = LayoutIndexToTextIndex(run->range.end()); 1221 size_t position = LayoutIndexToTextIndex(run->range.end());
1282 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); 1222 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD);
1283 return SelectionModel(position, CURSOR_FORWARD); 1223 return SelectionModel(position, CURSOR_FORWARD);
1284 } 1224 }
1285 1225
1286 RenderText* RenderText::CreateNativeInstance() { 1226 RenderText* RenderText::CreateNativeInstance() {
1287 return new RenderTextWin; 1227 return new RenderTextWin;
1288 } 1228 }
1289 1229
1290 } // namespace gfx 1230 } // namespace gfx
OLDNEW
« ui/gfx/render_text_harfbuzz.cc ('K') | « ui/gfx/render_text_harfbuzz.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698