Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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_harfbuzz.h" | 5 #include "ui/gfx/render_text_harfbuzz.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 | 8 |
| 9 #include "base/debug/leak_annotations.h" | 9 #include "base/debug/leak_annotations.h" |
| 10 #include "base/i18n/bidi_line_iterator.h" | 10 #include "base/i18n/bidi_line_iterator.h" |
| (...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 447 | 447 |
| 448 TextRunHarfBuzz::~TextRunHarfBuzz() {} | 448 TextRunHarfBuzz::~TextRunHarfBuzz() {} |
| 449 | 449 |
| 450 void TextRunHarfBuzz::GetClusterAt(size_t pos, | 450 void TextRunHarfBuzz::GetClusterAt(size_t pos, |
| 451 Range* chars, | 451 Range* chars, |
| 452 Range* glyphs) const { | 452 Range* glyphs) const { |
| 453 DCHECK(range.Contains(Range(pos, pos + 1))); | 453 DCHECK(range.Contains(Range(pos, pos + 1))); |
| 454 DCHECK(chars); | 454 DCHECK(chars); |
| 455 DCHECK(glyphs); | 455 DCHECK(glyphs); |
| 456 | 456 |
| 457 if (glyph_count == 0) { | |
| 458 *chars = range; | |
| 459 *glyphs = Range(); | |
| 460 return; | |
| 461 } | |
| 462 | |
| 457 if (is_rtl) { | 463 if (is_rtl) { |
| 458 GetClusterAtImpl(pos, range, glyph_to_char.rbegin(), glyph_to_char.rend(), | 464 GetClusterAtImpl(pos, range, glyph_to_char.rbegin(), glyph_to_char.rend(), |
| 459 true, chars, glyphs); | 465 true, chars, glyphs); |
| 460 return; | 466 return; |
| 461 } | 467 } |
| 462 | 468 |
| 463 GetClusterAtImpl(pos, range, glyph_to_char.begin(), glyph_to_char.end(), | 469 GetClusterAtImpl(pos, range, glyph_to_char.begin(), glyph_to_char.end(), |
| 464 false, chars, glyphs); | 470 false, chars, glyphs); |
| 465 } | 471 } |
| 466 | 472 |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 484 size_t missing = 0; | 490 size_t missing = 0; |
| 485 for (size_t i = 0; i < glyph_count; ++i) | 491 for (size_t i = 0; i < glyph_count; ++i) |
| 486 missing += (glyphs[i] == kMissingGlyphId) ? 1 : 0; | 492 missing += (glyphs[i] == kMissingGlyphId) ? 1 : 0; |
| 487 return missing; | 493 return missing; |
| 488 } | 494 } |
| 489 | 495 |
| 490 Range TextRunHarfBuzz::GetGraphemeBounds( | 496 Range TextRunHarfBuzz::GetGraphemeBounds( |
| 491 base::i18n::BreakIterator* grapheme_iterator, | 497 base::i18n::BreakIterator* grapheme_iterator, |
| 492 size_t text_index) { | 498 size_t text_index) { |
| 493 DCHECK_LT(text_index, range.end()); | 499 DCHECK_LT(text_index, range.end()); |
| 500 if (glyph_count == 0) | |
| 501 return Range(preceding_run_widths, preceding_run_widths + width); | |
| 494 | 502 |
| 495 Range chars; | 503 Range chars; |
| 496 Range glyphs; | 504 Range glyphs; |
| 497 GetClusterAt(text_index, &chars, &glyphs); | 505 GetClusterAt(text_index, &chars, &glyphs); |
| 498 const int cluster_begin_x = SkScalarRoundToInt(positions[glyphs.start()].x()); | 506 const int cluster_begin_x = SkScalarRoundToInt(positions[glyphs.start()].x()); |
| 499 const int cluster_end_x = glyphs.end() < glyph_count ? | 507 const int cluster_end_x = glyphs.end() < glyph_count ? |
| 500 SkScalarRoundToInt(positions[glyphs.end()].x()) : width; | 508 SkScalarRoundToInt(positions[glyphs.end()].x()) : width; |
| 501 | 509 |
| 502 // A cluster consists of a number of code points and corresponds to a number | 510 // A cluster consists of a number of code points and corresponds to a number |
| 503 // of glyphs that should be drawn together. A cluster can contain multiple | 511 // of glyphs that should be drawn together. A cluster can contain multiple |
| (...skipping 497 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1001 ubidi_reorderVisual(&levels[0], num_runs, &visual_to_logical_[0]); | 1009 ubidi_reorderVisual(&levels[0], num_runs, &visual_to_logical_[0]); |
| 1002 logical_to_visual_.resize(num_runs); | 1010 logical_to_visual_.resize(num_runs); |
| 1003 ubidi_reorderLogical(&levels[0], num_runs, &logical_to_visual_[0]); | 1011 ubidi_reorderLogical(&levels[0], num_runs, &logical_to_visual_[0]); |
| 1004 } | 1012 } |
| 1005 | 1013 |
| 1006 void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) { | 1014 void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) { |
| 1007 const Font& primary_font = font_list().GetPrimaryFont(); | 1015 const Font& primary_font = font_list().GetPrimaryFont(); |
| 1008 const std::string primary_font_name = primary_font.GetFontName(); | 1016 const std::string primary_font_name = primary_font.GetFontName(); |
| 1009 run->font_size = primary_font.GetFontSize(); | 1017 run->font_size = primary_font.GetFontSize(); |
| 1010 | 1018 |
| 1019 size_t best_font_missing = std::numeric_limits<size_t>::max(); | |
| 1020 std::string best_font; | |
| 1021 std::string current_font; | |
| 1022 | |
| 1011 // Try shaping with |primary_font|. | 1023 // Try shaping with |primary_font|. |
| 1012 ShapeRunWithFont(run, primary_font_name); | 1024 if (ShapeRunWithFont(run, primary_font_name)) { |
| 1013 size_t best_font_missing = run->CountMissingGlyphs(); | 1025 current_font = primary_font_name; |
| 1014 if (best_font_missing == 0) | 1026 size_t current_missing = run->CountMissingGlyphs(); |
| 1015 return; | 1027 if (current_missing == 0) |
| 1016 std::string best_font = primary_font_name; | 1028 return; |
| 1029 if (current_missing < best_font_missing) { | |
| 1030 best_font_missing = current_missing; | |
| 1031 best_font = primary_font_name; | |
|
msw
2014/08/02 18:05:33
nit: s/primary_font_name/current_font/
ckocagil
2014/08/03 03:36:54
Done.
| |
| 1032 } | |
| 1033 } | |
| 1017 | 1034 |
| 1018 #if defined(OS_WIN) | 1035 #if defined(OS_WIN) |
| 1019 Font uniscribe_font; | 1036 Font uniscribe_font; |
| 1020 const base::char16* run_text = &(GetLayoutText()[run->range.start()]); | 1037 const base::char16* run_text = &(GetLayoutText()[run->range.start()]); |
| 1021 if (GetUniscribeFallbackFont(primary_font, run_text, run->range.length(), | 1038 if (GetUniscribeFallbackFont(primary_font, run_text, run->range.length(), |
| 1022 &uniscribe_font)) { | 1039 &uniscribe_font) && |
| 1023 ShapeRunWithFont(run, uniscribe_font.GetFontName()); | 1040 ShapeRunWithFont(run, uniscribe_font.GetFontName())) { |
| 1041 current_font = uniscribe_font.GetFontName(); | |
| 1024 size_t current_missing = run->CountMissingGlyphs(); | 1042 size_t current_missing = run->CountMissingGlyphs(); |
| 1025 if (current_missing == 0) | 1043 if (current_missing == 0) |
| 1026 return; | 1044 return; |
| 1027 if (current_missing < best_font_missing) { | 1045 if (current_missing < best_font_missing) { |
| 1028 best_font_missing = current_missing; | 1046 best_font_missing = current_missing; |
| 1029 best_font = uniscribe_font.GetFontName(); | 1047 best_font = uniscribe_font.GetFontName(); |
|
msw
2014/08/02 18:05:33
nit: s/uniscribe_font.GetFontName()/current_font/
ckocagil
2014/08/03 03:36:54
Done.
| |
| 1030 } | 1048 } |
| 1031 } | 1049 } |
| 1032 #endif | 1050 #endif |
| 1033 | 1051 |
| 1034 // Try shaping with the fonts in the fallback list except the first, which is | 1052 // Try shaping with the fonts in the fallback list except the first, which is |
| 1035 // |primary_font|. | 1053 // |primary_font|. |
| 1036 std::vector<std::string> fonts = GetFallbackFontFamilies(primary_font_name); | 1054 std::vector<std::string> fonts = GetFallbackFontFamilies(primary_font_name); |
| 1037 for (size_t i = 1; i < fonts.size(); ++i) { | 1055 for (size_t i = 1; i < fonts.size(); ++i) { |
| 1038 ShapeRunWithFont(run, fonts[i]); | 1056 if (!ShapeRunWithFont(run, fonts[i])) |
| 1057 continue; | |
| 1058 current_font = fonts[i]; | |
| 1039 size_t current_missing = run->CountMissingGlyphs(); | 1059 size_t current_missing = run->CountMissingGlyphs(); |
| 1040 if (current_missing == 0) | 1060 if (current_missing == 0) |
| 1041 return; | 1061 return; |
| 1042 if (current_missing < best_font_missing) { | 1062 if (current_missing < best_font_missing) { |
| 1043 best_font_missing = current_missing; | 1063 best_font_missing = current_missing; |
| 1044 best_font = fonts[i]; | 1064 best_font = fonts[i]; |
|
msw
2014/08/02 18:05:33
nit: s/fonts[i]/current_font/
ckocagil
2014/08/03 03:36:54
Done.
| |
| 1045 } | 1065 } |
| 1046 } | 1066 } |
| 1047 | 1067 |
| 1048 ShapeRunWithFont(run, best_font); | 1068 if (!best_font.empty() && |
| 1069 (best_font == current_font || ShapeRunWithFont(run, best_font))) { | |
| 1070 return; | |
| 1071 } | |
| 1072 | |
| 1073 run->glyph_count = 0; | |
| 1074 run->width = 0; | |
| 1049 } | 1075 } |
| 1050 | 1076 |
| 1051 void RenderTextHarfBuzz::ShapeRunWithFont(internal::TextRunHarfBuzz* run, | 1077 bool RenderTextHarfBuzz::ShapeRunWithFont(internal::TextRunHarfBuzz* run, |
| 1052 const std::string& font_family) { | 1078 const std::string& font_family) { |
| 1053 const base::string16& text = GetLayoutText(); | 1079 const base::string16& text = GetLayoutText(); |
| 1054 run->skia_face = internal::CreateSkiaTypeface(font_family, run->font_style); | 1080 skia::RefPtr<SkTypeface> skia_face = |
| 1081 internal::CreateSkiaTypeface(font_family, run->font_style); | |
| 1082 if (skia_face == NULL) | |
| 1083 return false; | |
| 1084 run->skia_face = skia_face; | |
| 1055 hb_font_t* harfbuzz_font = CreateHarfBuzzFont(run->skia_face.get(), | 1085 hb_font_t* harfbuzz_font = CreateHarfBuzzFont(run->skia_face.get(), |
| 1056 run->font_size); | 1086 run->font_size); |
| 1057 | 1087 |
| 1058 // Create a HarfBuzz buffer and add the string to be shaped. The HarfBuzz | 1088 // Create a HarfBuzz buffer and add the string to be shaped. The HarfBuzz |
| 1059 // buffer holds our text, run information to be used by the shaping engine, | 1089 // buffer holds our text, run information to be used by the shaping engine, |
| 1060 // and the resulting glyph data. | 1090 // and the resulting glyph data. |
| 1061 hb_buffer_t* buffer = hb_buffer_create(); | 1091 hb_buffer_t* buffer = hb_buffer_create(); |
| 1062 hb_buffer_add_utf16(buffer, reinterpret_cast<const uint16*>(text.c_str()), | 1092 hb_buffer_add_utf16(buffer, reinterpret_cast<const uint16*>(text.c_str()), |
| 1063 text.length(), run->range.start(), run->range.length()); | 1093 text.length(), run->range.start(), run->range.length()); |
| 1064 hb_buffer_set_script(buffer, ICUScriptToHBScript(run->script)); | 1094 hb_buffer_set_script(buffer, ICUScriptToHBScript(run->script)); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 1087 SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_offset)); | 1117 SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_offset)); |
| 1088 const int y_offset = | 1118 const int y_offset = |
| 1089 SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].y_offset)); | 1119 SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].y_offset)); |
| 1090 run->positions[i].set(run->width + x_offset, -y_offset); | 1120 run->positions[i].set(run->width + x_offset, -y_offset); |
| 1091 run->width += | 1121 run->width += |
| 1092 SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_advance)); | 1122 SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_advance)); |
| 1093 } | 1123 } |
| 1094 | 1124 |
| 1095 hb_buffer_destroy(buffer); | 1125 hb_buffer_destroy(buffer); |
| 1096 hb_font_destroy(harfbuzz_font); | 1126 hb_font_destroy(harfbuzz_font); |
| 1127 return true; | |
| 1097 } | 1128 } |
| 1098 | 1129 |
| 1099 } // namespace gfx | 1130 } // namespace gfx |
| OLD | NEW |