| 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" |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 // height for each line. | 213 // height for each line. |
| 214 // TODO(ckocagil): Expose the interface of this class in the header and test | 214 // TODO(ckocagil): Expose the interface of this class in the header and test |
| 215 // this class directly. | 215 // this class directly. |
| 216 class HarfBuzzLineBreaker { | 216 class HarfBuzzLineBreaker { |
| 217 public: | 217 public: |
| 218 HarfBuzzLineBreaker(size_t max_width, | 218 HarfBuzzLineBreaker(size_t max_width, |
| 219 int min_baseline, | 219 int min_baseline, |
| 220 float min_height, | 220 float min_height, |
| 221 bool multiline, | 221 bool multiline, |
| 222 const base::string16& text, | 222 const base::string16& text, |
| 223 const std::vector<int32_t>& logical_to_visual, |
| 223 const BreakList<size_t>* words, | 224 const BreakList<size_t>* words, |
| 224 const ScopedVector<internal::TextRunHarfBuzz>& runs) | 225 const ScopedVector<internal::TextRunHarfBuzz>& runs) |
| 225 : max_width_((max_width == 0) ? SK_ScalarMax : SkIntToScalar(max_width)), | 226 : max_width_((max_width == 0) ? SK_ScalarMax : SkIntToScalar(max_width)), |
| 226 min_baseline_(min_baseline), | 227 min_baseline_(min_baseline), |
| 227 min_height_(min_height), | 228 min_height_(min_height), |
| 228 multiline_(multiline), | 229 multiline_(multiline), |
| 229 text_(text), | 230 text_(text), |
| 231 logical_to_visual_(logical_to_visual), |
| 230 words_(words), | 232 words_(words), |
| 231 runs_(runs), | 233 runs_(runs), |
| 232 text_x_(0), | 234 text_x_(0), |
| 233 line_x_(0), | 235 line_x_(0), |
| 234 max_descent_(0), | 236 max_descent_(0), |
| 235 max_ascent_(0) { | 237 max_ascent_(0) { |
| 236 DCHECK_EQ(multiline_, (words_ != nullptr)); | 238 DCHECK_EQ(multiline_, (words_ != nullptr)); |
| 237 AdvanceLine(); | 239 AdvanceLine(); |
| 238 } | 240 } |
| 239 | 241 |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 366 x += segment_width; | 368 x += segment_width; |
| 367 } | 369 } |
| 368 rtl_segments_.clear(); | 370 rtl_segments_.clear(); |
| 369 } | 371 } |
| 370 | 372 |
| 371 // Finishes the size calculations of the last Line in |lines_|. Adds a new | 373 // Finishes the size calculations of the last Line in |lines_|. Adds a new |
| 372 // Line to the back of |lines_|. | 374 // Line to the back of |lines_|. |
| 373 void AdvanceLine() { | 375 void AdvanceLine() { |
| 374 if (!lines_.empty()) { | 376 if (!lines_.empty()) { |
| 375 internal::Line* line = &lines_.back(); | 377 internal::Line* line = &lines_.back(); |
| 378 std::sort(line->segments.begin(), line->segments.end(), |
| 379 [this](const internal::LineSegment& s1, |
| 380 const internal::LineSegment& s2) -> bool { |
| 381 return logical_to_visual_[s1.run] < logical_to_visual_[s2.run]; |
| 382 }); |
| 376 line->size.set_height(std::max(min_height_, max_descent_ + max_ascent_)); | 383 line->size.set_height(std::max(min_height_, max_descent_ + max_ascent_)); |
| 377 line->baseline = | 384 line->baseline = |
| 378 std::max(min_baseline_, SkScalarRoundToInt(max_ascent_)); | 385 std::max(min_baseline_, SkScalarRoundToInt(max_ascent_)); |
| 379 line->preceding_heights = std::ceil(total_size_.height()); | 386 line->preceding_heights = std::ceil(total_size_.height()); |
| 380 total_size_.set_height(total_size_.height() + line->size.height()); | 387 total_size_.set_height(total_size_.height() + line->size.height()); |
| 381 total_size_.set_width(std::max(total_size_.width(), line->size.width())); | 388 total_size_.set_width(std::max(total_size_.width(), line->size.width())); |
| 382 } | 389 } |
| 383 max_descent_ = 0; | 390 max_descent_ = 0; |
| 384 max_ascent_ = 0; | 391 max_ascent_ = 0; |
| 385 line_x_ = 0; | 392 line_x_ = 0; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 427 } | 434 } |
| 428 text_x_ += SkFloatToScalar(width); | 435 text_x_ += SkFloatToScalar(width); |
| 429 line_x_ += SkFloatToScalar(width); | 436 line_x_ += SkFloatToScalar(width); |
| 430 } | 437 } |
| 431 | 438 |
| 432 const SkScalar max_width_; | 439 const SkScalar max_width_; |
| 433 const int min_baseline_; | 440 const int min_baseline_; |
| 434 const float min_height_; | 441 const float min_height_; |
| 435 const bool multiline_; | 442 const bool multiline_; |
| 436 const base::string16& text_; | 443 const base::string16& text_; |
| 444 const std::vector<int32_t>& logical_to_visual_; |
| 437 const BreakList<size_t>* const words_; | 445 const BreakList<size_t>* const words_; |
| 438 const ScopedVector<internal::TextRunHarfBuzz>& runs_; | 446 const ScopedVector<internal::TextRunHarfBuzz>& runs_; |
| 439 | 447 |
| 440 // Stores the resulting lines. | 448 // Stores the resulting lines. |
| 441 std::vector<internal::Line> lines_; | 449 std::vector<internal::Line> lines_; |
| 442 | 450 |
| 443 // Text space and line space x coordinates of the next segment to be added. | 451 // Text space and line space x coordinates of the next segment to be added. |
| 444 SkScalar text_x_; | 452 SkScalar text_x_; |
| 445 SkScalar line_x_; | 453 SkScalar line_x_; |
| 446 | 454 |
| (...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 916 | 924 |
| 917 if (lines().empty()) { | 925 if (lines().empty()) { |
| 918 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. | 926 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. |
| 919 tracked_objects::ScopedTracker tracking_profile2( | 927 tracked_objects::ScopedTracker tracking_profile2( |
| 920 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 928 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 921 "431326 RenderTextHarfBuzz::EnsureLayout2")); | 929 "431326 RenderTextHarfBuzz::EnsureLayout2")); |
| 922 | 930 |
| 923 HarfBuzzLineBreaker line_breaker( | 931 HarfBuzzLineBreaker line_breaker( |
| 924 display_rect().width(), font_list().GetBaseline(), | 932 display_rect().width(), font_list().GetBaseline(), |
| 925 std::max(font_list().GetHeight(), min_line_height()), multiline(), | 933 std::max(font_list().GetHeight(), min_line_height()), multiline(), |
| 926 GetLayoutText(), multiline() ? &GetLineBreaks() : nullptr, runs_); | 934 GetLayoutText(), logical_to_visual_, |
| 935 multiline() ? &GetLineBreaks() : nullptr, runs_); |
| 927 | 936 |
| 928 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. | 937 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. |
| 929 tracked_objects::ScopedTracker tracking_profile3( | 938 tracked_objects::ScopedTracker tracking_profile3( |
| 930 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 939 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 931 "431326 RenderTextHarfBuzz::EnsureLayout3")); | 940 "431326 RenderTextHarfBuzz::EnsureLayout3")); |
| 932 | 941 |
| 933 for (size_t i = 0; i < runs_.size(); ++i) | 942 for (size_t i = 0; i < runs_.size(); ++i) |
| 934 line_breaker.AddRun(visual_to_logical_[i]); | 943 line_breaker.AddRun(i); |
| 935 std::vector<internal::Line> lines; | 944 std::vector<internal::Line> lines; |
| 936 line_breaker.Finalize(&lines, &total_size_); | 945 line_breaker.Finalize(&lines, &total_size_); |
| 937 set_lines(&lines); | 946 set_lines(&lines); |
| 938 } | 947 } |
| 939 } | 948 } |
| 940 | 949 |
| 941 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { | 950 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { |
| 951 internal::SkiaTextRenderer renderer(canvas); |
| 952 DrawVisualTextInternal(&renderer); |
| 953 } |
| 954 |
| 955 void RenderTextHarfBuzz::DrawVisualTextInternal( |
| 956 internal::SkiaTextRenderer* renderer) { |
| 942 DCHECK(!needs_layout_); | 957 DCHECK(!needs_layout_); |
| 943 if (lines().empty()) | 958 if (lines().empty()) |
| 944 return; | 959 return; |
| 945 | 960 |
| 946 internal::SkiaTextRenderer renderer(canvas); | 961 ApplyFadeEffects(renderer); |
| 947 ApplyFadeEffects(&renderer); | 962 ApplyTextShadows(renderer); |
| 948 ApplyTextShadows(&renderer); | |
| 949 ApplyCompositionAndSelectionStyles(); | 963 ApplyCompositionAndSelectionStyles(); |
| 950 | 964 |
| 951 for (size_t i = 0; i < lines().size(); ++i) { | 965 for (size_t i = 0; i < lines().size(); ++i) { |
| 952 const internal::Line& line = lines()[i]; | 966 const internal::Line& line = lines()[i]; |
| 953 const Vector2d origin = GetLineOffset(i) + Vector2d(0, line.baseline); | 967 const Vector2d origin = GetLineOffset(i) + Vector2d(0, line.baseline); |
| 954 SkScalar preceding_segment_widths = 0; | 968 SkScalar preceding_segment_widths = 0; |
| 955 for (const internal::LineSegment& segment : line.segments) { | 969 for (const internal::LineSegment& segment : line.segments) { |
| 956 const internal::TextRunHarfBuzz& run = *runs_[segment.run]; | 970 const internal::TextRunHarfBuzz& run = *runs_[segment.run]; |
| 957 renderer.SetTypeface(run.skia_face.get()); | 971 renderer->SetTypeface(run.skia_face.get()); |
| 958 renderer.SetTextSize(SkIntToScalar(run.font_size)); | 972 renderer->SetTextSize(SkIntToScalar(run.font_size)); |
| 959 renderer.SetFontRenderParams(run.render_params, | 973 renderer->SetFontRenderParams(run.render_params, |
| 960 background_is_transparent()); | 974 background_is_transparent()); |
| 961 Range glyphs_range = run.CharRangeToGlyphRange(segment.char_range); | 975 Range glyphs_range = run.CharRangeToGlyphRange(segment.char_range); |
| 962 scoped_ptr<SkPoint[]> positions(new SkPoint[glyphs_range.length()]); | 976 scoped_ptr<SkPoint[]> positions(new SkPoint[glyphs_range.length()]); |
| 963 SkScalar offset_x = | 977 SkScalar offset_x = |
| 964 preceding_segment_widths - run.positions[glyphs_range.start()].x(); | 978 preceding_segment_widths - run.positions[glyphs_range.start()].x(); |
| 965 for (size_t j = 0; j < glyphs_range.length(); ++j) { | 979 for (size_t j = 0; j < glyphs_range.length(); ++j) { |
| 966 positions[j] = run.positions[(glyphs_range.is_reversed()) ? | 980 positions[j] = run.positions[(glyphs_range.is_reversed()) ? |
| 967 (glyphs_range.start() - j) : | 981 (glyphs_range.start() - j) : |
| 968 (glyphs_range.start() + j)]; | 982 (glyphs_range.start() + j)]; |
| 969 positions[j].offset(SkIntToScalar(origin.x()) + offset_x, | 983 positions[j].offset(SkIntToScalar(origin.x()) + offset_x, |
| 970 SkIntToScalar(origin.y())); | 984 SkIntToScalar(origin.y())); |
| 971 } | 985 } |
| 972 for (BreakList<SkColor>::const_iterator it = | 986 for (BreakList<SkColor>::const_iterator it = |
| 973 colors().GetBreak(segment.char_range.start()); | 987 colors().GetBreak(segment.char_range.start()); |
| 974 it != colors().breaks().end() && | 988 it != colors().breaks().end() && |
| 975 it->first < segment.char_range.end(); | 989 it->first < segment.char_range.end(); |
| 976 ++it) { | 990 ++it) { |
| 977 const Range intersection = | 991 const Range intersection = |
| 978 colors().GetRange(it).Intersect(segment.char_range); | 992 colors().GetRange(it).Intersect(segment.char_range); |
| 979 const Range colored_glyphs = run.CharRangeToGlyphRange(intersection); | 993 const Range colored_glyphs = run.CharRangeToGlyphRange(intersection); |
| 980 // The range may be empty if a portion of a multi-character grapheme is | 994 // The range may be empty if a portion of a multi-character grapheme is |
| 981 // selected, yielding two colors for a single glyph. For now, this just | 995 // selected, yielding two colors for a single glyph. For now, this just |
| 982 // paints the glyph with a single style, but it should paint it twice, | 996 // paints the glyph with a single style, but it should paint it twice, |
| 983 // clipped according to selection bounds. See http://crbug.com/366786 | 997 // clipped according to selection bounds. See http://crbug.com/366786 |
| 984 if (colored_glyphs.is_empty()) | 998 if (colored_glyphs.is_empty()) |
| 985 continue; | 999 continue; |
| 986 | 1000 |
| 987 renderer.SetForegroundColor(it->second); | 1001 renderer->SetForegroundColor(it->second); |
| 988 renderer.DrawPosText( | 1002 renderer->DrawPosText( |
| 989 &positions[colored_glyphs.start() - glyphs_range.start()], | 1003 &positions[colored_glyphs.start() - glyphs_range.start()], |
| 990 &run.glyphs[colored_glyphs.start()], colored_glyphs.length()); | 1004 &run.glyphs[colored_glyphs.start()], colored_glyphs.length()); |
| 991 int start_x = SkScalarRoundToInt( | 1005 int start_x = SkScalarRoundToInt( |
| 992 positions[colored_glyphs.start() - glyphs_range.start()].x()); | 1006 positions[colored_glyphs.start() - glyphs_range.start()].x()); |
| 993 int end_x = SkScalarRoundToInt( | 1007 int end_x = SkScalarRoundToInt( |
| 994 (colored_glyphs.end() == glyphs_range.end()) | 1008 (colored_glyphs.end() == glyphs_range.end()) |
| 995 ? (SkFloatToScalar(segment.width) + preceding_segment_widths + | 1009 ? (SkFloatToScalar(segment.width) + preceding_segment_widths + |
| 996 SkIntToScalar(origin.x())) | 1010 SkIntToScalar(origin.x())) |
| 997 : positions[colored_glyphs.end() - glyphs_range.start()].x()); | 1011 : positions[colored_glyphs.end() - glyphs_range.start()].x()); |
| 998 renderer.DrawDecorations(start_x, origin.y(), end_x - start_x, | 1012 renderer->DrawDecorations(start_x, origin.y(), end_x - start_x, |
| 999 run.underline, run.strike, | 1013 run.underline, run.strike, |
| 1000 run.diagonal_strike); | 1014 run.diagonal_strike); |
| 1001 } | 1015 } |
| 1002 preceding_segment_widths += SkFloatToScalar(segment.width); | 1016 preceding_segment_widths += SkFloatToScalar(segment.width); |
| 1003 } | 1017 } |
| 1004 } | 1018 } |
| 1005 | 1019 |
| 1006 renderer.EndDiagonalStrike(); | 1020 renderer->EndDiagonalStrike(); |
| 1007 | 1021 |
| 1008 UndoCompositionAndSelectionStyles(); | 1022 UndoCompositionAndSelectionStyles(); |
| 1009 } | 1023 } |
| 1010 | 1024 |
| 1011 size_t RenderTextHarfBuzz::GetRunContainingCaret( | 1025 size_t RenderTextHarfBuzz::GetRunContainingCaret( |
| 1012 const SelectionModel& caret) const { | 1026 const SelectionModel& caret) const { |
| 1013 DCHECK(!needs_layout_); | 1027 DCHECK(!needs_layout_); |
| 1014 size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos()); | 1028 size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos()); |
| 1015 LogicalCursorDirection affinity = caret.caret_affinity(); | 1029 LogicalCursorDirection affinity = caret.caret_affinity(); |
| 1016 for (size_t run = 0; run < runs_.size(); ++run) { | 1030 for (size_t run = 0; run < runs_.size(); ++run) { |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1311 "431326 RenderTextHarfBuzz::ShapeRunWithFont3")); | 1325 "431326 RenderTextHarfBuzz::ShapeRunWithFont3")); |
| 1312 | 1326 |
| 1313 for (size_t i = 0; i < run->glyph_count; ++i) { | 1327 for (size_t i = 0; i < run->glyph_count; ++i) { |
| 1314 DCHECK_LE(infos[i].codepoint, std::numeric_limits<uint16>::max()); | 1328 DCHECK_LE(infos[i].codepoint, std::numeric_limits<uint16>::max()); |
| 1315 run->glyphs[i] = static_cast<uint16>(infos[i].codepoint); | 1329 run->glyphs[i] = static_cast<uint16>(infos[i].codepoint); |
| 1316 run->glyph_to_char[i] = infos[i].cluster; | 1330 run->glyph_to_char[i] = infos[i].cluster; |
| 1317 const SkScalar x_offset = SkFixedToScalar(hb_positions[i].x_offset); | 1331 const SkScalar x_offset = SkFixedToScalar(hb_positions[i].x_offset); |
| 1318 const SkScalar y_offset = SkFixedToScalar(hb_positions[i].y_offset); | 1332 const SkScalar y_offset = SkFixedToScalar(hb_positions[i].y_offset); |
| 1319 run->positions[i].set(run->width + x_offset, -y_offset); | 1333 run->positions[i].set(run->width + x_offset, -y_offset); |
| 1320 run->width += (glyph_width_for_test_ > 0) | 1334 run->width += (glyph_width_for_test_ > 0) |
| 1321 ? SkIntToScalar(glyph_width_for_test_) | 1335 ? glyph_width_for_test_ |
| 1322 : SkFixedToScalar(hb_positions[i].x_advance); | 1336 : SkFixedToFloat(hb_positions[i].x_advance); |
| 1323 // Round run widths if subpixel positioning is off to match native behavior. | 1337 // Round run widths if subpixel positioning is off to match native behavior. |
| 1324 if (!run->render_params.subpixel_positioning) | 1338 if (!run->render_params.subpixel_positioning) |
| 1325 run->width = std::floor(run->width + 0.5f); | 1339 run->width = std::floor(run->width + 0.5f); |
| 1326 } | 1340 } |
| 1327 | 1341 |
| 1328 hb_buffer_destroy(buffer); | 1342 hb_buffer_destroy(buffer); |
| 1329 hb_font_destroy(harfbuzz_font); | 1343 hb_font_destroy(harfbuzz_font); |
| 1330 return true; | 1344 return true; |
| 1331 } | 1345 } |
| 1332 | 1346 |
| 1333 } // namespace gfx | 1347 } // namespace gfx |
| OLD | NEW |