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; | 1065 run->logical_clusters.reset(new WORD[run_length]); |
1066 | |
1067 // Try to shape with the first font in the fallback list, which is | |
1068 // |original_font|. | |
1069 Font current_font; | |
1070 fonts.NextFont(¤t_font); | |
1071 int missing_count = CountCharsWithMissingGlyphs(run, | |
1072 ShapeTextRunWithFont(run, current_font)); | |
1073 if (missing_count == 0) | |
1074 return; | |
1075 | |
1066 // Keep track of the font that is able to display the greatest number of | 1076 // 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 | 1077 // 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. | 1078 // in the case where no font is able to display the entire run. |
1069 int best_partial_font_missing_char_count = INT_MAX; | 1079 int best_partial_font_missing_char_count = missing_count; |
1070 Font best_partial_font = original_font; | 1080 Font best_partial_font = current_font; |
1071 Font current_font; | |
1072 | 1081 |
1073 run->logical_clusters.reset(new WORD[run_length]); | 1082 // Try to shape with the cached font from previous runs, if any. |
1074 while (fonts.NextFont(¤t_font)) { | 1083 std::map<std::string, Font>::const_iterator it = |
1075 HRESULT hr = ShapeTextRunWithFont(run, current_font); | 1084 successful_substitute_fonts_.find(original_font.GetFontName()); |
1076 | 1085 if (it != successful_substitute_fonts_.end()) { |
1077 bool glyphs_missing = false; | 1086 current_font = it->second; |
1078 if (hr == USP_E_SCRIPT_NOT_IN_FONT) { | 1087 missing_count = CountCharsWithMissingGlyphs(run, |
1079 glyphs_missing = true; | 1088 ShapeTextRunWithFont(run, current_font)); |
1080 } else if (hr == S_OK) { | 1089 if (missing_count == 0) |
1081 // If |hr| is S_OK, there could still be missing glyphs in the output. | |
1082 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368564.aspx | |
1083 const int missing_count = CountCharsWithMissingGlyphs(run); | |
1084 // Track the font that produced the least missing glyphs. | |
1085 if (missing_count < best_partial_font_missing_char_count) { | |
1086 best_partial_font_missing_char_count = missing_count; | |
1087 best_partial_font = run->font; | |
1088 } | |
1089 glyphs_missing = (missing_count != 0); | |
1090 } else { | |
1091 NOTREACHED() << hr; | |
1092 } | |
1093 | |
1094 // Use the font if it had glyphs for all characters. | |
1095 if (!glyphs_missing) { | |
1096 // Save the successful fallback font that was chosen. | |
1097 if (tried_fallback) | |
1098 successful_substitute_fonts_[original_font.GetFontName()] = run->font; | |
1099 return; | 1090 return; |
1100 } | 1091 if (missing_count < best_partial_font_missing_char_count) { |
1101 | 1092 best_partial_font_missing_char_count = missing_count; |
1102 // First, try the cached font from previous runs, if any. | 1093 best_partial_font = current_font; |
1103 if (!tried_cached_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 } | 1094 } |
1127 } | 1095 } |
1128 | 1096 |
1097 // Try finding a fallback font using a meta file. | |
1098 // TODO(msw|asvitkine): Support RenderText's font_list()? | |
1099 if (ChooseFallbackFont(cached_hdc_, run->font, run_text, run_length, | |
1100 ¤t_font)) { | |
1101 missing_count = CountCharsWithMissingGlyphs(run, | |
1102 ShapeTextRunWithFont(run, current_font)); | |
Alexei Svitkine (slow)
2014/07/15 19:48:20
If these two functions are always called together
| |
1103 if (missing_count == 0) { | |
1104 successful_substitute_fonts_[original_font.GetFontName()] = current_font; | |
1105 return; | |
1106 } | |
1107 if (missing_count < best_partial_font_missing_char_count) { | |
1108 best_partial_font_missing_char_count = missing_count; | |
1109 best_partial_font = current_font; | |
1110 } | |
1111 } | |
1112 | |
1113 // Try the rest of fonts in the fallback list. | |
1114 while (fonts.NextFont(¤t_font)) { | |
Alexei Svitkine (slow)
2014/07/15 19:48:20
Now that you're not calling SetNextFont() on |font
| |
1115 missing_count = CountCharsWithMissingGlyphs(run, | |
1116 ShapeTextRunWithFont(run, current_font)); | |
1117 if (missing_count == 0) { | |
1118 successful_substitute_fonts_[original_font.GetFontName()] = current_font; | |
1119 return; | |
1120 } | |
1121 if (missing_count < best_partial_font_missing_char_count) { | |
1122 best_partial_font_missing_char_count = missing_count; | |
1123 best_partial_font = current_font; | |
1124 } | |
1125 } | |
1126 | |
1129 // 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. |
1130 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)) { |
1131 // 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. |
1132 if (best_partial_font.GetNativeFont() != run->font.GetNativeFont()) | 1130 if (best_partial_font.GetNativeFont() != run->font.GetNativeFont()) |
1133 ShapeTextRunWithFont(run, best_partial_font); | 1131 ShapeTextRunWithFont(run, best_partial_font); |
1134 return; | 1132 return; |
1135 } | 1133 } |
1136 | 1134 |
1137 // 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 |
1138 // 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 Loading... | |
1206 hr = ScriptShape(cached_hdc_, &run->script_cache, run_text, run_length, | 1204 hr = ScriptShape(cached_hdc_, &run->script_cache, run_text, run_length, |
1207 max_glyphs, &run->script_analysis, run->glyphs.get(), | 1205 max_glyphs, &run->script_analysis, run->glyphs.get(), |
1208 run->logical_clusters.get(), run->visible_attributes.get(), | 1206 run->logical_clusters.get(), run->visible_attributes.get(), |
1209 &run->glyph_count); | 1207 &run->glyph_count); |
1210 // Ensure that |kMaxGlyphs| is attempted and the loop terminates afterward. | 1208 // Ensure that |kMaxGlyphs| is attempted and the loop terminates afterward. |
1211 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)); |
1212 } | 1210 } |
1213 return hr; | 1211 return hr; |
1214 } | 1212 } |
1215 | 1213 |
1216 int RenderTextWin::CountCharsWithMissingGlyphs(internal::TextRun* run) const { | 1214 int RenderTextWin::CountCharsWithMissingGlyphs(internal::TextRun* run, |
1215 HRESULT shaping_result) const { | |
1216 if (shaping_result != S_OK) { | |
1217 DCHECK_EQ(shaping_result, USP_E_SCRIPT_NOT_IN_FONT); | |
Alexei Svitkine (slow)
2014/07/15 19:48:20
Nit: The expected value constant should be the fir
| |
1218 return INT_MAX; | |
Alexei Svitkine (slow)
2014/07/15 19:48:20
What does it mean for INT_MAX to be returned by th
| |
1219 } | |
1220 | |
1221 // If |hr| is S_OK, there could still be missing glyphs in the output. | |
1222 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368564.aspx | |
1217 int chars_not_missing_glyphs = 0; | 1223 int chars_not_missing_glyphs = 0; |
1218 SCRIPT_FONTPROPERTIES properties; | 1224 SCRIPT_FONTPROPERTIES properties; |
1219 memset(&properties, 0, sizeof(properties)); | 1225 memset(&properties, 0, sizeof(properties)); |
1220 properties.cBytes = sizeof(properties); | 1226 properties.cBytes = sizeof(properties); |
1221 ScriptGetFontProperties(cached_hdc_, &run->script_cache, &properties); | 1227 ScriptGetFontProperties(cached_hdc_, &run->script_cache, &properties); |
1222 | 1228 |
1223 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]); | 1229 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]); |
1224 for (size_t char_index = 0; char_index < run->range.length(); ++char_index) { | 1230 for (size_t char_index = 0; char_index < run->range.length(); ++char_index) { |
1225 const int glyph_index = run->logical_clusters[char_index]; | 1231 const int glyph_index = run->logical_clusters[char_index]; |
1226 DCHECK_GE(glyph_index, 0); | 1232 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()); | 1286 size_t position = LayoutIndexToTextIndex(run->range.end()); |
1281 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); | 1287 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); |
1282 return SelectionModel(position, CURSOR_FORWARD); | 1288 return SelectionModel(position, CURSOR_FORWARD); |
1283 } | 1289 } |
1284 | 1290 |
1285 RenderText* RenderText::CreateNativeInstance() { | 1291 RenderText* RenderText::CreateNativeInstance() { |
1286 return new RenderTextWin; | 1292 return new RenderTextWin; |
1287 } | 1293 } |
1288 | 1294 |
1289 } // namespace gfx | 1295 } // namespace gfx |
OLD | NEW |