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 <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 18 matching lines...) Expand all Loading... | |
| 258 AdvanceLine(); | 260 AdvanceLine(); |
| 259 lines_.pop_back(); | 261 lines_.pop_back(); |
| 260 *size = total_size_; | 262 *size = total_size_; |
| 261 lines->swap(lines_); | 263 lines->swap(lines_); |
| 262 } | 264 } |
| 263 | 265 |
| 264 private: | 266 private: |
| 265 // A (line index, segment index) pair that specifies a segment in |lines_|. | 267 // A (line index, segment index) pair that specifies a segment in |lines_|. |
| 266 typedef std::pair<size_t, size_t> SegmentHandle; | 268 typedef std::pair<size_t, size_t> SegmentHandle; |
| 267 | 269 |
| 270 struct SortByVisualPosition { | |
|
ckocagil
2015/02/13 19:05:25
Make this comparator a lambda expression and defin
Jun Mukai
2015/02/13 21:57:58
Done.
| |
| 271 explicit SortByVisualPosition(const std::vector<int32_t>& logical_to_visual) | |
| 272 : logical_to_visual(logical_to_visual) {} | |
| 273 | |
| 274 bool operator()(const internal::LineSegment& segment1, | |
| 275 const internal::LineSegment& segment2) { | |
| 276 return logical_to_visual[segment1.run] < logical_to_visual[segment2.run]; | |
| 277 } | |
| 278 | |
| 279 const std::vector<int32_t>& logical_to_visual; | |
| 280 }; | |
| 281 | |
| 268 internal::LineSegment* SegmentFromHandle(const SegmentHandle& handle) { | 282 internal::LineSegment* SegmentFromHandle(const SegmentHandle& handle) { |
| 269 return &lines_[handle.first].segments[handle.second]; | 283 return &lines_[handle.first].segments[handle.second]; |
| 270 } | 284 } |
| 271 | 285 |
| 272 // Breaks a run into segments that fit in the last line in |lines_| and adds | 286 // Breaks a run into segments that fit in the last line in |lines_| and adds |
| 273 // them. Adds a new Line to the back of |lines_| whenever a new segment can't | 287 // them. Adds a new Line to the back of |lines_| whenever a new segment can't |
| 274 // be added without the Line's width exceeding |max_width_|. | 288 // be added without the Line's width exceeding |max_width_|. |
| 275 void BreakRun(int run_index) { | 289 void BreakRun(int run_index) { |
| 276 const internal::TextRunHarfBuzz& run = *runs_[run_index]; | 290 const internal::TextRunHarfBuzz& run = *runs_[run_index]; |
| 277 SkScalar width = 0; | 291 SkScalar width = 0; |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 366 x += segment_width; | 380 x += segment_width; |
| 367 } | 381 } |
| 368 rtl_segments_.clear(); | 382 rtl_segments_.clear(); |
| 369 } | 383 } |
| 370 | 384 |
| 371 // Finishes the size calculations of the last Line in |lines_|. Adds a new | 385 // Finishes the size calculations of the last Line in |lines_|. Adds a new |
| 372 // Line to the back of |lines_|. | 386 // Line to the back of |lines_|. |
| 373 void AdvanceLine() { | 387 void AdvanceLine() { |
| 374 if (!lines_.empty()) { | 388 if (!lines_.empty()) { |
| 375 internal::Line* line = &lines_.back(); | 389 internal::Line* line = &lines_.back(); |
| 390 std::sort(line->segments.begin(), line->segments.end(), | |
| 391 SortByVisualPosition(logical_to_visual_)); | |
| 376 line->size.set_height(std::max(min_height_, max_descent_ + max_ascent_)); | 392 line->size.set_height(std::max(min_height_, max_descent_ + max_ascent_)); |
| 377 line->baseline = | 393 line->baseline = |
| 378 std::max(min_baseline_, SkScalarRoundToInt(max_ascent_)); | 394 std::max(min_baseline_, SkScalarRoundToInt(max_ascent_)); |
| 379 line->preceding_heights = std::ceil(total_size_.height()); | 395 line->preceding_heights = std::ceil(total_size_.height()); |
| 380 total_size_.set_height(total_size_.height() + line->size.height()); | 396 total_size_.set_height(total_size_.height() + line->size.height()); |
| 381 total_size_.set_width(std::max(total_size_.width(), line->size.width())); | 397 total_size_.set_width(std::max(total_size_.width(), line->size.width())); |
| 382 } | 398 } |
| 383 max_descent_ = 0; | 399 max_descent_ = 0; |
| 384 max_ascent_ = 0; | 400 max_ascent_ = 0; |
| 385 line_x_ = 0; | 401 line_x_ = 0; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 427 } | 443 } |
| 428 text_x_ += SkFloatToScalar(width); | 444 text_x_ += SkFloatToScalar(width); |
| 429 line_x_ += SkFloatToScalar(width); | 445 line_x_ += SkFloatToScalar(width); |
| 430 } | 446 } |
| 431 | 447 |
| 432 const SkScalar max_width_; | 448 const SkScalar max_width_; |
| 433 const int min_baseline_; | 449 const int min_baseline_; |
| 434 const float min_height_; | 450 const float min_height_; |
| 435 const bool multiline_; | 451 const bool multiline_; |
| 436 const base::string16& text_; | 452 const base::string16& text_; |
| 453 const std::vector<int32_t>& logical_to_visual_; | |
| 437 const BreakList<size_t>* const words_; | 454 const BreakList<size_t>* const words_; |
| 438 const ScopedVector<internal::TextRunHarfBuzz>& runs_; | 455 const ScopedVector<internal::TextRunHarfBuzz>& runs_; |
| 439 | 456 |
| 440 // Stores the resulting lines. | 457 // Stores the resulting lines. |
| 441 std::vector<internal::Line> lines_; | 458 std::vector<internal::Line> lines_; |
| 442 | 459 |
| 443 // Text space and line space x coordinates of the next segment to be added. | 460 // Text space and line space x coordinates of the next segment to be added. |
| 444 SkScalar text_x_; | 461 SkScalar text_x_; |
| 445 SkScalar line_x_; | 462 SkScalar line_x_; |
| 446 | 463 |
| (...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 916 | 933 |
| 917 if (lines().empty()) { | 934 if (lines().empty()) { |
| 918 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. | 935 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. |
| 919 tracked_objects::ScopedTracker tracking_profile2( | 936 tracked_objects::ScopedTracker tracking_profile2( |
| 920 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 937 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 921 "431326 RenderTextHarfBuzz::EnsureLayout2")); | 938 "431326 RenderTextHarfBuzz::EnsureLayout2")); |
| 922 | 939 |
| 923 HarfBuzzLineBreaker line_breaker( | 940 HarfBuzzLineBreaker line_breaker( |
| 924 display_rect().width(), font_list().GetBaseline(), | 941 display_rect().width(), font_list().GetBaseline(), |
| 925 std::max(font_list().GetHeight(), min_line_height()), multiline(), | 942 std::max(font_list().GetHeight(), min_line_height()), multiline(), |
| 926 GetLayoutText(), multiline() ? &GetLineBreaks() : nullptr, runs_); | 943 GetLayoutText(), logical_to_visual_, |
| 944 multiline() ? &GetLineBreaks() : nullptr, runs_); | |
| 927 | 945 |
| 928 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. | 946 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. |
| 929 tracked_objects::ScopedTracker tracking_profile3( | 947 tracked_objects::ScopedTracker tracking_profile3( |
| 930 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 948 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 931 "431326 RenderTextHarfBuzz::EnsureLayout3")); | 949 "431326 RenderTextHarfBuzz::EnsureLayout3")); |
| 932 | 950 |
| 933 for (size_t i = 0; i < runs_.size(); ++i) | 951 for (size_t i = 0; i < runs_.size(); ++i) |
| 934 line_breaker.AddRun(visual_to_logical_[i]); | 952 line_breaker.AddRun(i); |
| 935 std::vector<internal::Line> lines; | 953 std::vector<internal::Line> lines; |
| 936 line_breaker.Finalize(&lines, &total_size_); | 954 line_breaker.Finalize(&lines, &total_size_); |
| 937 set_lines(&lines); | 955 set_lines(&lines); |
| 938 } | 956 } |
| 939 } | 957 } |
| 940 | 958 |
| 941 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { | 959 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { |
| 960 internal::SkiaTextRenderer renderer(canvas); | |
| 961 DrawVisualTextInternal(&renderer); | |
| 962 } | |
| 963 | |
| 964 void RenderTextHarfBuzz::DrawVisualTextInternal( | |
| 965 internal::SkiaTextRenderer* renderer) { | |
| 942 DCHECK(!needs_layout_); | 966 DCHECK(!needs_layout_); |
| 943 if (lines().empty()) | 967 if (lines().empty()) |
| 944 return; | 968 return; |
| 945 | 969 |
| 946 internal::SkiaTextRenderer renderer(canvas); | 970 ApplyFadeEffects(renderer); |
| 947 ApplyFadeEffects(&renderer); | 971 ApplyTextShadows(renderer); |
| 948 ApplyTextShadows(&renderer); | |
| 949 ApplyCompositionAndSelectionStyles(); | 972 ApplyCompositionAndSelectionStyles(); |
| 950 | 973 |
| 951 for (size_t i = 0; i < lines().size(); ++i) { | 974 for (size_t i = 0; i < lines().size(); ++i) { |
| 952 const internal::Line& line = lines()[i]; | 975 const internal::Line& line = lines()[i]; |
| 953 const Vector2d origin = GetLineOffset(i) + Vector2d(0, line.baseline); | 976 const Vector2d origin = GetLineOffset(i) + Vector2d(0, line.baseline); |
| 954 SkScalar preceding_segment_widths = 0; | 977 SkScalar preceding_segment_widths = 0; |
| 955 for (const internal::LineSegment& segment : line.segments) { | 978 for (const internal::LineSegment& segment : line.segments) { |
| 956 const internal::TextRunHarfBuzz& run = *runs_[segment.run]; | 979 const internal::TextRunHarfBuzz& run = *runs_[segment.run]; |
| 957 renderer.SetTypeface(run.skia_face.get()); | 980 renderer->SetTypeface(run.skia_face.get()); |
| 958 renderer.SetTextSize(SkIntToScalar(run.font_size)); | 981 renderer->SetTextSize(SkIntToScalar(run.font_size)); |
| 959 renderer.SetFontRenderParams(run.render_params, | 982 renderer->SetFontRenderParams(run.render_params, |
| 960 background_is_transparent()); | 983 background_is_transparent()); |
| 961 Range glyphs_range = run.CharRangeToGlyphRange(segment.char_range); | 984 Range glyphs_range = run.CharRangeToGlyphRange(segment.char_range); |
| 962 scoped_ptr<SkPoint[]> positions(new SkPoint[glyphs_range.length()]); | 985 scoped_ptr<SkPoint[]> positions(new SkPoint[glyphs_range.length()]); |
| 963 SkScalar offset_x = | 986 SkScalar offset_x = |
| 964 preceding_segment_widths - run.positions[glyphs_range.start()].x(); | 987 preceding_segment_widths - run.positions[glyphs_range.start()].x(); |
| 965 for (size_t j = 0; j < glyphs_range.length(); ++j) { | 988 for (size_t j = 0; j < glyphs_range.length(); ++j) { |
| 966 positions[j] = run.positions[(glyphs_range.is_reversed()) ? | 989 positions[j] = run.positions[(glyphs_range.is_reversed()) ? |
| 967 (glyphs_range.start() - j) : | 990 (glyphs_range.start() - j) : |
| 968 (glyphs_range.start() + j)]; | 991 (glyphs_range.start() + j)]; |
| 969 positions[j].offset(SkIntToScalar(origin.x()) + offset_x, | 992 positions[j].offset(SkIntToScalar(origin.x()) + offset_x, |
| 970 SkIntToScalar(origin.y())); | 993 SkIntToScalar(origin.y())); |
| 971 } | 994 } |
| 972 for (BreakList<SkColor>::const_iterator it = | 995 for (BreakList<SkColor>::const_iterator it = |
| 973 colors().GetBreak(segment.char_range.start()); | 996 colors().GetBreak(segment.char_range.start()); |
| 974 it != colors().breaks().end() && | 997 it != colors().breaks().end() && |
| 975 it->first < segment.char_range.end(); | 998 it->first < segment.char_range.end(); |
| 976 ++it) { | 999 ++it) { |
| 977 const Range intersection = | 1000 const Range intersection = |
| 978 colors().GetRange(it).Intersect(segment.char_range); | 1001 colors().GetRange(it).Intersect(segment.char_range); |
| 979 const Range colored_glyphs = run.CharRangeToGlyphRange(intersection); | 1002 const Range colored_glyphs = run.CharRangeToGlyphRange(intersection); |
| 980 // The range may be empty if a portion of a multi-character grapheme is | 1003 // 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 | 1004 // 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, | 1005 // paints the glyph with a single style, but it should paint it twice, |
| 983 // clipped according to selection bounds. See http://crbug.com/366786 | 1006 // clipped according to selection bounds. See http://crbug.com/366786 |
| 984 if (colored_glyphs.is_empty()) | 1007 if (colored_glyphs.is_empty()) |
| 985 continue; | 1008 continue; |
| 986 | 1009 |
| 987 renderer.SetForegroundColor(it->second); | 1010 renderer->SetForegroundColor(it->second); |
| 988 renderer.DrawPosText( | 1011 renderer->DrawPosText( |
| 989 &positions[colored_glyphs.start() - glyphs_range.start()], | 1012 &positions[colored_glyphs.start() - glyphs_range.start()], |
| 990 &run.glyphs[colored_glyphs.start()], colored_glyphs.length()); | 1013 &run.glyphs[colored_glyphs.start()], colored_glyphs.length()); |
| 991 int start_x = SkScalarRoundToInt( | 1014 int start_x = SkScalarRoundToInt( |
| 992 positions[colored_glyphs.start() - glyphs_range.start()].x()); | 1015 positions[colored_glyphs.start() - glyphs_range.start()].x()); |
| 993 int end_x = SkScalarRoundToInt( | 1016 int end_x = SkScalarRoundToInt( |
| 994 (colored_glyphs.end() == glyphs_range.end()) | 1017 (colored_glyphs.end() == glyphs_range.end()) |
| 995 ? (SkFloatToScalar(segment.width) + preceding_segment_widths + | 1018 ? (SkFloatToScalar(segment.width) + preceding_segment_widths + |
| 996 SkIntToScalar(origin.x())) | 1019 SkIntToScalar(origin.x())) |
| 997 : positions[colored_glyphs.end() - glyphs_range.start()].x()); | 1020 : positions[colored_glyphs.end() - glyphs_range.start()].x()); |
| 998 renderer.DrawDecorations(start_x, origin.y(), end_x - start_x, | 1021 renderer->DrawDecorations(start_x, origin.y(), end_x - start_x, |
| 999 run.underline, run.strike, | 1022 run.underline, run.strike, |
| 1000 run.diagonal_strike); | 1023 run.diagonal_strike); |
| 1001 } | 1024 } |
| 1002 preceding_segment_widths += SkFloatToScalar(segment.width); | 1025 preceding_segment_widths += SkFloatToScalar(segment.width); |
| 1003 } | 1026 } |
| 1004 } | 1027 } |
| 1005 | 1028 |
| 1006 renderer.EndDiagonalStrike(); | 1029 renderer->EndDiagonalStrike(); |
| 1007 | 1030 |
| 1008 UndoCompositionAndSelectionStyles(); | 1031 UndoCompositionAndSelectionStyles(); |
| 1009 } | 1032 } |
| 1010 | 1033 |
| 1011 size_t RenderTextHarfBuzz::GetRunContainingCaret( | 1034 size_t RenderTextHarfBuzz::GetRunContainingCaret( |
| 1012 const SelectionModel& caret) const { | 1035 const SelectionModel& caret) const { |
| 1013 DCHECK(!needs_layout_); | 1036 DCHECK(!needs_layout_); |
| 1014 size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos()); | 1037 size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos()); |
| 1015 LogicalCursorDirection affinity = caret.caret_affinity(); | 1038 LogicalCursorDirection affinity = caret.caret_affinity(); |
| 1016 for (size_t run = 0; run < runs_.size(); ++run) { | 1039 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")); | 1334 "431326 RenderTextHarfBuzz::ShapeRunWithFont3")); |
| 1312 | 1335 |
| 1313 for (size_t i = 0; i < run->glyph_count; ++i) { | 1336 for (size_t i = 0; i < run->glyph_count; ++i) { |
| 1314 DCHECK_LE(infos[i].codepoint, std::numeric_limits<uint16>::max()); | 1337 DCHECK_LE(infos[i].codepoint, std::numeric_limits<uint16>::max()); |
| 1315 run->glyphs[i] = static_cast<uint16>(infos[i].codepoint); | 1338 run->glyphs[i] = static_cast<uint16>(infos[i].codepoint); |
| 1316 run->glyph_to_char[i] = infos[i].cluster; | 1339 run->glyph_to_char[i] = infos[i].cluster; |
| 1317 const SkScalar x_offset = SkFixedToScalar(hb_positions[i].x_offset); | 1340 const SkScalar x_offset = SkFixedToScalar(hb_positions[i].x_offset); |
| 1318 const SkScalar y_offset = SkFixedToScalar(hb_positions[i].y_offset); | 1341 const SkScalar y_offset = SkFixedToScalar(hb_positions[i].y_offset); |
| 1319 run->positions[i].set(run->width + x_offset, -y_offset); | 1342 run->positions[i].set(run->width + x_offset, -y_offset); |
| 1320 run->width += (glyph_width_for_test_ > 0) | 1343 run->width += (glyph_width_for_test_ > 0) |
| 1321 ? SkIntToScalar(glyph_width_for_test_) | 1344 ? glyph_width_for_test_ |
| 1322 : SkFixedToScalar(hb_positions[i].x_advance); | 1345 : SkFixedToFloat(hb_positions[i].x_advance); |
| 1323 // Round run widths if subpixel positioning is off to match native behavior. | 1346 // Round run widths if subpixel positioning is off to match native behavior. |
| 1324 if (!run->render_params.subpixel_positioning) | 1347 if (!run->render_params.subpixel_positioning) |
| 1325 run->width = std::floor(run->width + 0.5f); | 1348 run->width = std::floor(run->width + 0.5f); |
| 1326 } | 1349 } |
| 1327 | 1350 |
| 1328 hb_buffer_destroy(buffer); | 1351 hb_buffer_destroy(buffer); |
| 1329 hb_font_destroy(harfbuzz_font); | 1352 hb_font_destroy(harfbuzz_font); |
| 1330 return true; | 1353 return true; |
| 1331 } | 1354 } |
| 1332 | 1355 |
| 1333 } // namespace gfx | 1356 } // namespace gfx |
| OLD | NEW |