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 |