| 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 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 // TODO(ckocagil): Expose the interface of this class in the header and test | 216 // TODO(ckocagil): Expose the interface of this class in the header and test |
| 217 // this class directly. | 217 // this class directly. |
| 218 class HarfBuzzLineBreaker { | 218 class HarfBuzzLineBreaker { |
| 219 public: | 219 public: |
| 220 HarfBuzzLineBreaker(size_t max_width, | 220 HarfBuzzLineBreaker(size_t max_width, |
| 221 int min_baseline, | 221 int min_baseline, |
| 222 float min_height, | 222 float min_height, |
| 223 bool multiline, | 223 bool multiline, |
| 224 const base::string16& text, | 224 const base::string16& text, |
| 225 const BreakList<size_t>* words, | 225 const BreakList<size_t>* words, |
| 226 const ScopedVector<internal::TextRunHarfBuzz>& runs) | 226 const internal::TextRunList& run_list) |
| 227 : max_width_((max_width == 0) ? SK_ScalarMax : SkIntToScalar(max_width)), | 227 : max_width_((max_width == 0) ? SK_ScalarMax : SkIntToScalar(max_width)), |
| 228 min_baseline_(min_baseline), | 228 min_baseline_(min_baseline), |
| 229 min_height_(min_height), | 229 min_height_(min_height), |
| 230 multiline_(multiline), | 230 multiline_(multiline), |
| 231 text_(text), | 231 text_(text), |
| 232 words_(words), | 232 words_(words), |
| 233 runs_(runs), | 233 run_list_(run_list), |
| 234 text_x_(0), | 234 text_x_(0), |
| 235 line_x_(0), | 235 line_x_(0), |
| 236 max_descent_(0), | 236 max_descent_(0), |
| 237 max_ascent_(0) { | 237 max_ascent_(0) { |
| 238 DCHECK_EQ(multiline_, (words_ != nullptr)); | 238 DCHECK_EQ(multiline_, (words_ != nullptr)); |
| 239 AdvanceLine(); | 239 AdvanceLine(); |
| 240 } | 240 } |
| 241 | 241 |
| 242 // Breaks the run at given |run_index| into Line structs. | 242 // Breaks the run at given |run_index| into Line structs. |
| 243 void AddRun(int run_index) { | 243 void AddRun(int run_index) { |
| 244 const internal::TextRunHarfBuzz* run = runs_[run_index]; | 244 const internal::TextRunHarfBuzz* run = run_list_.runs()[run_index]; |
| 245 base::char16 first_char = text_[run->range.start()]; | 245 base::char16 first_char = text_[run->range.start()]; |
| 246 if (multiline_ && first_char == '\n') { | 246 if (multiline_ && first_char == '\n') { |
| 247 AdvanceLine(); | 247 AdvanceLine(); |
| 248 } else if (multiline_ && (line_x_ + SkFloatToScalar(run->width)) > | 248 } else if (multiline_ && (line_x_ + SkFloatToScalar(run->width)) > |
| 249 max_width_) { | 249 max_width_) { |
| 250 BreakRun(run_index); | 250 BreakRun(run_index); |
| 251 } else { | 251 } else { |
| 252 AddSegment(run_index, run->range, run->width); | 252 AddSegment(run_index, run->range, run->width); |
| 253 } | 253 } |
| 254 } | 254 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 268 typedef std::pair<size_t, size_t> SegmentHandle; | 268 typedef std::pair<size_t, size_t> SegmentHandle; |
| 269 | 269 |
| 270 internal::LineSegment* SegmentFromHandle(const SegmentHandle& handle) { | 270 internal::LineSegment* SegmentFromHandle(const SegmentHandle& handle) { |
| 271 return &lines_[handle.first].segments[handle.second]; | 271 return &lines_[handle.first].segments[handle.second]; |
| 272 } | 272 } |
| 273 | 273 |
| 274 // Breaks a run into segments that fit in the last line in |lines_| and adds | 274 // Breaks a run into segments that fit in the last line in |lines_| and adds |
| 275 // them. Adds a new Line to the back of |lines_| whenever a new segment can't | 275 // them. Adds a new Line to the back of |lines_| whenever a new segment can't |
| 276 // be added without the Line's width exceeding |max_width_|. | 276 // be added without the Line's width exceeding |max_width_|. |
| 277 void BreakRun(int run_index) { | 277 void BreakRun(int run_index) { |
| 278 const internal::TextRunHarfBuzz& run = *runs_[run_index]; | 278 const internal::TextRunHarfBuzz& run = *(run_list_.runs()[run_index]); |
| 279 SkScalar width = 0; | 279 SkScalar width = 0; |
| 280 size_t next_char = run.range.start(); | 280 size_t next_char = run.range.start(); |
| 281 | 281 |
| 282 // Break the run until it fits the current line. | 282 // Break the run until it fits the current line. |
| 283 while (next_char < run.range.end()) { | 283 while (next_char < run.range.end()) { |
| 284 const size_t current_char = next_char; | 284 const size_t current_char = next_char; |
| 285 const bool skip_line = | 285 const bool skip_line = |
| 286 BreakRunAtWidth(run, current_char, &width, &next_char); | 286 BreakRunAtWidth(run, current_char, &width, &next_char); |
| 287 AddSegment(run_index, Range(current_char, next_char), | 287 AddSegment(run_index, Range(current_char, next_char), |
| 288 SkScalarToFloat(width)); | 288 SkScalarToFloat(width)); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 368 x += segment_width; | 368 x += segment_width; |
| 369 } | 369 } |
| 370 rtl_segments_.clear(); | 370 rtl_segments_.clear(); |
| 371 } | 371 } |
| 372 | 372 |
| 373 // 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 |
| 374 // Line to the back of |lines_|. | 374 // Line to the back of |lines_|. |
| 375 void AdvanceLine() { | 375 void AdvanceLine() { |
| 376 if (!lines_.empty()) { | 376 if (!lines_.empty()) { |
| 377 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 run_list_.logical_to_visual(s1.run) < |
| 382 run_list_.logical_to_visual(s2.run); |
| 383 }); |
| 378 line->size.set_height(std::max(min_height_, max_descent_ + max_ascent_)); | 384 line->size.set_height(std::max(min_height_, max_descent_ + max_ascent_)); |
| 379 line->baseline = | 385 line->baseline = |
| 380 std::max(min_baseline_, SkScalarRoundToInt(max_ascent_)); | 386 std::max(min_baseline_, SkScalarRoundToInt(max_ascent_)); |
| 381 line->preceding_heights = std::ceil(total_size_.height()); | 387 line->preceding_heights = std::ceil(total_size_.height()); |
| 382 total_size_.set_height(total_size_.height() + line->size.height()); | 388 total_size_.set_height(total_size_.height() + line->size.height()); |
| 383 total_size_.set_width(std::max(total_size_.width(), line->size.width())); | 389 total_size_.set_width(std::max(total_size_.width(), line->size.width())); |
| 384 } | 390 } |
| 385 max_descent_ = 0; | 391 max_descent_ = 0; |
| 386 max_ascent_ = 0; | 392 max_ascent_ = 0; |
| 387 line_x_ = 0; | 393 line_x_ = 0; |
| 388 lines_.push_back(internal::Line()); | 394 lines_.push_back(internal::Line()); |
| 389 } | 395 } |
| 390 | 396 |
| 391 // Adds a new segment with the given properties to |lines_.back()|. | 397 // Adds a new segment with the given properties to |lines_.back()|. |
| 392 void AddSegment(int run_index, Range char_range, float width) { | 398 void AddSegment(int run_index, Range char_range, float width) { |
| 393 if (char_range.is_empty()) { | 399 if (char_range.is_empty()) { |
| 394 DCHECK_EQ(0, width); | 400 DCHECK_EQ(0, width); |
| 395 return; | 401 return; |
| 396 } | 402 } |
| 397 const internal::TextRunHarfBuzz& run = *runs_[run_index]; | 403 const internal::TextRunHarfBuzz& run = *(run_list_.runs()[run_index]); |
| 398 | 404 |
| 399 internal::LineSegment segment; | 405 internal::LineSegment segment; |
| 400 segment.run = run_index; | 406 segment.run = run_index; |
| 401 segment.char_range = char_range; | 407 segment.char_range = char_range; |
| 402 segment.x_range = Range( | 408 segment.x_range = Range( |
| 403 SkScalarCeilToInt(text_x_), | 409 SkScalarCeilToInt(text_x_), |
| 404 SkScalarCeilToInt(text_x_ + SkFloatToScalar(width))); | 410 SkScalarCeilToInt(text_x_ + SkFloatToScalar(width))); |
| 405 segment.width = width; | 411 segment.width = width; |
| 406 | 412 |
| 407 internal::Line* line = &lines_.back(); | 413 internal::Line* line = &lines_.back(); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 430 text_x_ += SkFloatToScalar(width); | 436 text_x_ += SkFloatToScalar(width); |
| 431 line_x_ += SkFloatToScalar(width); | 437 line_x_ += SkFloatToScalar(width); |
| 432 } | 438 } |
| 433 | 439 |
| 434 const SkScalar max_width_; | 440 const SkScalar max_width_; |
| 435 const int min_baseline_; | 441 const int min_baseline_; |
| 436 const float min_height_; | 442 const float min_height_; |
| 437 const bool multiline_; | 443 const bool multiline_; |
| 438 const base::string16& text_; | 444 const base::string16& text_; |
| 439 const BreakList<size_t>* const words_; | 445 const BreakList<size_t>* const words_; |
| 440 const ScopedVector<internal::TextRunHarfBuzz>& runs_; | 446 const internal::TextRunList& run_list_; |
| 441 | 447 |
| 442 // Stores the resulting lines. | 448 // Stores the resulting lines. |
| 443 std::vector<internal::Line> lines_; | 449 std::vector<internal::Line> lines_; |
| 444 | 450 |
| 445 // 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. |
| 446 SkScalar text_x_; | 452 SkScalar text_x_; |
| 447 SkScalar line_x_; | 453 SkScalar line_x_; |
| 448 | 454 |
| 449 float max_descent_; | 455 float max_descent_; |
| 450 float max_ascent_; | 456 float max_ascent_; |
| (...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 963 if (lines().empty()) { | 969 if (lines().empty()) { |
| 964 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. | 970 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. |
| 965 tracked_objects::ScopedTracker tracking_profile2( | 971 tracked_objects::ScopedTracker tracking_profile2( |
| 966 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 972 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 967 "431326 RenderTextHarfBuzz::EnsureLayout2")); | 973 "431326 RenderTextHarfBuzz::EnsureLayout2")); |
| 968 | 974 |
| 969 internal::TextRunList* run_list = GetRunList(); | 975 internal::TextRunList* run_list = GetRunList(); |
| 970 HarfBuzzLineBreaker line_breaker( | 976 HarfBuzzLineBreaker line_breaker( |
| 971 display_rect().width(), font_list().GetBaseline(), | 977 display_rect().width(), font_list().GetBaseline(), |
| 972 std::max(font_list().GetHeight(), min_line_height()), multiline(), | 978 std::max(font_list().GetHeight(), min_line_height()), multiline(), |
| 973 GetDisplayText(), multiline() ? &GetLineBreaks() : nullptr, | 979 GetDisplayText(), multiline() ? &GetLineBreaks() : nullptr, *run_list); |
| 974 run_list->runs()); | |
| 975 | 980 |
| 976 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. | 981 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. |
| 977 tracked_objects::ScopedTracker tracking_profile3( | 982 tracked_objects::ScopedTracker tracking_profile3( |
| 978 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 983 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 979 "431326 RenderTextHarfBuzz::EnsureLayout3")); | 984 "431326 RenderTextHarfBuzz::EnsureLayout3")); |
| 980 | 985 |
| 981 for (size_t i = 0; i < run_list->size(); ++i) | 986 for (size_t i = 0; i < run_list->size(); ++i) |
| 982 line_breaker.AddRun(run_list->visual_to_logical(i)); | 987 line_breaker.AddRun(i); |
| 983 | |
| 984 std::vector<internal::Line> lines; | 988 std::vector<internal::Line> lines; |
| 985 line_breaker.Finalize(&lines, &total_size_); | 989 line_breaker.Finalize(&lines, &total_size_); |
| 986 set_lines(&lines); | 990 set_lines(&lines); |
| 987 } | 991 } |
| 988 } | 992 } |
| 989 | 993 |
| 990 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { | 994 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { |
| 995 internal::SkiaTextRenderer renderer(canvas); |
| 996 DrawVisualTextInternal(&renderer); |
| 997 } |
| 998 |
| 999 void RenderTextHarfBuzz::DrawVisualTextInternal( |
| 1000 internal::SkiaTextRenderer* renderer) { |
| 991 DCHECK(!update_layout_run_list_); | 1001 DCHECK(!update_layout_run_list_); |
| 992 DCHECK(!update_display_run_list_); | 1002 DCHECK(!update_display_run_list_); |
| 993 DCHECK(!update_display_text_); | 1003 DCHECK(!update_display_text_); |
| 994 if (lines().empty()) | 1004 if (lines().empty()) |
| 995 return; | 1005 return; |
| 996 | 1006 |
| 997 internal::SkiaTextRenderer renderer(canvas); | 1007 ApplyFadeEffects(renderer); |
| 998 ApplyFadeEffects(&renderer); | 1008 ApplyTextShadows(renderer); |
| 999 ApplyTextShadows(&renderer); | |
| 1000 ApplyCompositionAndSelectionStyles(); | 1009 ApplyCompositionAndSelectionStyles(); |
| 1001 | 1010 |
| 1002 internal::TextRunList* run_list = GetRunList(); | 1011 internal::TextRunList* run_list = GetRunList(); |
| 1003 for (size_t i = 0; i < lines().size(); ++i) { | 1012 for (size_t i = 0; i < lines().size(); ++i) { |
| 1004 const internal::Line& line = lines()[i]; | 1013 const internal::Line& line = lines()[i]; |
| 1005 const Vector2d origin = GetLineOffset(i) + Vector2d(0, line.baseline); | 1014 const Vector2d origin = GetLineOffset(i) + Vector2d(0, line.baseline); |
| 1006 SkScalar preceding_segment_widths = 0; | 1015 SkScalar preceding_segment_widths = 0; |
| 1007 for (const internal::LineSegment& segment : line.segments) { | 1016 for (const internal::LineSegment& segment : line.segments) { |
| 1008 const internal::TextRunHarfBuzz& run = *run_list->runs()[segment.run]; | 1017 const internal::TextRunHarfBuzz& run = *run_list->runs()[segment.run]; |
| 1009 renderer.SetTypeface(run.skia_face.get()); | 1018 renderer->SetTypeface(run.skia_face.get()); |
| 1010 renderer.SetTextSize(SkIntToScalar(run.font_size)); | 1019 renderer->SetTextSize(SkIntToScalar(run.font_size)); |
| 1011 renderer.SetFontRenderParams(run.render_params, | 1020 renderer->SetFontRenderParams(run.render_params, |
| 1012 background_is_transparent()); | 1021 background_is_transparent()); |
| 1013 Range glyphs_range = run.CharRangeToGlyphRange(segment.char_range); | 1022 Range glyphs_range = run.CharRangeToGlyphRange(segment.char_range); |
| 1014 scoped_ptr<SkPoint[]> positions(new SkPoint[glyphs_range.length()]); | 1023 scoped_ptr<SkPoint[]> positions(new SkPoint[glyphs_range.length()]); |
| 1015 SkScalar offset_x = | 1024 SkScalar offset_x = |
| 1016 preceding_segment_widths - run.positions[glyphs_range.start()].x(); | 1025 preceding_segment_widths - run.positions[glyphs_range.start()].x(); |
| 1017 for (size_t j = 0; j < glyphs_range.length(); ++j) { | 1026 for (size_t j = 0; j < glyphs_range.length(); ++j) { |
| 1018 positions[j] = run.positions[(glyphs_range.is_reversed()) ? | 1027 positions[j] = run.positions[(glyphs_range.is_reversed()) ? |
| 1019 (glyphs_range.start() - j) : | 1028 (glyphs_range.start() - j) : |
| 1020 (glyphs_range.start() + j)]; | 1029 (glyphs_range.start() + j)]; |
| 1021 positions[j].offset(SkIntToScalar(origin.x()) + offset_x, | 1030 positions[j].offset(SkIntToScalar(origin.x()) + offset_x, |
| 1022 SkIntToScalar(origin.y())); | 1031 SkIntToScalar(origin.y())); |
| 1023 } | 1032 } |
| 1024 for (BreakList<SkColor>::const_iterator it = | 1033 for (BreakList<SkColor>::const_iterator it = |
| 1025 colors().GetBreak(segment.char_range.start()); | 1034 colors().GetBreak(segment.char_range.start()); |
| 1026 it != colors().breaks().end() && | 1035 it != colors().breaks().end() && |
| 1027 it->first < segment.char_range.end(); | 1036 it->first < segment.char_range.end(); |
| 1028 ++it) { | 1037 ++it) { |
| 1029 const Range intersection = | 1038 const Range intersection = |
| 1030 colors().GetRange(it).Intersect(segment.char_range); | 1039 colors().GetRange(it).Intersect(segment.char_range); |
| 1031 const Range colored_glyphs = run.CharRangeToGlyphRange(intersection); | 1040 const Range colored_glyphs = run.CharRangeToGlyphRange(intersection); |
| 1032 // The range may be empty if a portion of a multi-character grapheme is | 1041 // The range may be empty if a portion of a multi-character grapheme is |
| 1033 // selected, yielding two colors for a single glyph. For now, this just | 1042 // selected, yielding two colors for a single glyph. For now, this just |
| 1034 // paints the glyph with a single style, but it should paint it twice, | 1043 // paints the glyph with a single style, but it should paint it twice, |
| 1035 // clipped according to selection bounds. See http://crbug.com/366786 | 1044 // clipped according to selection bounds. See http://crbug.com/366786 |
| 1036 if (colored_glyphs.is_empty()) | 1045 if (colored_glyphs.is_empty()) |
| 1037 continue; | 1046 continue; |
| 1038 | 1047 |
| 1039 renderer.SetForegroundColor(it->second); | 1048 renderer->SetForegroundColor(it->second); |
| 1040 renderer.DrawPosText( | 1049 renderer->DrawPosText( |
| 1041 &positions[colored_glyphs.start() - glyphs_range.start()], | 1050 &positions[colored_glyphs.start() - glyphs_range.start()], |
| 1042 &run.glyphs[colored_glyphs.start()], colored_glyphs.length()); | 1051 &run.glyphs[colored_glyphs.start()], colored_glyphs.length()); |
| 1043 int start_x = SkScalarRoundToInt( | 1052 int start_x = SkScalarRoundToInt( |
| 1044 positions[colored_glyphs.start() - glyphs_range.start()].x()); | 1053 positions[colored_glyphs.start() - glyphs_range.start()].x()); |
| 1045 int end_x = SkScalarRoundToInt( | 1054 int end_x = SkScalarRoundToInt( |
| 1046 (colored_glyphs.end() == glyphs_range.end()) | 1055 (colored_glyphs.end() == glyphs_range.end()) |
| 1047 ? (SkFloatToScalar(segment.width) + preceding_segment_widths + | 1056 ? (SkFloatToScalar(segment.width) + preceding_segment_widths + |
| 1048 SkIntToScalar(origin.x())) | 1057 SkIntToScalar(origin.x())) |
| 1049 : positions[colored_glyphs.end() - glyphs_range.start()].x()); | 1058 : positions[colored_glyphs.end() - glyphs_range.start()].x()); |
| 1050 renderer.DrawDecorations(start_x, origin.y(), end_x - start_x, | 1059 renderer->DrawDecorations(start_x, origin.y(), end_x - start_x, |
| 1051 run.underline, run.strike, | 1060 run.underline, run.strike, |
| 1052 run.diagonal_strike); | 1061 run.diagonal_strike); |
| 1053 } | 1062 } |
| 1054 preceding_segment_widths += SkFloatToScalar(segment.width); | 1063 preceding_segment_widths += SkFloatToScalar(segment.width); |
| 1055 } | 1064 } |
| 1056 } | 1065 } |
| 1057 | 1066 |
| 1058 renderer.EndDiagonalStrike(); | 1067 renderer->EndDiagonalStrike(); |
| 1059 | 1068 |
| 1060 UndoCompositionAndSelectionStyles(); | 1069 UndoCompositionAndSelectionStyles(); |
| 1061 } | 1070 } |
| 1062 | 1071 |
| 1063 size_t RenderTextHarfBuzz::GetRunContainingCaret( | 1072 size_t RenderTextHarfBuzz::GetRunContainingCaret( |
| 1064 const SelectionModel& caret) { | 1073 const SelectionModel& caret) { |
| 1065 DCHECK(!update_display_run_list_); | 1074 DCHECK(!update_display_run_list_); |
| 1066 size_t layout_position = TextIndexToDisplayIndex(caret.caret_pos()); | 1075 size_t layout_position = TextIndexToDisplayIndex(caret.caret_pos()); |
| 1067 LogicalCursorDirection affinity = caret.caret_affinity(); | 1076 LogicalCursorDirection affinity = caret.caret_affinity(); |
| 1068 internal::TextRunList* run_list = GetRunList(); | 1077 internal::TextRunList* run_list = GetRunList(); |
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1370 "431326 RenderTextHarfBuzz::ShapeRunWithFont3")); | 1379 "431326 RenderTextHarfBuzz::ShapeRunWithFont3")); |
| 1371 | 1380 |
| 1372 for (size_t i = 0; i < run->glyph_count; ++i) { | 1381 for (size_t i = 0; i < run->glyph_count; ++i) { |
| 1373 DCHECK_LE(infos[i].codepoint, std::numeric_limits<uint16>::max()); | 1382 DCHECK_LE(infos[i].codepoint, std::numeric_limits<uint16>::max()); |
| 1374 run->glyphs[i] = static_cast<uint16>(infos[i].codepoint); | 1383 run->glyphs[i] = static_cast<uint16>(infos[i].codepoint); |
| 1375 run->glyph_to_char[i] = infos[i].cluster; | 1384 run->glyph_to_char[i] = infos[i].cluster; |
| 1376 const SkScalar x_offset = SkFixedToScalar(hb_positions[i].x_offset); | 1385 const SkScalar x_offset = SkFixedToScalar(hb_positions[i].x_offset); |
| 1377 const SkScalar y_offset = SkFixedToScalar(hb_positions[i].y_offset); | 1386 const SkScalar y_offset = SkFixedToScalar(hb_positions[i].y_offset); |
| 1378 run->positions[i].set(run->width + x_offset, -y_offset); | 1387 run->positions[i].set(run->width + x_offset, -y_offset); |
| 1379 run->width += (glyph_width_for_test_ > 0) | 1388 run->width += (glyph_width_for_test_ > 0) |
| 1380 ? SkIntToScalar(glyph_width_for_test_) | 1389 ? glyph_width_for_test_ |
| 1381 : SkFixedToScalar(hb_positions[i].x_advance); | 1390 : SkFixedToFloat(hb_positions[i].x_advance); |
| 1382 // Round run widths if subpixel positioning is off to match native behavior. | 1391 // Round run widths if subpixel positioning is off to match native behavior. |
| 1383 if (!run->render_params.subpixel_positioning) | 1392 if (!run->render_params.subpixel_positioning) |
| 1384 run->width = std::floor(run->width + 0.5f); | 1393 run->width = std::floor(run->width + 0.5f); |
| 1385 } | 1394 } |
| 1386 | 1395 |
| 1387 hb_buffer_destroy(buffer); | 1396 hb_buffer_destroy(buffer); |
| 1388 hb_font_destroy(harfbuzz_font); | 1397 hb_font_destroy(harfbuzz_font); |
| 1389 return true; | 1398 return true; |
| 1390 } | 1399 } |
| 1391 | 1400 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1457 DCHECK(!update_layout_run_list_); | 1466 DCHECK(!update_layout_run_list_); |
| 1458 DCHECK(!update_display_run_list_); | 1467 DCHECK(!update_display_run_list_); |
| 1459 return text_elided() ? display_run_list_.get() : &layout_run_list_; | 1468 return text_elided() ? display_run_list_.get() : &layout_run_list_; |
| 1460 } | 1469 } |
| 1461 | 1470 |
| 1462 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const { | 1471 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const { |
| 1463 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList(); | 1472 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList(); |
| 1464 } | 1473 } |
| 1465 | 1474 |
| 1466 } // namespace gfx | 1475 } // namespace gfx |
| OLD | NEW |