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

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

Issue 638413003: Revert 4939383c95030cf963cf5a70ede23c57b212baa4 from M39 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@2171
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
229 } // namespace 288 } // namespace
230 289
231 namespace internal { 290 namespace internal {
232 291
233 TextRun::TextRun() 292 TextRun::TextRun()
234 : font_style(0), 293 : font_style(0),
235 strike(false), 294 strike(false),
236 diagonal_strike(false), 295 diagonal_strike(false),
237 underline(false), 296 underline(false),
238 width(0), 297 width(0),
(...skipping 753 matching lines...) Expand 10 before | Expand all | Expand 10 after
992 run->width = abc.abcA + abc.abcB + abc.abcC; 1051 run->width = abc.abcA + abc.abcB + abc.abcC;
993 preceding_run_widths += run->width; 1052 preceding_run_widths += run->width;
994 } 1053 }
995 string_width_ = preceding_run_widths; 1054 string_width_ = preceding_run_widths;
996 } 1055 }
997 1056
998 void RenderTextWin::LayoutTextRun(internal::TextRun* run) { 1057 void RenderTextWin::LayoutTextRun(internal::TextRun* run) {
999 const size_t run_length = run->range.length(); 1058 const size_t run_length = run->range.length();
1000 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]); 1059 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]);
1001 Font original_font = run->font; 1060 Font original_font = run->font;
1002 1061 internal::LinkedFontsIterator fonts(original_font);
1003 run->logical_clusters.reset(new WORD[run_length]); 1062 bool tried_cached_font = false;
1004 1063 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 1064 // 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 1065 // 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. 1066 // in the case where no font is able to display the entire run.
1015 int best_partial_font_missing_char_count = missing_count; 1067 int best_partial_font_missing_char_count = INT_MAX;
1016 Font best_partial_font = current_font; 1068 Font best_partial_font = original_font;
1069 Font current_font;
1017 1070
1018 // Try to shape with the cached font from previous runs, if any. 1071 run->logical_clusters.reset(new WORD[run_length]);
1019 std::map<std::string, Font>::const_iterator it = 1072 while (fonts.NextFont(&current_font)) {
1020 successful_substitute_fonts_.find(original_font.GetFontName()); 1073 HRESULT hr = ShapeTextRunWithFont(run, current_font);
1021 if (it != successful_substitute_fonts_.end()) { 1074
1022 current_font = it->second; 1075 bool glyphs_missing = false;
1023 missing_count = CountCharsWithMissingGlyphs(run, 1076 if (hr == USP_E_SCRIPT_NOT_IN_FONT) {
1024 ShapeTextRunWithFont(run, current_font)); 1077 glyphs_missing = true;
1025 if (missing_count == 0) 1078 } else if (hr == S_OK) {
1079 // If |hr| is S_OK, there could still be missing glyphs in the output.
1080 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368564.aspx
1081 const int missing_count = CountCharsWithMissingGlyphs(run);
1082 // Track the font that produced the least missing glyphs.
1083 if (missing_count < best_partial_font_missing_char_count) {
1084 best_partial_font_missing_char_count = missing_count;
1085 best_partial_font = run->font;
1086 }
1087 glyphs_missing = (missing_count != 0);
1088 } else {
1089 NOTREACHED() << hr;
1090 }
1091
1092 // Use the font if it had glyphs for all characters.
1093 if (!glyphs_missing) {
1094 // Save the successful fallback font that was chosen.
1095 if (tried_fallback)
1096 successful_substitute_fonts_[original_font.GetFontName()] = run->font;
1026 return; 1097 return;
1027 if (missing_count < best_partial_font_missing_char_count) { 1098 }
1028 best_partial_font_missing_char_count = missing_count; 1099
1029 best_partial_font = current_font; 1100 // First, try the cached font from previous runs, if any.
1101 if (!tried_cached_font) {
1102 tried_cached_font = true;
1103
1104 std::map<std::string, Font>::const_iterator it =
1105 successful_substitute_fonts_.find(original_font.GetFontName());
1106 if (it != successful_substitute_fonts_.end()) {
1107 fonts.SetNextFont(it->second);
1108 continue;
1109 }
1110 }
1111
1112 // If there are missing glyphs, first try finding a fallback font using a
1113 // meta file, if it hasn't yet been attempted for this run.
1114 // TODO(msw|asvitkine): Support RenderText's font_list()?
1115 if (!tried_fallback) {
1116 tried_fallback = true;
1117
1118 Font fallback_font;
1119 if (ChooseFallbackFont(cached_hdc_, run->font, run_text, run_length,
1120 &fallback_font)) {
1121 fonts.SetNextFont(fallback_font);
1122 continue;
1123 }
1030 } 1124 }
1031 } 1125 }
1032 1126
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. 1127 // 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)) { 1128 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. 1129 // Re-shape the run only if |best_partial_font| differs from the last font.
1068 if (best_partial_font.GetNativeFont() != run->font.GetNativeFont()) 1130 if (best_partial_font.GetNativeFont() != run->font.GetNativeFont())
1069 ShapeTextRunWithFont(run, best_partial_font); 1131 ShapeTextRunWithFont(run, best_partial_font);
1070 return; 1132 return;
1071 } 1133 }
1072 1134
1073 // If no font was able to partially display the run, replace all glyphs 1135 // 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 1136 // 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, 1204 hr = ScriptShape(cached_hdc_, &run->script_cache, run_text, run_length,
1143 max_glyphs, &run->script_analysis, run->glyphs.get(), 1205 max_glyphs, &run->script_analysis, run->glyphs.get(),
1144 run->logical_clusters.get(), run->visible_attributes.get(), 1206 run->logical_clusters.get(), run->visible_attributes.get(),
1145 &run->glyph_count); 1207 &run->glyph_count);
1146 // Ensure that |kMaxGlyphs| is attempted and the loop terminates afterward. 1208 // Ensure that |kMaxGlyphs| is attempted and the loop terminates afterward.
1147 max_glyphs = std::max(max_glyphs + 1, std::min(max_glyphs * 2, kMaxGlyphs)); 1209 max_glyphs = std::max(max_glyphs + 1, std::min(max_glyphs * 2, kMaxGlyphs));
1148 } 1210 }
1149 return hr; 1211 return hr;
1150 } 1212 }
1151 1213
1152 int RenderTextWin::CountCharsWithMissingGlyphs(internal::TextRun* run, 1214 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; 1215 int chars_not_missing_glyphs = 0;
1162 SCRIPT_FONTPROPERTIES properties; 1216 SCRIPT_FONTPROPERTIES properties;
1163 memset(&properties, 0, sizeof(properties)); 1217 memset(&properties, 0, sizeof(properties));
1164 properties.cBytes = sizeof(properties); 1218 properties.cBytes = sizeof(properties);
1165 ScriptGetFontProperties(cached_hdc_, &run->script_cache, &properties); 1219 ScriptGetFontProperties(cached_hdc_, &run->script_cache, &properties);
1166 1220
1167 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]); 1221 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]);
1168 for (size_t char_index = 0; char_index < run->range.length(); ++char_index) { 1222 for (size_t char_index = 0; char_index < run->range.length(); ++char_index) {
1169 const int glyph_index = run->logical_clusters[char_index]; 1223 const int glyph_index = run->logical_clusters[char_index];
1170 DCHECK_GE(glyph_index, 0); 1224 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()); 1278 size_t position = LayoutIndexToTextIndex(run->range.end());
1225 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); 1279 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD);
1226 return SelectionModel(position, CURSOR_FORWARD); 1280 return SelectionModel(position, CURSOR_FORWARD);
1227 } 1281 }
1228 1282
1229 RenderText* RenderText::CreateNativeInstance() { 1283 RenderText* RenderText::CreateNativeInstance() {
1230 return new RenderTextWin; 1284 return new RenderTextWin;
1231 } 1285 }
1232 1286
1233 } // namespace gfx 1287 } // 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