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" |
| 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" | |
| 14 #include "base/trace_event/trace_event.h" | |
| 13 #include "third_party/harfbuzz-ng/src/hb.h" | 15 #include "third_party/harfbuzz-ng/src/hb.h" |
| 14 #include "third_party/icu/source/common/unicode/ubidi.h" | 16 #include "third_party/icu/source/common/unicode/ubidi.h" |
| 15 #include "third_party/skia/include/core/SkColor.h" | 17 #include "third_party/skia/include/core/SkColor.h" |
| 16 #include "third_party/skia/include/core/SkTypeface.h" | 18 #include "third_party/skia/include/core/SkTypeface.h" |
| 17 #include "ui/gfx/canvas.h" | 19 #include "ui/gfx/canvas.h" |
| 18 #include "ui/gfx/font_fallback.h" | 20 #include "ui/gfx/font_fallback.h" |
| 19 #include "ui/gfx/font_render_params.h" | 21 #include "ui/gfx/font_render_params.h" |
| 20 #include "ui/gfx/harfbuzz_font_skia.h" | 22 #include "ui/gfx/harfbuzz_font_skia.h" |
| 21 #include "ui/gfx/utf16_indexing.h" | 23 #include "ui/gfx/utf16_indexing.h" |
| 22 | 24 |
| (...skipping 544 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 567 cluster_width * (before + 1) / static_cast<float>(total)); | 569 cluster_width * (before + 1) / static_cast<float>(total)); |
| 568 return RangeF(preceding_run_widths + grapheme_begin_x, | 570 return RangeF(preceding_run_widths + grapheme_begin_x, |
| 569 preceding_run_widths + grapheme_end_x); | 571 preceding_run_widths + grapheme_end_x); |
| 570 } | 572 } |
| 571 } | 573 } |
| 572 | 574 |
| 573 return RangeF(preceding_run_widths + cluster_begin_x, | 575 return RangeF(preceding_run_widths + cluster_begin_x, |
| 574 preceding_run_widths + cluster_end_x); | 576 preceding_run_widths + cluster_end_x); |
| 575 } | 577 } |
| 576 | 578 |
| 579 TextRunList::TextRunList() {} | |
| 580 | |
| 581 TextRunList::~TextRunList() {} | |
| 582 | |
| 583 void TextRunList::InitIndexMap() { | |
| 584 if (runs_.size() == 1) { | |
| 585 visual_to_logical_ = logical_to_visual_ = std::vector<int32_t>(1, 0); | |
| 586 return; | |
| 587 } | |
| 588 const size_t num_runs = runs_.size(); | |
| 589 std::vector<UBiDiLevel> levels(num_runs); | |
| 590 for (size_t i = 0; i < num_runs; ++i) | |
| 591 levels[i] = runs_[i]->level; | |
| 592 visual_to_logical_.resize(num_runs); | |
| 593 ubidi_reorderVisual(&levels[0], num_runs, &visual_to_logical_[0]); | |
| 594 logical_to_visual_.resize(num_runs); | |
| 595 ubidi_reorderLogical(&levels[0], num_runs, &logical_to_visual_[0]); | |
| 596 } | |
| 597 | |
| 598 void TextRunList::ComputePrecedingRunWidths() { | |
| 599 // Precalculate run width information. | |
| 600 float preceding_run_widths = 0.0f; | |
| 601 for (size_t i = 0; i < runs_.size(); ++i) { | |
| 602 TextRunHarfBuzz* run = runs_[visual_to_logical_[i]]; | |
| 603 run->preceding_run_widths = preceding_run_widths; | |
| 604 preceding_run_widths += run->width; | |
| 605 } | |
| 606 } | |
| 607 | |
| 608 float TextRunList::GetWidthF() const { | |
| 609 float width = 0.0f; | |
| 610 for (auto* run : runs_) | |
| 611 width += run->width; | |
| 612 return width; | |
| 613 } | |
| 614 | |
| 577 } // namespace internal | 615 } // namespace internal |
| 578 | 616 |
| 579 RenderTextHarfBuzz::RenderTextHarfBuzz() | 617 RenderTextHarfBuzz::RenderTextHarfBuzz() |
| 580 : RenderText(), | 618 : RenderText(), |
| 581 needs_layout_(false), | 619 update_layout_run_list_(false), |
| 620 update_display_run_list_(false), | |
| 621 update_grapheme_iterator_(false), | |
| 622 update_display_text_(false), | |
| 582 glyph_width_for_test_(0u) { | 623 glyph_width_for_test_(0u) { |
| 583 set_truncate_length(kMaxTextLength); | 624 set_truncate_length(kMaxTextLength); |
| 584 } | 625 } |
| 585 | 626 |
| 586 RenderTextHarfBuzz::~RenderTextHarfBuzz() {} | 627 RenderTextHarfBuzz::~RenderTextHarfBuzz() {} |
| 587 | 628 |
| 588 scoped_ptr<RenderText> RenderTextHarfBuzz::CreateInstanceOfSameType() const { | 629 scoped_ptr<RenderText> RenderTextHarfBuzz::CreateInstanceOfSameType() const { |
| 589 return scoped_ptr<RenderTextHarfBuzz>(new RenderTextHarfBuzz); | 630 return scoped_ptr<RenderTextHarfBuzz>(new RenderTextHarfBuzz); |
| 590 } | 631 } |
| 591 | 632 |
| 633 const base::string16& RenderTextHarfBuzz::GetDisplayText() { | |
| 634 // TODO(oshima): Consider supporting eliding multi-line text. | |
| 635 // This requires max_line support first. | |
| 636 if (multiline() || | |
| 637 elide_behavior() == NO_ELIDE || | |
| 638 elide_behavior() == FADE_TAIL) { | |
| 639 // Call UpdateDisplayText to clear |display_text_| and |text_elided_| | |
| 640 // on the RenderText class. | |
| 641 UpdateDisplayText(0); | |
| 642 update_display_text_ = false; | |
| 643 display_run_list_.reset(); | |
| 644 return layout_text(); | |
| 645 } | |
| 646 | |
| 647 EnsureLayoutRunList(); | |
| 648 DCHECK(!update_display_text_); | |
| 649 return text_elided() ? display_text() : layout_text(); | |
| 650 } | |
| 651 | |
| 592 Size RenderTextHarfBuzz::GetStringSize() { | 652 Size RenderTextHarfBuzz::GetStringSize() { |
| 593 const SizeF size_f = GetStringSizeF(); | 653 const SizeF size_f = GetStringSizeF(); |
| 594 return Size(std::ceil(size_f.width()), size_f.height()); | 654 return Size(std::ceil(size_f.width()), size_f.height()); |
| 595 } | 655 } |
| 596 | 656 |
| 597 SizeF RenderTextHarfBuzz::GetStringSizeF() { | 657 SizeF RenderTextHarfBuzz::GetStringSizeF() { |
| 598 EnsureLayout(); | 658 EnsureLayout(); |
| 599 return total_size_; | 659 return total_size_; |
| 600 } | 660 } |
| 601 | 661 |
| 602 SelectionModel RenderTextHarfBuzz::FindCursorPosition(const Point& point) { | 662 SelectionModel RenderTextHarfBuzz::FindCursorPosition(const Point& point) { |
| 603 EnsureLayout(); | 663 EnsureLayout(); |
| 604 | 664 |
| 605 int x = ToTextPoint(point).x(); | 665 int x = ToTextPoint(point).x(); |
| 606 float offset = 0; | 666 float offset = 0; |
| 607 size_t run_index = GetRunContainingXCoord(x, &offset); | 667 size_t run_index = GetRunContainingXCoord(x, &offset); |
| 608 if (run_index >= runs_.size()) | 668 |
| 669 internal::TextRunList* run_list = GetRunList(); | |
| 670 | |
|
msw
2015/02/13 22:19:05
nit: I meant to remove this blank line.
oshima
2015/02/13 23:24:11
Done.
| |
| 671 if (run_index >= run_list->size()) | |
| 609 return EdgeSelectionModel((x < 0) ? CURSOR_LEFT : CURSOR_RIGHT); | 672 return EdgeSelectionModel((x < 0) ? CURSOR_LEFT : CURSOR_RIGHT); |
| 610 const internal::TextRunHarfBuzz& run = *runs_[run_index]; | 673 const internal::TextRunHarfBuzz& run = *run_list->runs()[run_index]; |
| 611 | |
| 612 for (size_t i = 0; i < run.glyph_count; ++i) { | 674 for (size_t i = 0; i < run.glyph_count; ++i) { |
| 613 const SkScalar end = | 675 const SkScalar end = |
| 614 i + 1 == run.glyph_count ? run.width : run.positions[i + 1].x(); | 676 i + 1 == run.glyph_count ? run.width : run.positions[i + 1].x(); |
| 615 const SkScalar middle = (end + run.positions[i].x()) / 2; | 677 const SkScalar middle = (end + run.positions[i].x()) / 2; |
| 616 | 678 |
| 617 if (offset < middle) { | 679 if (offset < middle) { |
| 618 return SelectionModel(LayoutIndexToTextIndex( | 680 return SelectionModel(DisplayIndexToTextIndex( |
| 619 run.glyph_to_char[i] + (run.is_rtl ? 1 : 0)), | 681 run.glyph_to_char[i] + (run.is_rtl ? 1 : 0)), |
| 620 (run.is_rtl ? CURSOR_BACKWARD : CURSOR_FORWARD)); | 682 (run.is_rtl ? CURSOR_BACKWARD : CURSOR_FORWARD)); |
| 621 } | 683 } |
| 622 if (offset < end) { | 684 if (offset < end) { |
| 623 return SelectionModel(LayoutIndexToTextIndex( | 685 return SelectionModel(DisplayIndexToTextIndex( |
| 624 run.glyph_to_char[i] + (run.is_rtl ? 0 : 1)), | 686 run.glyph_to_char[i] + (run.is_rtl ? 0 : 1)), |
| 625 (run.is_rtl ? CURSOR_FORWARD : CURSOR_BACKWARD)); | 687 (run.is_rtl ? CURSOR_FORWARD : CURSOR_BACKWARD)); |
| 626 } | 688 } |
| 627 } | 689 } |
| 628 return EdgeSelectionModel(CURSOR_RIGHT); | 690 return EdgeSelectionModel(CURSOR_RIGHT); |
| 629 } | 691 } |
| 630 | 692 |
| 631 std::vector<RenderText::FontSpan> RenderTextHarfBuzz::GetFontSpansForTesting() { | 693 std::vector<RenderText::FontSpan> RenderTextHarfBuzz::GetFontSpansForTesting() { |
| 632 EnsureLayout(); | 694 EnsureLayout(); |
| 633 | 695 |
| 696 internal::TextRunList* run_list = GetRunList(); | |
| 634 std::vector<RenderText::FontSpan> spans; | 697 std::vector<RenderText::FontSpan> spans; |
| 635 for (size_t i = 0; i < runs_.size(); ++i) { | 698 for (auto* run : run_list->runs()) { |
| 636 SkString family_name; | 699 SkString family_name; |
| 637 runs_[i]->skia_face->getFamilyName(&family_name); | 700 run->skia_face->getFamilyName(&family_name); |
| 638 Font font(family_name.c_str(), runs_[i]->font_size); | 701 Font font(family_name.c_str(), run->font_size); |
| 639 spans.push_back(RenderText::FontSpan(font, | 702 spans.push_back(RenderText::FontSpan( |
| 640 Range(LayoutIndexToTextIndex(runs_[i]->range.start()), | 703 font, |
| 641 LayoutIndexToTextIndex(runs_[i]->range.end())))); | 704 Range(DisplayIndexToTextIndex(run->range.start()), |
| 705 DisplayIndexToTextIndex(run->range.end())))); | |
| 642 } | 706 } |
| 643 | 707 |
| 644 return spans; | 708 return spans; |
| 645 } | 709 } |
| 646 | 710 |
| 647 Range RenderTextHarfBuzz::GetGlyphBounds(size_t index) { | 711 Range RenderTextHarfBuzz::GetGlyphBounds(size_t index) { |
| 648 EnsureLayout(); | 712 EnsureLayout(); |
| 649 const size_t run_index = | 713 const size_t run_index = |
| 650 GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD)); | 714 GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD)); |
| 715 internal::TextRunList* run_list = GetRunList(); | |
| 651 // Return edge bounds if the index is invalid or beyond the layout text size. | 716 // Return edge bounds if the index is invalid or beyond the layout text size. |
| 652 if (run_index >= runs_.size()) | 717 if (run_index >= run_list->size()) |
| 653 return Range(GetStringSize().width()); | 718 return Range(GetStringSize().width()); |
| 654 const size_t layout_index = TextIndexToLayoutIndex(index); | 719 const size_t layout_index = TextIndexToDisplayIndex(index); |
| 655 internal::TextRunHarfBuzz* run = runs_[run_index]; | 720 internal::TextRunHarfBuzz* run = run_list->runs()[run_index]; |
| 656 RangeF bounds = | 721 RangeF bounds = |
| 657 run->GetGraphemeBounds(grapheme_iterator_.get(), layout_index); | 722 run->GetGraphemeBounds(GetGraphemeIterator(), layout_index); |
| 658 // If cursor is enabled, extend the last glyph up to the rightmost cursor | 723 // If cursor is enabled, extend the last glyph up to the rightmost cursor |
| 659 // position since clients expect them to be contiguous. | 724 // position since clients expect them to be contiguous. |
| 660 if (cursor_enabled() && run_index == runs_.size() - 1 && | 725 if (cursor_enabled() && run_index == run_list->size() - 1 && |
| 661 index == (run->is_rtl ? run->range.start() : run->range.end() - 1)) | 726 index == (run->is_rtl ? run->range.start() : run->range.end() - 1)) |
| 662 bounds.second = std::ceil(bounds.second); | 727 bounds.second = std::ceil(bounds.second); |
| 663 return RoundRangeF(run->is_rtl ? | 728 return RoundRangeF(run->is_rtl ? |
| 664 RangeF(bounds.second, bounds.first) : bounds); | 729 RangeF(bounds.second, bounds.first) : bounds); |
| 665 } | 730 } |
| 666 | 731 |
| 667 int RenderTextHarfBuzz::GetLayoutTextBaseline() { | 732 int RenderTextHarfBuzz::GetDisplayTextBaseline() { |
| 668 EnsureLayout(); | 733 EnsureLayout(); |
| 669 return lines()[0].baseline; | 734 return lines()[0].baseline; |
| 670 } | 735 } |
| 671 | 736 |
| 672 SelectionModel RenderTextHarfBuzz::AdjacentCharSelectionModel( | 737 SelectionModel RenderTextHarfBuzz::AdjacentCharSelectionModel( |
| 673 const SelectionModel& selection, | 738 const SelectionModel& selection, |
| 674 VisualCursorDirection direction) { | 739 VisualCursorDirection direction) { |
| 675 DCHECK(!needs_layout_); | 740 DCHECK(!update_display_run_list_); |
| 741 | |
| 742 internal::TextRunList* run_list = GetRunList(); | |
| 676 internal::TextRunHarfBuzz* run; | 743 internal::TextRunHarfBuzz* run; |
| 744 | |
| 677 size_t run_index = GetRunContainingCaret(selection); | 745 size_t run_index = GetRunContainingCaret(selection); |
| 678 if (run_index >= runs_.size()) { | 746 if (run_index >= run_list->size()) { |
| 679 // The cursor is not in any run: we're at the visual and logical edge. | 747 // The cursor is not in any run: we're at the visual and logical edge. |
| 680 SelectionModel edge = EdgeSelectionModel(direction); | 748 SelectionModel edge = EdgeSelectionModel(direction); |
| 681 if (edge.caret_pos() == selection.caret_pos()) | 749 if (edge.caret_pos() == selection.caret_pos()) |
| 682 return edge; | 750 return edge; |
| 683 int visual_index = (direction == CURSOR_RIGHT) ? 0 : runs_.size() - 1; | 751 int visual_index = (direction == CURSOR_RIGHT) ? 0 : run_list->size() - 1; |
| 684 run = runs_[visual_to_logical_[visual_index]]; | 752 run = run_list->runs()[run_list->visual_to_logical(visual_index)]; |
| 685 } else { | 753 } else { |
| 686 // If the cursor is moving within the current run, just move it by one | 754 // If the cursor is moving within the current run, just move it by one |
| 687 // grapheme in the appropriate direction. | 755 // grapheme in the appropriate direction. |
| 688 run = runs_[run_index]; | 756 run = run_list->runs()[run_index]; |
| 689 size_t caret = selection.caret_pos(); | 757 size_t caret = selection.caret_pos(); |
| 690 bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT); | 758 bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT); |
| 691 if (forward_motion) { | 759 if (forward_motion) { |
| 692 if (caret < LayoutIndexToTextIndex(run->range.end())) { | 760 if (caret < DisplayIndexToTextIndex(run->range.end())) { |
| 693 caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); | 761 caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); |
| 694 return SelectionModel(caret, CURSOR_BACKWARD); | 762 return SelectionModel(caret, CURSOR_BACKWARD); |
| 695 } | 763 } |
| 696 } else { | 764 } else { |
| 697 if (caret > LayoutIndexToTextIndex(run->range.start())) { | 765 if (caret > DisplayIndexToTextIndex(run->range.start())) { |
| 698 caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD); | 766 caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD); |
| 699 return SelectionModel(caret, CURSOR_FORWARD); | 767 return SelectionModel(caret, CURSOR_FORWARD); |
| 700 } | 768 } |
| 701 } | 769 } |
| 702 // The cursor is at the edge of a run; move to the visually adjacent run. | 770 // The cursor is at the edge of a run; move to the visually adjacent run. |
| 703 int visual_index = logical_to_visual_[run_index]; | 771 int visual_index = run_list->logical_to_visual(run_index); |
| 704 visual_index += (direction == CURSOR_LEFT) ? -1 : 1; | 772 visual_index += (direction == CURSOR_LEFT) ? -1 : 1; |
| 705 if (visual_index < 0 || visual_index >= static_cast<int>(runs_.size())) | 773 if (visual_index < 0 || visual_index >= static_cast<int>(run_list->size())) |
| 706 return EdgeSelectionModel(direction); | 774 return EdgeSelectionModel(direction); |
| 707 run = runs_[visual_to_logical_[visual_index]]; | 775 run = run_list->runs()[run_list->visual_to_logical(visual_index)]; |
| 708 } | 776 } |
| 709 bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT); | 777 bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT); |
| 710 return forward_motion ? FirstSelectionModelInsideRun(run) : | 778 return forward_motion ? FirstSelectionModelInsideRun(run) : |
| 711 LastSelectionModelInsideRun(run); | 779 LastSelectionModelInsideRun(run); |
| 712 } | 780 } |
| 713 | 781 |
| 714 SelectionModel RenderTextHarfBuzz::AdjacentWordSelectionModel( | 782 SelectionModel RenderTextHarfBuzz::AdjacentWordSelectionModel( |
| 715 const SelectionModel& selection, | 783 const SelectionModel& selection, |
| 716 VisualCursorDirection direction) { | 784 VisualCursorDirection direction) { |
| 717 if (obscured()) | 785 if (obscured()) |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 751 // Move to the top of current word. | 819 // Move to the top of current word. |
| 752 pos = begin; | 820 pos = begin; |
| 753 break; | 821 break; |
| 754 } | 822 } |
| 755 pos = iter.pos() - iter.GetString().length(); | 823 pos = iter.pos() - iter.GetString().length(); |
| 756 } | 824 } |
| 757 } | 825 } |
| 758 } | 826 } |
| 759 return SelectionModel(pos, CURSOR_FORWARD); | 827 return SelectionModel(pos, CURSOR_FORWARD); |
| 760 #else | 828 #else |
| 829 internal::TextRunList* run_list = GetRunList(); | |
| 761 SelectionModel cur(selection); | 830 SelectionModel cur(selection); |
| 762 for (;;) { | 831 for (;;) { |
| 763 cur = AdjacentCharSelectionModel(cur, direction); | 832 cur = AdjacentCharSelectionModel(cur, direction); |
| 764 size_t run = GetRunContainingCaret(cur); | 833 size_t run = GetRunContainingCaret(cur); |
| 765 if (run == runs_.size()) | 834 if (run == run_list->size()) |
| 766 break; | 835 break; |
| 767 const bool is_forward = runs_[run]->is_rtl == (direction == CURSOR_LEFT); | 836 const bool is_forward = |
| 837 run_list->runs()[run]->is_rtl == (direction == CURSOR_LEFT); | |
| 768 size_t cursor = cur.caret_pos(); | 838 size_t cursor = cur.caret_pos(); |
| 769 if (is_forward ? iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor)) | 839 if (is_forward ? iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor)) |
| 770 break; | 840 break; |
| 771 } | 841 } |
| 772 return cur; | 842 return cur; |
| 773 #endif | 843 #endif |
| 774 } | 844 } |
| 775 | 845 |
| 776 std::vector<Rect> RenderTextHarfBuzz::GetSubstringBounds(const Range& range) { | 846 std::vector<Rect> RenderTextHarfBuzz::GetSubstringBounds(const Range& range) { |
| 777 DCHECK(!needs_layout_); | 847 DCHECK(!update_display_run_list_); |
| 778 DCHECK(Range(0, text().length()).Contains(range)); | 848 DCHECK(Range(0, text().length()).Contains(range)); |
| 779 Range layout_range(TextIndexToLayoutIndex(range.start()), | 849 Range layout_range(TextIndexToDisplayIndex(range.start()), |
| 780 TextIndexToLayoutIndex(range.end())); | 850 TextIndexToDisplayIndex(range.end())); |
| 781 DCHECK(Range(0, GetLayoutText().length()).Contains(layout_range)); | 851 DCHECK(Range(0, GetDisplayText().length()).Contains(layout_range)); |
| 782 | 852 |
| 783 std::vector<Rect> rects; | 853 std::vector<Rect> rects; |
| 784 if (layout_range.is_empty()) | 854 if (layout_range.is_empty()) |
| 785 return rects; | 855 return rects; |
| 786 std::vector<Range> bounds; | 856 std::vector<Range> bounds; |
| 787 | 857 |
| 858 internal::TextRunList* run_list = GetRunList(); | |
| 859 | |
| 788 // Add a Range for each run/selection intersection. | 860 // Add a Range for each run/selection intersection. |
| 789 for (size_t i = 0; i < runs_.size(); ++i) { | 861 for (size_t i = 0; i < run_list->size(); ++i) { |
| 790 internal::TextRunHarfBuzz* run = runs_[visual_to_logical_[i]]; | 862 internal::TextRunHarfBuzz* run = |
| 863 run_list->runs()[run_list->visual_to_logical(i)]; | |
| 791 Range intersection = run->range.Intersect(layout_range); | 864 Range intersection = run->range.Intersect(layout_range); |
| 792 if (!intersection.IsValid()) | 865 if (!intersection.IsValid()) |
| 793 continue; | 866 continue; |
| 794 DCHECK(!intersection.is_reversed()); | 867 DCHECK(!intersection.is_reversed()); |
| 795 const Range leftmost_character_x = RoundRangeF(run->GetGraphemeBounds( | 868 const Range leftmost_character_x = RoundRangeF(run->GetGraphemeBounds( |
| 796 grapheme_iterator_.get(), | 869 GetGraphemeIterator(), |
| 797 run->is_rtl ? intersection.end() - 1 : intersection.start())); | 870 run->is_rtl ? intersection.end() - 1 : intersection.start())); |
| 798 const Range rightmost_character_x = RoundRangeF(run->GetGraphemeBounds( | 871 const Range rightmost_character_x = RoundRangeF(run->GetGraphemeBounds( |
| 799 grapheme_iterator_.get(), | 872 GetGraphemeIterator(), |
| 800 run->is_rtl ? intersection.start() : intersection.end() - 1)); | 873 run->is_rtl ? intersection.start() : intersection.end() - 1)); |
| 801 Range range_x(leftmost_character_x.start(), rightmost_character_x.end()); | 874 Range range_x(leftmost_character_x.start(), rightmost_character_x.end()); |
| 802 DCHECK(!range_x.is_reversed()); | 875 DCHECK(!range_x.is_reversed()); |
| 803 if (range_x.is_empty()) | 876 if (range_x.is_empty()) |
| 804 continue; | 877 continue; |
| 805 | 878 |
| 806 // Union this with the last range if they're adjacent. | 879 // Union this with the last range if they're adjacent. |
| 807 DCHECK(bounds.empty() || bounds.back().GetMax() <= range_x.GetMin()); | 880 DCHECK(bounds.empty() || bounds.back().GetMax() <= range_x.GetMin()); |
| 808 if (!bounds.empty() && bounds.back().GetMax() == range_x.GetMin()) { | 881 if (!bounds.empty() && bounds.back().GetMax() == range_x.GetMin()) { |
| 809 range_x = Range(bounds.back().GetMin(), range_x.GetMax()); | 882 range_x = Range(bounds.back().GetMin(), range_x.GetMax()); |
| 810 bounds.pop_back(); | 883 bounds.pop_back(); |
| 811 } | 884 } |
| 812 bounds.push_back(range_x); | 885 bounds.push_back(range_x); |
| 813 } | 886 } |
| 814 for (size_t i = 0; i < bounds.size(); ++i) { | 887 for (Range& bound : bounds) { |
| 815 std::vector<Rect> current_rects = TextBoundsToViewBounds(bounds[i]); | 888 std::vector<Rect> current_rects = TextBoundsToViewBounds(bound); |
| 816 rects.insert(rects.end(), current_rects.begin(), current_rects.end()); | 889 rects.insert(rects.end(), current_rects.begin(), current_rects.end()); |
| 817 } | 890 } |
| 818 return rects; | 891 return rects; |
| 819 } | 892 } |
| 820 | 893 |
| 821 size_t RenderTextHarfBuzz::TextIndexToLayoutIndex(size_t index) const { | 894 size_t RenderTextHarfBuzz::TextIndexToDisplayIndex(size_t index) { |
| 822 DCHECK_LE(index, text().length()); | 895 return TextIndexToGivenTextIndex(GetDisplayText(), index); |
| 823 ptrdiff_t i = obscured() ? UTF16IndexToOffset(text(), 0, index) : index; | |
| 824 CHECK_GE(i, 0); | |
| 825 // Clamp layout indices to the length of the text actually used for layout. | |
| 826 return std::min<size_t>(GetLayoutText().length(), i); | |
| 827 } | 896 } |
| 828 | 897 |
| 829 size_t RenderTextHarfBuzz::LayoutIndexToTextIndex(size_t index) const { | 898 size_t RenderTextHarfBuzz::DisplayIndexToTextIndex(size_t index) { |
| 830 if (!obscured()) | 899 if (!obscured()) |
| 831 return index; | 900 return index; |
| 832 | |
| 833 DCHECK_LE(index, GetLayoutText().length()); | |
| 834 const size_t text_index = UTF16OffsetToIndex(text(), 0, index); | 901 const size_t text_index = UTF16OffsetToIndex(text(), 0, index); |
| 835 DCHECK_LE(text_index, text().length()); | 902 DCHECK_LE(text_index, text().length()); |
| 836 return text_index; | 903 return text_index; |
| 837 } | 904 } |
| 838 | 905 |
| 839 bool RenderTextHarfBuzz::IsValidCursorIndex(size_t index) { | 906 bool RenderTextHarfBuzz::IsValidCursorIndex(size_t index) { |
| 840 if (index == 0 || index == text().length()) | 907 if (index == 0 || index == text().length()) |
| 841 return true; | 908 return true; |
| 842 if (!IsValidLogicalIndex(index)) | 909 if (!IsValidLogicalIndex(index)) |
| 843 return false; | 910 return false; |
| 844 EnsureLayout(); | 911 base::i18n::BreakIterator* grapheme_iterator = GetGraphemeIterator(); |
| 845 return !grapheme_iterator_ || grapheme_iterator_->IsGraphemeBoundary(index); | 912 return !grapheme_iterator || grapheme_iterator->IsGraphemeBoundary(index); |
| 846 } | 913 } |
| 847 | 914 |
| 848 void RenderTextHarfBuzz::ResetLayout() { | 915 void RenderTextHarfBuzz::OnLayoutTextAttributeChanged(bool text_changed) { |
| 849 needs_layout_ = true; | 916 update_layout_run_list_ = true; |
| 917 OnDisplayTextAttributeChanged(); | |
| 918 } | |
| 919 | |
| 920 void RenderTextHarfBuzz::OnDisplayTextAttributeChanged() { | |
| 921 update_display_text_ = true; | |
| 922 update_grapheme_iterator_ = true; | |
| 850 } | 923 } |
| 851 | 924 |
| 852 void RenderTextHarfBuzz::EnsureLayout() { | 925 void RenderTextHarfBuzz::EnsureLayout() { |
| 853 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. | 926 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. |
| 854 tracked_objects::ScopedTracker tracking_profile( | 927 tracked_objects::ScopedTracker tracking_profile( |
| 855 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 928 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 856 "431326 RenderTextHarfBuzz::EnsureLayout")); | 929 "431326 RenderTextHarfBuzz::EnsureLayout")); |
| 857 | 930 |
| 858 if (needs_layout_) { | 931 EnsureLayoutRunList(); |
| 859 runs_.clear(); | |
| 860 grapheme_iterator_.reset(); | |
| 861 | 932 |
| 862 if (!GetLayoutText().empty()) { | 933 if (update_display_run_list_) { |
| 934 DCHECK(text_elided()); | |
| 935 const base::string16& display_text = GetDisplayText(); | |
| 936 display_run_list_.reset(new internal::TextRunList); | |
| 937 | |
| 938 if (!display_text.empty()) { | |
| 939 TRACE_EVENT0("ui", "RenderTextHarfBuzz:EnsureLayout1"); | |
| 940 | |
| 863 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is | 941 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is |
| 864 // fixed. | 942 // fixed. |
| 865 tracked_objects::ScopedTracker tracking_profile1( | 943 tracked_objects::ScopedTracker tracking_profile1( |
| 866 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 944 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 867 "431326 RenderTextHarfBuzz::EnsureLayout1")); | 945 "431326 RenderTextHarfBuzz::EnsureLayout1")); |
| 868 | 946 ItemizeTextToRuns(display_text, display_run_list_.get()); |
| 869 grapheme_iterator_.reset(new base::i18n::BreakIterator(GetLayoutText(), | |
| 870 base::i18n::BreakIterator::BREAK_CHARACTER)); | |
| 871 if (!grapheme_iterator_->Init()) | |
| 872 grapheme_iterator_.reset(); | |
| 873 | 947 |
| 874 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is | 948 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is |
| 875 // fixed. | 949 // fixed. |
| 876 tracked_objects::ScopedTracker tracking_profile11( | 950 tracked_objects::ScopedTracker tracking_profile2( |
| 877 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
| 878 "431326 RenderTextHarfBuzz::EnsureLayout11")); | |
| 879 | |
| 880 ItemizeText(); | |
| 881 | |
| 882 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is | |
| 883 // fixed. | |
| 884 tracked_objects::ScopedTracker tracking_profile12( | |
| 885 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 951 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 886 "431326 RenderTextHarfBuzz::EnsureLayout12")); | 952 "431326 RenderTextHarfBuzz::EnsureLayout12")); |
| 887 | 953 ShapeRunList(display_text, display_run_list_.get()); |
| 888 for (size_t i = 0; i < runs_.size(); ++i) | |
| 889 ShapeRun(runs_[i]); | |
| 890 | |
| 891 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is | |
| 892 // fixed. | |
| 893 tracked_objects::ScopedTracker tracking_profile13( | |
| 894 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
| 895 "431326 RenderTextHarfBuzz::EnsureLayout13")); | |
| 896 | |
| 897 // Precalculate run width information. | |
| 898 float preceding_run_widths = 0.0f; | |
| 899 for (size_t i = 0; i < runs_.size(); ++i) { | |
| 900 internal::TextRunHarfBuzz* run = runs_[visual_to_logical_[i]]; | |
| 901 run->preceding_run_widths = preceding_run_widths; | |
| 902 preceding_run_widths += run->width; | |
| 903 } | |
| 904 } | 954 } |
| 955 update_display_run_list_ = false; | |
| 905 | 956 |
| 906 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is | 957 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is |
| 907 // fixed. | 958 // fixed. |
| 908 tracked_objects::ScopedTracker tracking_profile14( | 959 tracked_objects::ScopedTracker tracking_profile14( |
| 909 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 960 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 910 "431326 RenderTextHarfBuzz::EnsureLayout14")); | 961 "431326 RenderTextHarfBuzz::EnsureLayout14")); |
| 911 | |
| 912 needs_layout_ = false; | |
| 913 std::vector<internal::Line> empty_lines; | 962 std::vector<internal::Line> empty_lines; |
| 914 set_lines(&empty_lines); | 963 set_lines(&empty_lines); |
| 915 } | 964 } |
| 916 | 965 |
| 917 if (lines().empty()) { | 966 if (lines().empty()) { |
| 918 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. | 967 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. |
| 919 tracked_objects::ScopedTracker tracking_profile2( | 968 tracked_objects::ScopedTracker tracking_profile2( |
| 920 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 969 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 921 "431326 RenderTextHarfBuzz::EnsureLayout2")); | 970 "431326 RenderTextHarfBuzz::EnsureLayout2")); |
| 922 | 971 |
| 972 internal::TextRunList* run_list = GetRunList(); | |
| 923 HarfBuzzLineBreaker line_breaker( | 973 HarfBuzzLineBreaker line_breaker( |
| 924 display_rect().width(), font_list().GetBaseline(), | 974 display_rect().width(), font_list().GetBaseline(), |
| 925 std::max(font_list().GetHeight(), min_line_height()), multiline(), | 975 std::max(font_list().GetHeight(), min_line_height()), multiline(), |
| 926 GetLayoutText(), multiline() ? &GetLineBreaks() : nullptr, runs_); | 976 GetDisplayText(), multiline() ? &GetLineBreaks() : nullptr, |
| 977 run_list->runs()); | |
| 927 | 978 |
| 928 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. | 979 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. |
| 929 tracked_objects::ScopedTracker tracking_profile3( | 980 tracked_objects::ScopedTracker tracking_profile3( |
| 930 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 981 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 931 "431326 RenderTextHarfBuzz::EnsureLayout3")); | 982 "431326 RenderTextHarfBuzz::EnsureLayout3")); |
| 932 | 983 |
| 933 for (size_t i = 0; i < runs_.size(); ++i) | 984 for (size_t i = 0; i < run_list->size(); ++i) |
| 934 line_breaker.AddRun(visual_to_logical_[i]); | 985 line_breaker.AddRun(run_list->visual_to_logical(i)); |
| 986 | |
| 935 std::vector<internal::Line> lines; | 987 std::vector<internal::Line> lines; |
| 936 line_breaker.Finalize(&lines, &total_size_); | 988 line_breaker.Finalize(&lines, &total_size_); |
| 937 set_lines(&lines); | 989 set_lines(&lines); |
| 938 } | 990 } |
| 939 } | 991 } |
| 940 | 992 |
| 941 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { | 993 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { |
| 942 DCHECK(!needs_layout_); | 994 DCHECK(!update_layout_run_list_); |
| 995 DCHECK(!update_display_run_list_); | |
| 996 DCHECK(!update_display_text_); | |
| 943 if (lines().empty()) | 997 if (lines().empty()) |
| 944 return; | 998 return; |
| 945 | 999 |
| 946 internal::SkiaTextRenderer renderer(canvas); | 1000 internal::SkiaTextRenderer renderer(canvas); |
| 947 ApplyFadeEffects(&renderer); | 1001 ApplyFadeEffects(&renderer); |
| 948 ApplyTextShadows(&renderer); | 1002 ApplyTextShadows(&renderer); |
| 949 ApplyCompositionAndSelectionStyles(); | 1003 ApplyCompositionAndSelectionStyles(); |
| 950 | 1004 |
| 1005 internal::TextRunList* run_list = GetRunList(); | |
| 951 for (size_t i = 0; i < lines().size(); ++i) { | 1006 for (size_t i = 0; i < lines().size(); ++i) { |
| 952 const internal::Line& line = lines()[i]; | 1007 const internal::Line& line = lines()[i]; |
| 953 const Vector2d origin = GetLineOffset(i) + Vector2d(0, line.baseline); | 1008 const Vector2d origin = GetLineOffset(i) + Vector2d(0, line.baseline); |
| 954 SkScalar preceding_segment_widths = 0; | 1009 SkScalar preceding_segment_widths = 0; |
| 955 for (const internal::LineSegment& segment : line.segments) { | 1010 for (const internal::LineSegment& segment : line.segments) { |
| 956 const internal::TextRunHarfBuzz& run = *runs_[segment.run]; | 1011 const internal::TextRunHarfBuzz& run = *run_list->runs()[segment.run]; |
| 957 renderer.SetTypeface(run.skia_face.get()); | 1012 renderer.SetTypeface(run.skia_face.get()); |
| 958 renderer.SetTextSize(SkIntToScalar(run.font_size)); | 1013 renderer.SetTextSize(SkIntToScalar(run.font_size)); |
| 959 renderer.SetFontRenderParams(run.render_params, | 1014 renderer.SetFontRenderParams(run.render_params, |
| 960 background_is_transparent()); | 1015 background_is_transparent()); |
| 961 Range glyphs_range = run.CharRangeToGlyphRange(segment.char_range); | 1016 Range glyphs_range = run.CharRangeToGlyphRange(segment.char_range); |
| 962 scoped_ptr<SkPoint[]> positions(new SkPoint[glyphs_range.length()]); | 1017 scoped_ptr<SkPoint[]> positions(new SkPoint[glyphs_range.length()]); |
| 963 SkScalar offset_x = | 1018 SkScalar offset_x = |
| 964 preceding_segment_widths - run.positions[glyphs_range.start()].x(); | 1019 preceding_segment_widths - run.positions[glyphs_range.start()].x(); |
| 965 for (size_t j = 0; j < glyphs_range.length(); ++j) { | 1020 for (size_t j = 0; j < glyphs_range.length(); ++j) { |
| 966 positions[j] = run.positions[(glyphs_range.is_reversed()) ? | 1021 positions[j] = run.positions[(glyphs_range.is_reversed()) ? |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1002 preceding_segment_widths += SkFloatToScalar(segment.width); | 1057 preceding_segment_widths += SkFloatToScalar(segment.width); |
| 1003 } | 1058 } |
| 1004 } | 1059 } |
| 1005 | 1060 |
| 1006 renderer.EndDiagonalStrike(); | 1061 renderer.EndDiagonalStrike(); |
| 1007 | 1062 |
| 1008 UndoCompositionAndSelectionStyles(); | 1063 UndoCompositionAndSelectionStyles(); |
| 1009 } | 1064 } |
| 1010 | 1065 |
| 1011 size_t RenderTextHarfBuzz::GetRunContainingCaret( | 1066 size_t RenderTextHarfBuzz::GetRunContainingCaret( |
| 1012 const SelectionModel& caret) const { | 1067 const SelectionModel& caret) { |
| 1013 DCHECK(!needs_layout_); | 1068 DCHECK(!update_display_run_list_); |
| 1014 size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos()); | 1069 size_t layout_position = TextIndexToDisplayIndex(caret.caret_pos()); |
| 1015 LogicalCursorDirection affinity = caret.caret_affinity(); | 1070 LogicalCursorDirection affinity = caret.caret_affinity(); |
| 1016 for (size_t run = 0; run < runs_.size(); ++run) { | 1071 internal::TextRunList* run_list = GetRunList(); |
| 1017 if (RangeContainsCaret(runs_[run]->range, layout_position, affinity)) | 1072 for (size_t i = 0; i < run_list->size(); ++i) { |
| 1018 return run; | 1073 internal::TextRunHarfBuzz* run = run_list->runs()[i]; |
| 1074 if (RangeContainsCaret(run->range, layout_position, affinity)) | |
| 1075 return i; | |
| 1019 } | 1076 } |
| 1020 return runs_.size(); | 1077 return run_list->size(); |
| 1021 } | 1078 } |
| 1022 | 1079 |
| 1023 size_t RenderTextHarfBuzz::GetRunContainingXCoord(float x, | 1080 size_t RenderTextHarfBuzz::GetRunContainingXCoord(float x, |
| 1024 float* offset) const { | 1081 float* offset) const { |
| 1025 DCHECK(!needs_layout_); | 1082 DCHECK(!update_display_run_list_); |
| 1083 const internal::TextRunList* run_list = GetRunList(); | |
| 1026 if (x < 0) | 1084 if (x < 0) |
| 1027 return runs_.size(); | 1085 return run_list->size(); |
| 1028 // Find the text run containing the argument point (assumed already offset). | 1086 // Find the text run containing the argument point (assumed already offset). |
| 1029 float current_x = 0; | 1087 float current_x = 0; |
| 1030 for (size_t i = 0; i < runs_.size(); ++i) { | 1088 for (size_t i = 0; i < run_list->size(); ++i) { |
| 1031 size_t run = visual_to_logical_[i]; | 1089 size_t run = run_list->visual_to_logical(i); |
| 1032 current_x += runs_[run]->width; | 1090 current_x += run_list->runs()[run]->width; |
| 1033 if (x < current_x) { | 1091 if (x < current_x) { |
| 1034 *offset = x - (current_x - runs_[run]->width); | 1092 *offset = x - (current_x - run_list->runs()[run]->width); |
| 1035 return run; | 1093 return run; |
| 1036 } | 1094 } |
| 1037 } | 1095 } |
| 1038 return runs_.size(); | 1096 return run_list->size(); |
| 1039 } | 1097 } |
| 1040 | 1098 |
| 1041 SelectionModel RenderTextHarfBuzz::FirstSelectionModelInsideRun( | 1099 SelectionModel RenderTextHarfBuzz::FirstSelectionModelInsideRun( |
| 1042 const internal::TextRunHarfBuzz* run) { | 1100 const internal::TextRunHarfBuzz* run) { |
| 1043 size_t position = LayoutIndexToTextIndex(run->range.start()); | 1101 size_t position = DisplayIndexToTextIndex(run->range.start()); |
| 1044 position = IndexOfAdjacentGrapheme(position, CURSOR_FORWARD); | 1102 position = IndexOfAdjacentGrapheme(position, CURSOR_FORWARD); |
| 1045 return SelectionModel(position, CURSOR_BACKWARD); | 1103 return SelectionModel(position, CURSOR_BACKWARD); |
| 1046 } | 1104 } |
| 1047 | 1105 |
| 1048 SelectionModel RenderTextHarfBuzz::LastSelectionModelInsideRun( | 1106 SelectionModel RenderTextHarfBuzz::LastSelectionModelInsideRun( |
| 1049 const internal::TextRunHarfBuzz* run) { | 1107 const internal::TextRunHarfBuzz* run) { |
| 1050 size_t position = LayoutIndexToTextIndex(run->range.end()); | 1108 size_t position = DisplayIndexToTextIndex(run->range.end()); |
| 1051 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); | 1109 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); |
| 1052 return SelectionModel(position, CURSOR_FORWARD); | 1110 return SelectionModel(position, CURSOR_FORWARD); |
| 1053 } | 1111 } |
| 1054 | 1112 |
| 1055 void RenderTextHarfBuzz::ItemizeText() { | 1113 void RenderTextHarfBuzz::ItemizeTextToRuns( |
| 1056 const base::string16& text = GetLayoutText(); | 1114 const base::string16& text, |
| 1057 const bool is_text_rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT; | 1115 internal::TextRunList* run_list_out) { |
| 1116 const bool is_text_rtl = GetTextDirection(text) == base::i18n::RIGHT_TO_LEFT; | |
| 1058 DCHECK_NE(0U, text.length()); | 1117 DCHECK_NE(0U, text.length()); |
| 1059 | 1118 |
| 1060 // If ICU fails to itemize the text, we create a run that spans the entire | 1119 // If ICU fails to itemize the text, we create a run that spans the entire |
| 1061 // text. This is needed because leaving the runs set empty causes some clients | 1120 // text. This is needed because leaving the runs set empty causes some clients |
| 1062 // to misbehave since they expect non-zero text metrics from a non-empty text. | 1121 // to misbehave since they expect non-zero text metrics from a non-empty text. |
| 1063 base::i18n::BiDiLineIterator bidi_iterator; | 1122 base::i18n::BiDiLineIterator bidi_iterator; |
| 1064 if (!bidi_iterator.Open(text, is_text_rtl, false)) { | 1123 if (!bidi_iterator.Open(text, is_text_rtl, false)) { |
| 1065 internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz; | 1124 internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz; |
| 1066 run->range = Range(0, text.length()); | 1125 run->range = Range(0, text.length()); |
| 1067 runs_.push_back(run); | 1126 run_list_out->add(run); |
| 1068 visual_to_logical_ = logical_to_visual_ = std::vector<int32_t>(1, 0); | 1127 run_list_out->InitIndexMap(); |
| 1069 return; | 1128 return; |
| 1070 } | 1129 } |
| 1071 | 1130 |
| 1072 // Temporarily apply composition underlines and selection colors. | 1131 // Temporarily apply composition underlines and selection colors. |
| 1073 ApplyCompositionAndSelectionStyles(); | 1132 ApplyCompositionAndSelectionStyles(); |
| 1074 | 1133 |
| 1075 // Build the list of runs from the script items and ranged styles. Use an | 1134 // Build the list of runs from the script items and ranged styles. Use an |
| 1076 // empty color BreakList to avoid breaking runs at color boundaries. | 1135 // empty color BreakList to avoid breaking runs at color boundaries. |
| 1077 BreakList<SkColor> empty_colors; | 1136 BreakList<SkColor> empty_colors; |
| 1078 empty_colors.SetMax(text.length()); | 1137 empty_colors.SetMax(text.length()); |
| 1079 internal::StyleIterator style(empty_colors, styles()); | 1138 internal::StyleIterator style(empty_colors, styles()); |
| 1080 | 1139 |
| 1081 for (size_t run_break = 0; run_break < text.length();) { | 1140 for (size_t run_break = 0; run_break < text.length();) { |
| 1082 internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz; | 1141 internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz; |
| 1083 run->range.set_start(run_break); | 1142 run->range.set_start(run_break); |
| 1084 run->font_style = (style.style(BOLD) ? Font::BOLD : 0) | | 1143 run->font_style = (style.style(BOLD) ? Font::BOLD : 0) | |
| 1085 (style.style(ITALIC) ? Font::ITALIC : 0); | 1144 (style.style(ITALIC) ? Font::ITALIC : 0); |
| 1086 run->strike = style.style(STRIKE); | 1145 run->strike = style.style(STRIKE); |
| 1087 run->diagonal_strike = style.style(DIAGONAL_STRIKE); | 1146 run->diagonal_strike = style.style(DIAGONAL_STRIKE); |
| 1088 run->underline = style.style(UNDERLINE); | 1147 run->underline = style.style(UNDERLINE); |
| 1089 | |
| 1090 int32 script_item_break = 0; | 1148 int32 script_item_break = 0; |
| 1091 bidi_iterator.GetLogicalRun(run_break, &script_item_break, &run->level); | 1149 bidi_iterator.GetLogicalRun(run_break, &script_item_break, &run->level); |
| 1092 // Odd BiDi embedding levels correspond to RTL runs. | 1150 // Odd BiDi embedding levels correspond to RTL runs. |
| 1093 run->is_rtl = (run->level % 2) == 1; | 1151 run->is_rtl = (run->level % 2) == 1; |
| 1094 // Find the length and script of this script run. | 1152 // Find the length and script of this script run. |
| 1095 script_item_break = ScriptInterval(text, run_break, | 1153 script_item_break = ScriptInterval(text, run_break, |
| 1096 script_item_break - run_break, &run->script) + run_break; | 1154 script_item_break - run_break, &run->script) + run_break; |
| 1097 | 1155 |
| 1098 // Find the next break and advance the iterators as needed. | 1156 // Find the next break and advance the iterators as needed. |
| 1099 run_break = std::min(static_cast<size_t>(script_item_break), | 1157 run_break = std::min( |
| 1100 TextIndexToLayoutIndex(style.GetRange().end())); | 1158 static_cast<size_t>(script_item_break), |
| 1159 TextIndexToGivenTextIndex(text, style.GetRange().end())); | |
| 1101 | 1160 |
| 1102 // Break runs at certain characters that need to be rendered separately to | 1161 // Break runs at certain characters that need to be rendered separately to |
| 1103 // prevent either an unusual character from forcing a fallback font on the | 1162 // prevent either an unusual character from forcing a fallback font on the |
| 1104 // entire run, or brackets from being affected by a fallback font. | 1163 // entire run, or brackets from being affected by a fallback font. |
| 1105 // http://crbug.com/278913, http://crbug.com/396776 | 1164 // http://crbug.com/278913, http://crbug.com/396776 |
| 1106 if (run_break > run->range.start()) | 1165 if (run_break > run->range.start()) |
| 1107 run_break = FindRunBreakingCharacter(text, run->range.start(), run_break); | 1166 run_break = FindRunBreakingCharacter(text, run->range.start(), run_break); |
| 1108 | 1167 |
| 1109 DCHECK(IsValidCodePointIndex(text, run_break)); | 1168 DCHECK(IsValidCodePointIndex(text, run_break)); |
| 1110 style.UpdatePosition(LayoutIndexToTextIndex(run_break)); | 1169 style.UpdatePosition(DisplayIndexToTextIndex(run_break)); |
| 1111 run->range.set_end(run_break); | 1170 run->range.set_end(run_break); |
| 1112 | 1171 |
| 1113 runs_.push_back(run); | 1172 run_list_out->add(run); |
| 1114 } | 1173 } |
| 1115 | 1174 |
| 1116 // Undo the temporarily applied composition underlines and selection colors. | 1175 // Undo the temporarily applied composition underlines and selection colors. |
| 1117 UndoCompositionAndSelectionStyles(); | 1176 UndoCompositionAndSelectionStyles(); |
| 1118 | 1177 |
| 1119 const size_t num_runs = runs_.size(); | 1178 run_list_out->InitIndexMap(); |
| 1120 std::vector<UBiDiLevel> levels(num_runs); | |
| 1121 for (size_t i = 0; i < num_runs; ++i) | |
| 1122 levels[i] = runs_[i]->level; | |
| 1123 visual_to_logical_.resize(num_runs); | |
| 1124 ubidi_reorderVisual(&levels[0], num_runs, &visual_to_logical_[0]); | |
| 1125 logical_to_visual_.resize(num_runs); | |
| 1126 ubidi_reorderLogical(&levels[0], num_runs, &logical_to_visual_[0]); | |
| 1127 } | 1179 } |
| 1128 | 1180 |
| 1129 bool RenderTextHarfBuzz::CompareFamily( | 1181 bool RenderTextHarfBuzz::CompareFamily( |
| 1130 internal::TextRunHarfBuzz* run, | 1182 const base::string16& text, |
| 1131 const std::string& family, | 1183 const std::string& family, |
| 1132 const gfx::FontRenderParams& render_params, | 1184 const gfx::FontRenderParams& render_params, |
| 1185 internal::TextRunHarfBuzz* run, | |
| 1133 std::string* best_family, | 1186 std::string* best_family, |
| 1134 gfx::FontRenderParams* best_render_params, | 1187 gfx::FontRenderParams* best_render_params, |
| 1135 size_t* best_missing_glyphs) { | 1188 size_t* best_missing_glyphs) { |
| 1136 if (!ShapeRunWithFont(run, family, render_params)) | 1189 if (!ShapeRunWithFont(text, family, render_params, run)) |
| 1137 return false; | 1190 return false; |
| 1138 | 1191 |
| 1139 const size_t missing_glyphs = run->CountMissingGlyphs(); | 1192 const size_t missing_glyphs = run->CountMissingGlyphs(); |
| 1140 if (missing_glyphs < *best_missing_glyphs) { | 1193 if (missing_glyphs < *best_missing_glyphs) { |
| 1141 *best_family = family; | 1194 *best_family = family; |
| 1142 *best_render_params = render_params; | 1195 *best_render_params = render_params; |
| 1143 *best_missing_glyphs = missing_glyphs; | 1196 *best_missing_glyphs = missing_glyphs; |
| 1144 } | 1197 } |
| 1145 return missing_glyphs == 0; | 1198 return missing_glyphs == 0; |
| 1146 } | 1199 } |
| 1147 | 1200 |
| 1148 void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) { | 1201 void RenderTextHarfBuzz::ShapeRunList(const base::string16& text, |
| 1202 internal::TextRunList* run_list) { | |
| 1203 for (auto* run : run_list->runs()) | |
| 1204 ShapeRun(text, run); | |
| 1205 run_list->ComputePrecedingRunWidths(); | |
| 1206 } | |
| 1207 | |
| 1208 void RenderTextHarfBuzz::ShapeRun(const base::string16& text, | |
| 1209 internal::TextRunHarfBuzz* run) { | |
| 1149 const Font& primary_font = font_list().GetPrimaryFont(); | 1210 const Font& primary_font = font_list().GetPrimaryFont(); |
| 1150 const std::string primary_family = primary_font.GetFontName(); | 1211 const std::string primary_family = primary_font.GetFontName(); |
| 1151 run->font_size = primary_font.GetFontSize(); | 1212 run->font_size = primary_font.GetFontSize(); |
| 1152 | 1213 |
| 1153 std::string best_family; | 1214 std::string best_family; |
| 1154 FontRenderParams best_render_params; | 1215 FontRenderParams best_render_params; |
| 1155 size_t best_missing_glyphs = std::numeric_limits<size_t>::max(); | 1216 size_t best_missing_glyphs = std::numeric_limits<size_t>::max(); |
| 1156 | 1217 |
| 1157 for (const Font& font : font_list().GetFonts()) { | 1218 for (const Font& font : font_list().GetFonts()) { |
| 1158 if (CompareFamily(run, font.GetFontName(), font.GetFontRenderParams(), | 1219 if (CompareFamily(text, font.GetFontName(), font.GetFontRenderParams(), |
| 1159 &best_family, &best_render_params, &best_missing_glyphs)) | 1220 run, &best_family, &best_render_params, |
| 1221 &best_missing_glyphs)) | |
| 1160 return; | 1222 return; |
| 1161 } | 1223 } |
| 1162 | 1224 |
| 1163 #if defined(OS_WIN) | 1225 #if defined(OS_WIN) |
| 1164 Font uniscribe_font; | 1226 Font uniscribe_font; |
| 1165 std::string uniscribe_family; | 1227 std::string uniscribe_family; |
| 1166 const base::char16* run_text = &(GetLayoutText()[run->range.start()]); | 1228 const base::char16* run_text = &(text[run->range.start()]); |
| 1167 if (GetUniscribeFallbackFont(primary_font, run_text, run->range.length(), | 1229 if (GetUniscribeFallbackFont(primary_font, run_text, run->range.length(), |
| 1168 &uniscribe_font)) { | 1230 &uniscribe_font)) { |
| 1169 uniscribe_family = uniscribe_font.GetFontName(); | 1231 uniscribe_family = uniscribe_font.GetFontName(); |
| 1170 if (CompareFamily(run, uniscribe_family, | 1232 if (CompareFamily(text, uniscribe_family, |
| 1171 uniscribe_font.GetFontRenderParams(), | 1233 uniscribe_font.GetFontRenderParams(), run, |
| 1172 &best_family, &best_render_params, &best_missing_glyphs)) | 1234 &best_family, &best_render_params, &best_missing_glyphs)) |
| 1173 return; | 1235 return; |
| 1174 } | 1236 } |
| 1175 #endif | 1237 #endif |
| 1176 | 1238 |
| 1177 std::vector<std::string> fallback_families = | 1239 std::vector<std::string> fallback_families = |
| 1178 GetFallbackFontFamilies(primary_family); | 1240 GetFallbackFontFamilies(primary_family); |
| 1179 | 1241 |
| 1180 #if defined(OS_WIN) | 1242 #if defined(OS_WIN) |
| 1181 // Append fonts in the fallback list of the Uniscribe font. | 1243 // Append fonts in the fallback list of the Uniscribe font. |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 1193 continue; | 1255 continue; |
| 1194 #if defined(OS_WIN) | 1256 #if defined(OS_WIN) |
| 1195 if (family == uniscribe_family) | 1257 if (family == uniscribe_family) |
| 1196 continue; | 1258 continue; |
| 1197 #endif | 1259 #endif |
| 1198 FontRenderParamsQuery query(false); | 1260 FontRenderParamsQuery query(false); |
| 1199 query.families.push_back(family); | 1261 query.families.push_back(family); |
| 1200 query.pixel_size = run->font_size; | 1262 query.pixel_size = run->font_size; |
| 1201 query.style = run->font_style; | 1263 query.style = run->font_style; |
| 1202 FontRenderParams fallback_render_params = GetFontRenderParams(query, NULL); | 1264 FontRenderParams fallback_render_params = GetFontRenderParams(query, NULL); |
| 1203 if (CompareFamily(run, family, fallback_render_params, &best_family, | 1265 if (CompareFamily(text, family, fallback_render_params, run, &best_family, |
| 1204 &best_render_params, &best_missing_glyphs)) | 1266 &best_render_params, &best_missing_glyphs)) |
| 1205 return; | 1267 return; |
| 1206 } | 1268 } |
| 1207 | 1269 |
| 1208 if (!best_family.empty() && | 1270 if (!best_family.empty() && |
| 1209 (best_family == run->family || | 1271 (best_family == run->family || |
| 1210 ShapeRunWithFont(run, best_family, best_render_params))) | 1272 ShapeRunWithFont(text, best_family, best_render_params, run))) |
| 1211 return; | 1273 return; |
| 1212 | 1274 |
| 1213 run->glyph_count = 0; | 1275 run->glyph_count = 0; |
| 1214 run->width = 0.0f; | 1276 run->width = 0.0f; |
| 1215 } | 1277 } |
| 1216 | 1278 |
| 1217 bool RenderTextHarfBuzz::ShapeRunWithFont(internal::TextRunHarfBuzz* run, | 1279 bool RenderTextHarfBuzz::ShapeRunWithFont(const base::string16& text, |
| 1218 const std::string& font_family, | 1280 const std::string& font_family, |
| 1219 const FontRenderParams& params) { | 1281 const FontRenderParams& params, |
| 1282 internal::TextRunHarfBuzz* run) { | |
| 1220 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. | 1283 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. |
| 1221 tracked_objects::ScopedTracker tracking_profile0( | 1284 tracked_objects::ScopedTracker tracking_profile0( |
| 1222 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 1285 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 1223 "431326 RenderTextHarfBuzz::ShapeRunWithFont0")); | 1286 "431326 RenderTextHarfBuzz::ShapeRunWithFont0")); |
| 1224 | 1287 |
| 1225 const base::string16& text = GetLayoutText(); | |
| 1226 skia::RefPtr<SkTypeface> skia_face = | 1288 skia::RefPtr<SkTypeface> skia_face = |
| 1227 internal::CreateSkiaTypeface(font_family, run->font_style); | 1289 internal::CreateSkiaTypeface(font_family, run->font_style); |
| 1228 if (skia_face == NULL) | 1290 if (skia_face == NULL) |
| 1229 return false; | 1291 return false; |
| 1230 run->skia_face = skia_face; | 1292 run->skia_face = skia_face; |
| 1231 run->family = font_family; | 1293 run->family = font_family; |
| 1232 run->render_params = params; | 1294 run->render_params = params; |
| 1233 | 1295 |
| 1234 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. | 1296 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. |
| 1235 tracked_objects::ScopedTracker tracking_profile01( | 1297 tracked_objects::ScopedTracker tracking_profile01( |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1323 // Round run widths if subpixel positioning is off to match native behavior. | 1385 // Round run widths if subpixel positioning is off to match native behavior. |
| 1324 if (!run->render_params.subpixel_positioning) | 1386 if (!run->render_params.subpixel_positioning) |
| 1325 run->width = std::floor(run->width + 0.5f); | 1387 run->width = std::floor(run->width + 0.5f); |
| 1326 } | 1388 } |
| 1327 | 1389 |
| 1328 hb_buffer_destroy(buffer); | 1390 hb_buffer_destroy(buffer); |
| 1329 hb_font_destroy(harfbuzz_font); | 1391 hb_font_destroy(harfbuzz_font); |
| 1330 return true; | 1392 return true; |
| 1331 } | 1393 } |
| 1332 | 1394 |
| 1395 void RenderTextHarfBuzz::EnsureLayoutRunList() { | |
| 1396 if (update_layout_run_list_) { | |
| 1397 layout_run_list_.reset(); | |
| 1398 | |
| 1399 const base::string16& text = layout_text(); | |
| 1400 if (!text.empty()) { | |
| 1401 TRACE_EVENT0("ui", "RenderTextHarfBuzz:EnsureLayoutRunList"); | |
| 1402 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is | |
| 1403 // fixed. | |
| 1404 tracked_objects::ScopedTracker tracking_profile1( | |
| 1405 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
| 1406 "431326 RenderTextHarfBuzz::EnsureLayout1")); | |
| 1407 ItemizeTextToRuns(text, &layout_run_list_); | |
| 1408 | |
| 1409 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is | |
| 1410 // fixed. | |
| 1411 tracked_objects::ScopedTracker tracking_profile2( | |
| 1412 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
| 1413 "431326 RenderTextHarfBuzz::EnsureLayout12")); | |
| 1414 ShapeRunList(text, &layout_run_list_); | |
| 1415 } | |
| 1416 | |
| 1417 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is | |
| 1418 // fixed. | |
| 1419 tracked_objects::ScopedTracker tracking_profile14( | |
| 1420 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
| 1421 "431326 RenderTextHarfBuzz::EnsureLayout14")); | |
| 1422 | |
| 1423 std::vector<internal::Line> empty_lines; | |
| 1424 set_lines(&empty_lines); | |
| 1425 display_run_list_.reset(); | |
| 1426 update_display_text_ = true; | |
| 1427 update_layout_run_list_ = false; | |
| 1428 } | |
| 1429 if (update_display_text_) { | |
| 1430 UpdateDisplayText(layout_run_list_.GetWidthF()); | |
| 1431 update_display_text_ = false; | |
| 1432 update_display_run_list_ = text_elided(); | |
| 1433 } | |
| 1434 } | |
| 1435 | |
| 1436 base::i18n::BreakIterator* RenderTextHarfBuzz::GetGraphemeIterator() { | |
| 1437 if (update_grapheme_iterator_) { | |
| 1438 update_grapheme_iterator_ = false; | |
| 1439 grapheme_iterator_.reset(new base::i18n::BreakIterator( | |
| 1440 GetDisplayText(), | |
| 1441 base::i18n::BreakIterator::BREAK_CHARACTER)); | |
| 1442 if (!grapheme_iterator_->Init()) | |
| 1443 grapheme_iterator_.reset(); | |
| 1444 } | |
| 1445 return grapheme_iterator_.get(); | |
| 1446 } | |
| 1447 | |
| 1448 size_t RenderTextHarfBuzz::TextIndexToGivenTextIndex( | |
| 1449 const base::string16& given_text, | |
| 1450 size_t index) { | |
| 1451 DCHECK(given_text == layout_text() || given_text == display_text()); | |
| 1452 DCHECK_LE(index, text().length()); | |
| 1453 ptrdiff_t i = obscured() ? UTF16IndexToOffset(text(), 0, index) : index; | |
| 1454 CHECK_GE(i, 0); | |
| 1455 // Clamp indices to the length of the given layout or display text. | |
| 1456 return std::min<size_t>(given_text.length(), i); | |
| 1457 } | |
| 1458 | |
| 1459 internal::TextRunList* RenderTextHarfBuzz::GetRunList() { | |
| 1460 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList(); | |
| 1461 } | |
| 1462 | |
| 1463 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const { | |
| 1464 DCHECK(!update_layout_run_list_); | |
| 1465 DCHECK(!update_display_run_list_); | |
| 1466 return text_elided() ? display_run_list_.get() : &layout_run_list_; | |
| 1467 } | |
| 1468 | |
| 1333 } // namespace gfx | 1469 } // namespace gfx |
| OLD | NEW |