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 |