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