| 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 <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "base/i18n/bidi_line_iterator.h" | 9 #include "base/i18n/bidi_line_iterator.h" |
| 10 #include "base/i18n/break_iterator.h" | 10 #include "base/i18n/break_iterator.h" |
| 11 #include "base/i18n/char_iterator.h" | 11 #include "base/i18n/char_iterator.h" |
| 12 #include "base/profiler/scoped_tracker.h" | 12 #include "base/profiler/scoped_tracker.h" |
| 13 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
| 14 #include "base/trace_event/trace_event.h" | 14 #include "base/trace_event/trace_event.h" |
| 15 #include "third_party/harfbuzz-ng/src/hb.h" | 15 #include "third_party/harfbuzz-ng/src/hb.h" |
| 16 #include "third_party/icu/source/common/unicode/ubidi.h" | 16 #include "third_party/icu/source/common/unicode/ubidi.h" |
| 17 #include "third_party/skia/include/core/SkColor.h" | 17 #include "third_party/skia/include/core/SkColor.h" |
| 18 #include "third_party/skia/include/core/SkTypeface.h" | 18 #include "third_party/skia/include/core/SkTypeface.h" |
| 19 #include "ui/gfx/canvas.h" | 19 #include "ui/gfx/canvas.h" |
| 20 #include "ui/gfx/font_fallback.h" | 20 #include "ui/gfx/font_fallback.h" |
| 21 #include "ui/gfx/font_render_params.h" | 21 #include "ui/gfx/font_render_params.h" |
| 22 #include "ui/gfx/geometry/safe_integer_conversions.h" |
| 22 #include "ui/gfx/harfbuzz_font_skia.h" | 23 #include "ui/gfx/harfbuzz_font_skia.h" |
| 23 #include "ui/gfx/range/range_f.h" | 24 #include "ui/gfx/range/range_f.h" |
| 24 #include "ui/gfx/utf16_indexing.h" | 25 #include "ui/gfx/utf16_indexing.h" |
| 25 | 26 |
| 26 #if defined(OS_WIN) | 27 #if defined(OS_WIN) |
| 27 #include "ui/gfx/font_fallback_win.h" | 28 #include "ui/gfx/font_fallback_win.h" |
| 28 #endif | 29 #endif |
| 29 | 30 |
| 30 using gfx::internal::RoundRangeF; | 31 using gfx::internal::RoundRangeF; |
| 31 | 32 |
| (...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 474 } | 475 } |
| 475 | 476 |
| 476 TextRunHarfBuzz::TextRunHarfBuzz() | 477 TextRunHarfBuzz::TextRunHarfBuzz() |
| 477 : width(0.0f), | 478 : width(0.0f), |
| 478 preceding_run_widths(0.0f), | 479 preceding_run_widths(0.0f), |
| 479 is_rtl(false), | 480 is_rtl(false), |
| 480 level(0), | 481 level(0), |
| 481 script(USCRIPT_INVALID_CODE), | 482 script(USCRIPT_INVALID_CODE), |
| 482 glyph_count(static_cast<size_t>(-1)), | 483 glyph_count(static_cast<size_t>(-1)), |
| 483 font_size(0), | 484 font_size(0), |
| 485 baseline_offset(0), |
| 486 baseline_type(0), |
| 484 font_style(0), | 487 font_style(0), |
| 485 strike(false), | 488 strike(false), |
| 486 diagonal_strike(false), | 489 diagonal_strike(false), |
| 487 underline(false) {} | 490 underline(false) { |
| 491 } |
| 488 | 492 |
| 489 TextRunHarfBuzz::~TextRunHarfBuzz() {} | 493 TextRunHarfBuzz::~TextRunHarfBuzz() {} |
| 490 | 494 |
| 491 void TextRunHarfBuzz::GetClusterAt(size_t pos, | 495 void TextRunHarfBuzz::GetClusterAt(size_t pos, |
| 492 Range* chars, | 496 Range* chars, |
| 493 Range* glyphs) const { | 497 Range* glyphs) const { |
| 494 DCHECK(range.Contains(Range(pos, pos + 1))); | 498 DCHECK(range.Contains(Range(pos, pos + 1))); |
| 495 DCHECK(chars); | 499 DCHECK(chars); |
| 496 DCHECK(glyphs); | 500 DCHECK(glyphs); |
| 497 | 501 |
| (...skipping 525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1023 scoped_ptr<SkPoint[]> positions(new SkPoint[glyphs_range.length()]); | 1027 scoped_ptr<SkPoint[]> positions(new SkPoint[glyphs_range.length()]); |
| 1024 SkScalar offset_x = preceding_segment_widths - | 1028 SkScalar offset_x = preceding_segment_widths - |
| 1025 ((glyphs_range.GetMin() != 0) | 1029 ((glyphs_range.GetMin() != 0) |
| 1026 ? run.positions[glyphs_range.GetMin()].x() | 1030 ? run.positions[glyphs_range.GetMin()].x() |
| 1027 : 0); | 1031 : 0); |
| 1028 for (size_t j = 0; j < glyphs_range.length(); ++j) { | 1032 for (size_t j = 0; j < glyphs_range.length(); ++j) { |
| 1029 positions[j] = run.positions[(glyphs_range.is_reversed()) ? | 1033 positions[j] = run.positions[(glyphs_range.is_reversed()) ? |
| 1030 (glyphs_range.start() - j) : | 1034 (glyphs_range.start() - j) : |
| 1031 (glyphs_range.start() + j)]; | 1035 (glyphs_range.start() + j)]; |
| 1032 positions[j].offset(SkIntToScalar(origin.x()) + offset_x, | 1036 positions[j].offset(SkIntToScalar(origin.x()) + offset_x, |
| 1033 SkIntToScalar(origin.y())); | 1037 SkIntToScalar(origin.y() + run.baseline_offset)); |
| 1034 } | 1038 } |
| 1035 for (BreakList<SkColor>::const_iterator it = | 1039 for (BreakList<SkColor>::const_iterator it = |
| 1036 colors().GetBreak(segment.char_range.start()); | 1040 colors().GetBreak(segment.char_range.start()); |
| 1037 it != colors().breaks().end() && | 1041 it != colors().breaks().end() && |
| 1038 it->first < segment.char_range.end(); | 1042 it->first < segment.char_range.end(); |
| 1039 ++it) { | 1043 ++it) { |
| 1040 const Range intersection = | 1044 const Range intersection = |
| 1041 colors().GetRange(it).Intersect(segment.char_range); | 1045 colors().GetRange(it).Intersect(segment.char_range); |
| 1042 const Range colored_glyphs = run.CharRangeToGlyphRange(intersection); | 1046 const Range colored_glyphs = run.CharRangeToGlyphRange(intersection); |
| 1043 // The range may be empty if a portion of a multi-character grapheme is | 1047 // The range may be empty if a portion of a multi-character grapheme is |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1132 internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz; | 1136 internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz; |
| 1133 run->range = Range(0, text.length()); | 1137 run->range = Range(0, text.length()); |
| 1134 run_list_out->add(run); | 1138 run_list_out->add(run); |
| 1135 run_list_out->InitIndexMap(); | 1139 run_list_out->InitIndexMap(); |
| 1136 return; | 1140 return; |
| 1137 } | 1141 } |
| 1138 | 1142 |
| 1139 // Temporarily apply composition underlines and selection colors. | 1143 // Temporarily apply composition underlines and selection colors. |
| 1140 ApplyCompositionAndSelectionStyles(); | 1144 ApplyCompositionAndSelectionStyles(); |
| 1141 | 1145 |
| 1142 // Build the list of runs from the script items and ranged styles. Use an | 1146 // Build the run list from the script items and ranged styles and baselines. |
| 1143 // empty color BreakList to avoid breaking runs at color boundaries. | 1147 // Use an empty color BreakList to avoid breaking runs at color boundaries. |
| 1144 BreakList<SkColor> empty_colors; | 1148 BreakList<SkColor> empty_colors; |
| 1145 empty_colors.SetMax(text.length()); | 1149 empty_colors.SetMax(text.length()); |
| 1146 internal::StyleIterator style(empty_colors, styles()); | 1150 internal::StyleIterator style(empty_colors, baselines(), styles()); |
| 1147 | 1151 |
| 1148 for (size_t run_break = 0; run_break < text.length();) { | 1152 for (size_t run_break = 0; run_break < text.length();) { |
| 1149 internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz; | 1153 internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz; |
| 1150 run->range.set_start(run_break); | 1154 run->range.set_start(run_break); |
| 1151 run->font_style = (style.style(BOLD) ? Font::BOLD : 0) | | 1155 run->font_style = (style.style(BOLD) ? Font::BOLD : 0) | |
| 1152 (style.style(ITALIC) ? Font::ITALIC : 0); | 1156 (style.style(ITALIC) ? Font::ITALIC : 0); |
| 1157 run->baseline_type = style.baseline(); |
| 1153 run->strike = style.style(STRIKE); | 1158 run->strike = style.style(STRIKE); |
| 1154 run->diagonal_strike = style.style(DIAGONAL_STRIKE); | 1159 run->diagonal_strike = style.style(DIAGONAL_STRIKE); |
| 1155 run->underline = style.style(UNDERLINE); | 1160 run->underline = style.style(UNDERLINE); |
| 1156 int32 script_item_break = 0; | 1161 int32 script_item_break = 0; |
| 1157 bidi_iterator.GetLogicalRun(run_break, &script_item_break, &run->level); | 1162 bidi_iterator.GetLogicalRun(run_break, &script_item_break, &run->level); |
| 1158 // Odd BiDi embedding levels correspond to RTL runs. | 1163 // Odd BiDi embedding levels correspond to RTL runs. |
| 1159 run->is_rtl = (run->level % 2) == 1; | 1164 run->is_rtl = (run->level % 2) == 1; |
| 1160 // Find the length and script of this script run. | 1165 // Find the length and script of this script run. |
| 1161 script_item_break = ScriptInterval(text, run_break, | 1166 script_item_break = ScriptInterval(text, run_break, |
| 1162 script_item_break - run_break, &run->script) + run_break; | 1167 script_item_break - run_break, &run->script) + run_break; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1211 for (auto* run : run_list->runs()) | 1216 for (auto* run : run_list->runs()) |
| 1212 ShapeRun(text, run); | 1217 ShapeRun(text, run); |
| 1213 run_list->ComputePrecedingRunWidths(); | 1218 run_list->ComputePrecedingRunWidths(); |
| 1214 } | 1219 } |
| 1215 | 1220 |
| 1216 void RenderTextHarfBuzz::ShapeRun(const base::string16& text, | 1221 void RenderTextHarfBuzz::ShapeRun(const base::string16& text, |
| 1217 internal::TextRunHarfBuzz* run) { | 1222 internal::TextRunHarfBuzz* run) { |
| 1218 const Font& primary_font = font_list().GetPrimaryFont(); | 1223 const Font& primary_font = font_list().GetPrimaryFont(); |
| 1219 const std::string primary_family = primary_font.GetFontName(); | 1224 const std::string primary_family = primary_font.GetFontName(); |
| 1220 run->font_size = primary_font.GetFontSize(); | 1225 run->font_size = primary_font.GetFontSize(); |
| 1226 run->baseline_offset = 0; |
| 1227 if (run->baseline_type != NORMAL_BASELINE) { |
| 1228 // Calculate a slightly smaller font. The ratio here is somewhat arbitrary. |
| 1229 // Proportions from 5/9 to 5/7 all look pretty good. |
| 1230 const float ratio = 5.0f / 9.0f; |
| 1231 run->font_size = gfx::ToRoundedInt(primary_font.GetFontSize() * ratio); |
| 1232 switch (run->baseline_type) { |
| 1233 case SUPERSCRIPT: |
| 1234 run->baseline_offset = |
| 1235 primary_font.GetCapHeight() - primary_font.GetHeight(); |
| 1236 break; |
| 1237 case SUPERIOR: |
| 1238 run->baseline_offset = |
| 1239 gfx::ToRoundedInt(primary_font.GetCapHeight() * ratio) - |
| 1240 primary_font.GetCapHeight(); |
| 1241 break; |
| 1242 case SUBSCRIPT: |
| 1243 run->baseline_offset = |
| 1244 primary_font.GetHeight() - primary_font.GetBaseline(); |
| 1245 break; |
| 1246 case INFERIOR: // Fall through. |
| 1247 default: |
| 1248 break; |
| 1249 } |
| 1250 } |
| 1221 | 1251 |
| 1222 std::string best_family; | 1252 std::string best_family; |
| 1223 FontRenderParams best_render_params; | 1253 FontRenderParams best_render_params; |
| 1224 size_t best_missing_glyphs = std::numeric_limits<size_t>::max(); | 1254 size_t best_missing_glyphs = std::numeric_limits<size_t>::max(); |
| 1225 | 1255 |
| 1226 for (const Font& font : font_list().GetFonts()) { | 1256 for (const Font& font : font_list().GetFonts()) { |
| 1227 if (CompareFamily(text, font.GetFontName(), font.GetFontRenderParams(), | 1257 if (CompareFamily(text, font.GetFontName(), font.GetFontRenderParams(), |
| 1228 run, &best_family, &best_render_params, | 1258 run, &best_family, &best_render_params, |
| 1229 &best_missing_glyphs)) | 1259 &best_missing_glyphs)) |
| 1230 return; | 1260 return; |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1468 DCHECK(!update_layout_run_list_); | 1498 DCHECK(!update_layout_run_list_); |
| 1469 DCHECK(!update_display_run_list_); | 1499 DCHECK(!update_display_run_list_); |
| 1470 return text_elided() ? display_run_list_.get() : &layout_run_list_; | 1500 return text_elided() ? display_run_list_.get() : &layout_run_list_; |
| 1471 } | 1501 } |
| 1472 | 1502 |
| 1473 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const { | 1503 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const { |
| 1474 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList(); | 1504 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList(); |
| 1475 } | 1505 } |
| 1476 | 1506 |
| 1477 } // namespace gfx | 1507 } // namespace gfx |
| OLD | NEW |