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

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

Issue 663373005: Revert 4939383c95030cf963cf5a70ede23c57b212baa4 from M38 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@2125
Patch Set: Created 6 years, 2 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
« no previous file with comments | « ui/gfx/render_text_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 while (iter.Advance() && iter.array_pos() < run_length) { 219 while (iter.Advance() && iter.array_pos() < run_length) {
220 const UBlockCode current_block_code = ublock_getCode(iter.get()); 220 const UBlockCode current_block_code = ublock_getCode(iter.get());
221 if (current_block_code != first_block_code && 221 if (current_block_code != first_block_code &&
222 (first_block_unusual || IsUnusualBlockCode(current_block_code))) { 222 (first_block_unusual || IsUnusualBlockCode(current_block_code))) {
223 return run_start + iter.array_pos(); 223 return run_start + iter.array_pos();
224 } 224 }
225 } 225 }
226 return run_break; 226 return run_break;
227 } 227 }
228 228
229 // Callback to |EnumEnhMetaFile()| to intercept font creation.
230 int CALLBACK MetaFileEnumProc(HDC hdc,
231 HANDLETABLE* table,
232 CONST ENHMETARECORD* record,
233 int table_entries,
234 LPARAM log_font) {
235 if (record->iType == EMR_EXTCREATEFONTINDIRECTW) {
236 const EMREXTCREATEFONTINDIRECTW* create_font_record =
237 reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record);
238 *reinterpret_cast<LOGFONT*>(log_font) = create_font_record->elfw.elfLogFont;
239 }
240 return 1;
241 }
242
243 // Finds a fallback font to use to render the specified |text| with respect to
244 // an initial |font|. Returns the resulting font via out param |result|. Returns
245 // |true| if a fallback font was found.
246 // Adapted from WebKit's |FontCache::GetFontDataForCharacters()|.
247 // TODO(asvitkine): This should be moved to font_fallback_win.cc.
248 bool ChooseFallbackFont(HDC hdc,
249 const Font& font,
250 const wchar_t* text,
251 int text_length,
252 Font* result) {
253 // Use a meta file to intercept the fallback font chosen by Uniscribe.
254 HDC meta_file_dc = CreateEnhMetaFile(hdc, NULL, NULL, NULL);
255 if (!meta_file_dc)
256 return false;
257
258 SelectObject(meta_file_dc, font.GetNativeFont());
259
260 SCRIPT_STRING_ANALYSIS script_analysis;
261 HRESULT hresult =
262 ScriptStringAnalyse(meta_file_dc, text, text_length, 0, -1,
263 SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK,
264 0, NULL, NULL, NULL, NULL, NULL, &script_analysis);
265
266 if (SUCCEEDED(hresult)) {
267 hresult = ScriptStringOut(script_analysis, 0, 0, 0, NULL, 0, 0, FALSE);
268 ScriptStringFree(&script_analysis);
269 }
270
271 bool found_fallback = false;
272 HENHMETAFILE meta_file = CloseEnhMetaFile(meta_file_dc);
273 if (SUCCEEDED(hresult)) {
274 LOGFONT log_font;
275 log_font.lfFaceName[0] = 0;
276 EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL);
277 if (log_font.lfFaceName[0]) {
278 *result = Font(base::UTF16ToUTF8(log_font.lfFaceName),
279 font.GetFontSize());
280 found_fallback = true;
281 }
282 }
283 DeleteEnhMetaFile(meta_file);
284
285 return found_fallback;
286 }
287
288
229 } // namespace 289 } // namespace
230 290
231 namespace internal { 291 namespace internal {
232 292
233 TextRun::TextRun() 293 TextRun::TextRun()
234 : font_style(0), 294 : font_style(0),
235 strike(false), 295 strike(false),
236 diagonal_strike(false), 296 diagonal_strike(false),
237 underline(false), 297 underline(false),
238 width(0), 298 width(0),
(...skipping 753 matching lines...) Expand 10 before | Expand all | Expand 10 after
992 run->width = abc.abcA + abc.abcB + abc.abcC; 1052 run->width = abc.abcA + abc.abcB + abc.abcC;
993 preceding_run_widths += run->width; 1053 preceding_run_widths += run->width;
994 } 1054 }
995 string_width_ = preceding_run_widths; 1055 string_width_ = preceding_run_widths;
996 } 1056 }
997 1057
998 void RenderTextWin::LayoutTextRun(internal::TextRun* run) { 1058 void RenderTextWin::LayoutTextRun(internal::TextRun* run) {
999 const size_t run_length = run->range.length(); 1059 const size_t run_length = run->range.length();
1000 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]); 1060 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]);
1001 Font original_font = run->font; 1061 Font original_font = run->font;
1002 1062 internal::LinkedFontsIterator fonts(original_font);
1003 run->logical_clusters.reset(new WORD[run_length]); 1063 bool tried_cached_font = false;
1004 1064 bool tried_fallback = false;
1005 // Try shaping with |original_font|.
1006 Font current_font = original_font;
1007 int missing_count = CountCharsWithMissingGlyphs(run,
1008 ShapeTextRunWithFont(run, current_font));
1009 if (missing_count == 0)
1010 return;
1011
1012 // Keep track of the font that is able to display the greatest number of 1065 // Keep track of the font that is able to display the greatest number of
1013 // characters for which ScriptShape() returned S_OK. This font will be used 1066 // characters for which ScriptShape() returned S_OK. This font will be used
1014 // in the case where no font is able to display the entire run. 1067 // in the case where no font is able to display the entire run.
1015 int best_partial_font_missing_char_count = missing_count; 1068 int best_partial_font_missing_char_count = INT_MAX;
1016 Font best_partial_font = current_font; 1069 Font best_partial_font = original_font;
1070 Font current_font;
1017 1071
1018 // Try to shape with the cached font from previous runs, if any. 1072 run->logical_clusters.reset(new WORD[run_length]);
1019 std::map<std::string, Font>::const_iterator it = 1073 while (fonts.NextFont(&current_font)) {
1020 successful_substitute_fonts_.find(original_font.GetFontName()); 1074 HRESULT hr = ShapeTextRunWithFont(run, current_font);
1021 if (it != successful_substitute_fonts_.end()) { 1075
1022 current_font = it->second; 1076 bool glyphs_missing = false;
1023 missing_count = CountCharsWithMissingGlyphs(run, 1077 if (hr == USP_E_SCRIPT_NOT_IN_FONT) {
1024 ShapeTextRunWithFont(run, current_font)); 1078 glyphs_missing = true;
1025 if (missing_count == 0) 1079 } else if (hr == S_OK) {
1080 // If |hr| is S_OK, there could still be missing glyphs in the output.
1081 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368564.aspx
1082 const int missing_count = CountCharsWithMissingGlyphs(run);
1083 // Track the font that produced the least missing glyphs.
1084 if (missing_count < best_partial_font_missing_char_count) {
1085 best_partial_font_missing_char_count = missing_count;
1086 best_partial_font = run->font;
1087 }
1088 glyphs_missing = (missing_count != 0);
1089 } else {
1090 NOTREACHED() << hr;
1091 }
1092
1093 // Use the font if it had glyphs for all characters.
1094 if (!glyphs_missing) {
1095 // Save the successful fallback font that was chosen.
1096 if (tried_fallback)
1097 successful_substitute_fonts_[original_font.GetFontName()] = run->font;
1026 return; 1098 return;
1027 if (missing_count < best_partial_font_missing_char_count) { 1099 }
1028 best_partial_font_missing_char_count = missing_count; 1100
1029 best_partial_font = current_font; 1101 // First, try the cached font from previous runs, if any.
1102 if (!tried_cached_font) {
1103 tried_cached_font = true;
1104
1105 std::map<std::string, Font>::const_iterator it =
1106 successful_substitute_fonts_.find(original_font.GetFontName());
1107 if (it != successful_substitute_fonts_.end()) {
1108 fonts.SetNextFont(it->second);
1109 continue;
1110 }
1111 }
1112
1113 // If there are missing glyphs, first try finding a fallback font using a
1114 // meta file, if it hasn't yet been attempted for this run.
1115 // TODO(msw|asvitkine): Support RenderText's font_list()?
1116 if (!tried_fallback) {
1117 tried_fallback = true;
1118
1119 Font fallback_font;
1120 if (ChooseFallbackFont(cached_hdc_, run->font, run_text, run_length,
1121 &fallback_font)) {
1122 fonts.SetNextFont(fallback_font);
1123 continue;
1124 }
1030 } 1125 }
1031 } 1126 }
1032 1127
1033 // Try finding a fallback font using a meta file.
1034 // TODO(msw|asvitkine): Support RenderText's font_list()?
1035 if (GetUniscribeFallbackFont(original_font, run_text, run_length,
1036 &current_font)) {
1037 missing_count = CountCharsWithMissingGlyphs(run,
1038 ShapeTextRunWithFont(run, current_font));
1039 if (missing_count == 0) {
1040 successful_substitute_fonts_[original_font.GetFontName()] = current_font;
1041 return;
1042 }
1043 if (missing_count < best_partial_font_missing_char_count) {
1044 best_partial_font_missing_char_count = missing_count;
1045 best_partial_font = current_font;
1046 }
1047 }
1048
1049 // Try fonts in the fallback list except the first, which is |original_font|.
1050 std::vector<std::string> fonts =
1051 GetFallbackFontFamilies(original_font.GetFontName());
1052 for (size_t i = 1; i < fonts.size(); ++i) {
1053 missing_count = CountCharsWithMissingGlyphs(run,
1054 ShapeTextRunWithFont(run, Font(fonts[i], original_font.GetFontSize())));
1055 if (missing_count == 0) {
1056 successful_substitute_fonts_[original_font.GetFontName()] = current_font;
1057 return;
1058 }
1059 if (missing_count < best_partial_font_missing_char_count) {
1060 best_partial_font_missing_char_count = missing_count;
1061 best_partial_font = current_font;
1062 }
1063 }
1064
1065 // If a font was able to partially display the run, use that now. 1128 // If a font was able to partially display the run, use that now.
1066 if (best_partial_font_missing_char_count < static_cast<int>(run_length)) { 1129 if (best_partial_font_missing_char_count < static_cast<int>(run_length)) {
1067 // Re-shape the run only if |best_partial_font| differs from the last font. 1130 // Re-shape the run only if |best_partial_font| differs from the last font.
1068 if (best_partial_font.GetNativeFont() != run->font.GetNativeFont()) 1131 if (best_partial_font.GetNativeFont() != run->font.GetNativeFont())
1069 ShapeTextRunWithFont(run, best_partial_font); 1132 ShapeTextRunWithFont(run, best_partial_font);
1070 return; 1133 return;
1071 } 1134 }
1072 1135
1073 // If no font was able to partially display the run, replace all glyphs 1136 // If no font was able to partially display the run, replace all glyphs
1074 // with |wgDefault| from the original font to ensure to they don't hold 1137 // with |wgDefault| from the original font to ensure to they don't hold
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
1142 hr = ScriptShape(cached_hdc_, &run->script_cache, run_text, run_length, 1205 hr = ScriptShape(cached_hdc_, &run->script_cache, run_text, run_length,
1143 max_glyphs, &run->script_analysis, run->glyphs.get(), 1206 max_glyphs, &run->script_analysis, run->glyphs.get(),
1144 run->logical_clusters.get(), run->visible_attributes.get(), 1207 run->logical_clusters.get(), run->visible_attributes.get(),
1145 &run->glyph_count); 1208 &run->glyph_count);
1146 // Ensure that |kMaxGlyphs| is attempted and the loop terminates afterward. 1209 // Ensure that |kMaxGlyphs| is attempted and the loop terminates afterward.
1147 max_glyphs = std::max(max_glyphs + 1, std::min(max_glyphs * 2, kMaxGlyphs)); 1210 max_glyphs = std::max(max_glyphs + 1, std::min(max_glyphs * 2, kMaxGlyphs));
1148 } 1211 }
1149 return hr; 1212 return hr;
1150 } 1213 }
1151 1214
1152 int RenderTextWin::CountCharsWithMissingGlyphs(internal::TextRun* run, 1215 int RenderTextWin::CountCharsWithMissingGlyphs(internal::TextRun* run) const {
1153 HRESULT shaping_result) const {
1154 if (shaping_result != S_OK) {
1155 DCHECK_EQ(shaping_result, USP_E_SCRIPT_NOT_IN_FONT);
1156 return INT_MAX;
1157 }
1158
1159 // If |hr| is S_OK, there could still be missing glyphs in the output.
1160 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368564.aspx
1161 int chars_not_missing_glyphs = 0; 1216 int chars_not_missing_glyphs = 0;
1162 SCRIPT_FONTPROPERTIES properties; 1217 SCRIPT_FONTPROPERTIES properties;
1163 memset(&properties, 0, sizeof(properties)); 1218 memset(&properties, 0, sizeof(properties));
1164 properties.cBytes = sizeof(properties); 1219 properties.cBytes = sizeof(properties);
1165 ScriptGetFontProperties(cached_hdc_, &run->script_cache, &properties); 1220 ScriptGetFontProperties(cached_hdc_, &run->script_cache, &properties);
1166 1221
1167 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]); 1222 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]);
1168 for (size_t char_index = 0; char_index < run->range.length(); ++char_index) { 1223 for (size_t char_index = 0; char_index < run->range.length(); ++char_index) {
1169 const int glyph_index = run->logical_clusters[char_index]; 1224 const int glyph_index = run->logical_clusters[char_index];
1170 DCHECK_GE(glyph_index, 0); 1225 DCHECK_GE(glyph_index, 0);
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
1224 size_t position = LayoutIndexToTextIndex(run->range.end()); 1279 size_t position = LayoutIndexToTextIndex(run->range.end());
1225 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); 1280 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD);
1226 return SelectionModel(position, CURSOR_FORWARD); 1281 return SelectionModel(position, CURSOR_FORWARD);
1227 } 1282 }
1228 1283
1229 RenderText* RenderText::CreateNativeInstance() { 1284 RenderText* RenderText::CreateNativeInstance() {
1230 return new RenderTextWin; 1285 return new RenderTextWin;
1231 } 1286 }
1232 1287
1233 } // namespace gfx 1288 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698