Chromium Code Reviews| 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/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 1043 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1054 preceding_run_widths += run->width; | 1054 preceding_run_widths += run->width; |
| 1055 } | 1055 } |
| 1056 string_width_ = preceding_run_widths; | 1056 string_width_ = preceding_run_widths; |
| 1057 } | 1057 } |
| 1058 | 1058 |
| 1059 void RenderTextWin::LayoutTextRun(internal::TextRun* run) { | 1059 void RenderTextWin::LayoutTextRun(internal::TextRun* run) { |
| 1060 const size_t run_length = run->range.length(); | 1060 const size_t run_length = run->range.length(); |
| 1061 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]); | 1061 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]); |
| 1062 Font original_font = run->font; | 1062 Font original_font = run->font; |
| 1063 LinkedFontsIterator fonts(original_font); | 1063 LinkedFontsIterator fonts(original_font); |
| 1064 bool tried_cached_font = false; | 1064 |
| 1065 bool tried_fallback = false; | |
| 1066 // 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 |
| 1067 // 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 |
| 1068 // 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. |
| 1069 int best_partial_font_missing_char_count = INT_MAX; | 1068 int best_partial_font_missing_char_count = INT_MAX; |
| 1070 Font best_partial_font = original_font; | 1069 Font best_partial_font = original_font; |
| 1071 Font current_font; | 1070 Font current_font; |
| 1072 | 1071 |
| 1073 run->logical_clusters.reset(new WORD[run_length]); | 1072 run->logical_clusters.reset(new WORD[run_length]); |
| 1074 while (fonts.NextFont(¤t_font)) { | |
| 1075 HRESULT hr = ShapeTextRunWithFont(run, current_font); | |
| 1076 | 1073 |
| 1077 bool glyphs_missing = false; | 1074 // Try to shape with the first font in the fallback list. |
| 1078 if (hr == USP_E_SCRIPT_NOT_IN_FONT) { | 1075 fonts.NextFont(¤t_font); |
| 1079 glyphs_missing = true; | 1076 int missing_count = CountCharsWithMissingGlyphs(run, |
| 1080 } else if (hr == S_OK) { | 1077 ShapeTextRunWithFont(run, current_font)); |
| 1081 // If |hr| is S_OK, there could still be missing glyphs in the output. | 1078 if (missing_count == 0) |
| 1082 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368564.aspx | 1079 return; |
|
msw
2014/07/10 22:59:50
Should we ever add the original font to |successfu
ckocagil
2014/07/10 23:41:33
I can't see a reason to add the original font. It
msw
2014/07/11 00:08:39
Acknowledged.
| |
| 1083 const int missing_count = CountCharsWithMissingGlyphs(run); | 1080 if (missing_count < best_partial_font_missing_char_count) { |
| 1084 // Track the font that produced the least missing glyphs. | 1081 best_partial_font_missing_char_count = missing_count; |
|
msw
2014/07/10 22:59:50
We may as well declare and initialize |best_partia
ckocagil
2014/07/10 23:41:33
Done.
| |
| 1085 if (missing_count < best_partial_font_missing_char_count) { | 1082 best_partial_font = run->font; |
| 1086 best_partial_font_missing_char_count = missing_count; | 1083 } |
| 1087 best_partial_font = run->font; | |
| 1088 } | |
| 1089 glyphs_missing = (missing_count != 0); | |
| 1090 } else { | |
| 1091 NOTREACHED() << hr; | |
| 1092 } | |
| 1093 | 1084 |
| 1094 // Use the font if it had glyphs for all characters. | 1085 // Try to shape with the cached font from previous runs, if any. |
| 1095 if (!glyphs_missing) { | 1086 std::map<std::string, Font>::const_iterator it = |
| 1096 // Save the successful fallback font that was chosen. | 1087 successful_substitute_fonts_.find(original_font.GetFontName()); |
| 1097 if (tried_fallback) | 1088 if (it != successful_substitute_fonts_.end()) { |
| 1098 successful_substitute_fonts_[original_font.GetFontName()] = run->font; | 1089 current_font = it->second; |
| 1090 missing_count = CountCharsWithMissingGlyphs(run, | |
| 1091 ShapeTextRunWithFont(run, current_font)); | |
| 1092 if (missing_count == 0) { | |
| 1093 successful_substitute_fonts_[original_font.GetFontName()] = run->font; | |
|
msw
2014/07/10 22:59:50
Isn't this value already set? Can we skip this?
ckocagil
2014/07/10 23:41:33
Done.
| |
| 1099 return; | 1094 return; |
| 1100 } | 1095 } |
| 1101 | 1096 if (missing_count < best_partial_font_missing_char_count) { |
| 1102 // First, try the cached font from previous runs, if any. | 1097 best_partial_font_missing_char_count = missing_count; |
| 1103 if (!tried_cached_font) { | 1098 best_partial_font = run->font; |
| 1104 tried_cached_font = true; | |
| 1105 | |
| 1106 std::map<std::string, Font>::const_iterator it = | |
| 1107 successful_substitute_fonts_.find(original_font.GetFontName()); | |
| 1108 if (it != successful_substitute_fonts_.end()) { | |
| 1109 fonts.SetNextFont(it->second); | |
| 1110 continue; | |
| 1111 } | |
| 1112 } | |
| 1113 | |
| 1114 // If there are missing glyphs, first try finding a fallback font using a | |
| 1115 // meta file, if it hasn't yet been attempted for this run. | |
| 1116 // TODO(msw|asvitkine): Support RenderText's font_list()? | |
| 1117 if (!tried_fallback) { | |
| 1118 tried_fallback = true; | |
| 1119 | |
| 1120 Font fallback_font; | |
| 1121 if (ChooseFallbackFont(cached_hdc_, run->font, run_text, run_length, | |
| 1122 &fallback_font)) { | |
| 1123 fonts.SetNextFont(fallback_font); | |
| 1124 continue; | |
| 1125 } | |
| 1126 } | 1099 } |
| 1127 } | 1100 } |
| 1128 | 1101 |
| 1102 // Try finding a fallback font using a meta file. | |
| 1103 // TODO(msw|asvitkine): Support RenderText's font_list()? | |
| 1104 if (ChooseFallbackFont(cached_hdc_, run->font, run_text, run_length, | |
| 1105 ¤t_font)) { | |
| 1106 missing_count = CountCharsWithMissingGlyphs(run, | |
| 1107 ShapeTextRunWithFont(run, current_font)); | |
| 1108 if (missing_count == 0) { | |
| 1109 successful_substitute_fonts_[original_font.GetFontName()] = run->font; | |
| 1110 return; | |
| 1111 } | |
| 1112 if (missing_count < best_partial_font_missing_char_count) { | |
| 1113 best_partial_font_missing_char_count = missing_count; | |
| 1114 best_partial_font = run->font; | |
| 1115 } | |
| 1116 } | |
| 1117 | |
| 1118 // Try the rest of fonts in the fallback list. | |
| 1119 while (fonts.NextFont(¤t_font)) { | |
| 1120 missing_count = CountCharsWithMissingGlyphs(run, | |
| 1121 ShapeTextRunWithFont(run, current_font)); | |
| 1122 if (missing_count < best_partial_font_missing_char_count) { | |
| 1123 best_partial_font_missing_char_count = missing_count; | |
| 1124 best_partial_font = run->font; | |
| 1125 } | |
| 1126 if (missing_count == 0) { | |
| 1127 successful_substitute_fonts_[original_font.GetFontName()] = run->font; | |
| 1128 return; | |
| 1129 } | |
| 1130 } | |
| 1131 | |
| 1129 // If a font was able to partially display the run, use that now. | 1132 // If a font was able to partially display the run, use that now. |
| 1130 if (best_partial_font_missing_char_count < static_cast<int>(run_length)) { | 1133 if (best_partial_font_missing_char_count < static_cast<int>(run_length)) { |
| 1131 // Re-shape the run only if |best_partial_font| differs from the last font. | 1134 // Re-shape the run only if |best_partial_font| differs from the last font. |
| 1132 if (best_partial_font.GetNativeFont() != run->font.GetNativeFont()) | 1135 if (best_partial_font.GetNativeFont() != run->font.GetNativeFont()) |
| 1133 ShapeTextRunWithFont(run, best_partial_font); | 1136 ShapeTextRunWithFont(run, best_partial_font); |
| 1134 return; | 1137 return; |
| 1135 } | 1138 } |
| 1136 | 1139 |
| 1137 // If no font was able to partially display the run, replace all glyphs | 1140 // If no font was able to partially display the run, replace all glyphs |
| 1138 // with |wgDefault| from the original font to ensure to they don't hold | 1141 // 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 Loading... | |
| 1206 hr = ScriptShape(cached_hdc_, &run->script_cache, run_text, run_length, | 1209 hr = ScriptShape(cached_hdc_, &run->script_cache, run_text, run_length, |
| 1207 max_glyphs, &run->script_analysis, run->glyphs.get(), | 1210 max_glyphs, &run->script_analysis, run->glyphs.get(), |
| 1208 run->logical_clusters.get(), run->visible_attributes.get(), | 1211 run->logical_clusters.get(), run->visible_attributes.get(), |
| 1209 &run->glyph_count); | 1212 &run->glyph_count); |
| 1210 // Ensure that |kMaxGlyphs| is attempted and the loop terminates afterward. | 1213 // Ensure that |kMaxGlyphs| is attempted and the loop terminates afterward. |
| 1211 max_glyphs = std::max(max_glyphs + 1, std::min(max_glyphs * 2, kMaxGlyphs)); | 1214 max_glyphs = std::max(max_glyphs + 1, std::min(max_glyphs * 2, kMaxGlyphs)); |
| 1212 } | 1215 } |
| 1213 return hr; | 1216 return hr; |
| 1214 } | 1217 } |
| 1215 | 1218 |
| 1216 int RenderTextWin::CountCharsWithMissingGlyphs(internal::TextRun* run) const { | 1219 int RenderTextWin::CountCharsWithMissingGlyphs(internal::TextRun* run, |
| 1220 HRESULT shaping_result) const { | |
| 1221 if (shaping_result == USP_E_SCRIPT_NOT_IN_FONT) | |
|
msw
2014/07/10 22:59:50
nit: if (shaping_result != S_OK) { DCHECK_EQ(shapi
ckocagil
2014/07/10 23:41:33
Done.
| |
| 1222 return INT_MAX; | |
| 1223 if (shaping_result != S_OK) { | |
| 1224 NOTREACHED() << shaping_result; | |
| 1225 return INT_MAX; | |
| 1226 } | |
| 1227 | |
| 1228 // If |hr| is S_OK, there could still be missing glyphs in the output. | |
| 1229 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368564.aspx | |
| 1217 int chars_not_missing_glyphs = 0; | 1230 int chars_not_missing_glyphs = 0; |
| 1218 SCRIPT_FONTPROPERTIES properties; | 1231 SCRIPT_FONTPROPERTIES properties; |
| 1219 memset(&properties, 0, sizeof(properties)); | 1232 memset(&properties, 0, sizeof(properties)); |
| 1220 properties.cBytes = sizeof(properties); | 1233 properties.cBytes = sizeof(properties); |
| 1221 ScriptGetFontProperties(cached_hdc_, &run->script_cache, &properties); | 1234 ScriptGetFontProperties(cached_hdc_, &run->script_cache, &properties); |
| 1222 | 1235 |
| 1223 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]); | 1236 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]); |
| 1224 for (size_t char_index = 0; char_index < run->range.length(); ++char_index) { | 1237 for (size_t char_index = 0; char_index < run->range.length(); ++char_index) { |
| 1225 const int glyph_index = run->logical_clusters[char_index]; | 1238 const int glyph_index = run->logical_clusters[char_index]; |
| 1226 DCHECK_GE(glyph_index, 0); | 1239 DCHECK_GE(glyph_index, 0); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1280 size_t position = LayoutIndexToTextIndex(run->range.end()); | 1293 size_t position = LayoutIndexToTextIndex(run->range.end()); |
| 1281 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); | 1294 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); |
| 1282 return SelectionModel(position, CURSOR_FORWARD); | 1295 return SelectionModel(position, CURSOR_FORWARD); |
| 1283 } | 1296 } |
| 1284 | 1297 |
| 1285 RenderText* RenderText::CreateNativeInstance() { | 1298 RenderText* RenderText::CreateNativeInstance() { |
| 1286 return new RenderTextWin; | 1299 return new RenderTextWin; |
| 1287 } | 1300 } |
| 1288 | 1301 |
| 1289 } // namespace gfx | 1302 } // namespace gfx |
| OLD | NEW |