Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(953)

Side by Side Diff: ui/gfx/render_text_harfbuzz.cc

Issue 916203002: Reduce the number of text reshaping in RenderText (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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) {
msw 2015/02/13 05:53:36 nit: remove internal::
oshima 2015/02/13 21:03:10 Done.
584 runs_.push_back(run);
msw 2015/02/13 05:53:35 nit: can this be in-lined?
oshima 2015/02/13 21:03:10 Done.
585 }
586
587 void TextRunList::Reset() {
588 runs_.clear();
msw 2015/02/13 05:53:35 ditto nit: can this be in-lined? (and maybe rename
oshima 2015/02/13 21:03:10 Done.
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 =
msw 2015/02/13 05:53:35 nit: remove internal:: here for a one-liner
oshima 2015/02/13 21:03:10 Done.
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 {
msw 2015/02/13 05:53:35 Replace GetWidth with a simple |float width_| and
oshima 2015/02/13 21:03:11 I can't precompute the width because run's with ma
msw 2015/02/13 21:49:23 Huh? Isn't ComputePrecedingRunWidths run after sha
oshima 2015/02/13 23:24:11 I think I know why the total size changed, due to
618 int width = 0;
msw 2015/02/13 05:53:35 nit: TextRunHarfBuzz is a float, shouldn't this be
oshima 2015/02/13 21:03:10 Done.
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_display_run_list_(false),
630 update_grapheme_iterator_(false),
631 update_display_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() ||
msw 2015/02/13 05:53:35 Add a TODO here to support eliding multi-line text
oshima 2015/02/13 21:03:10 Done.
644 elide_behavior() == NO_ELIDE ||
645 elide_behavior() == FADE_TAIL) {
646 UpdateDisplayText(0);
msw 2015/02/13 05:53:36 nit: It's odd to use UpdateDisplayText just to cle
oshima 2015/02/13 21:03:10 Done.
647 update_display_text_ = false;
648 display_run_list_.reset();
649 return layout_text();
650 }
651
652 EnsureLayoutRunList();
653
654 return text_elided() ? display_text() : layout_text();
msw 2015/02/13 05:53:35 Add DCHECK(!update_display_text_) just above this.
oshima 2015/02/13 21:03:10 Done.
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
msw 2015/02/13 05:53:35 nit: remove blank line.
oshima 2015/02/13 21:03:11 Done.
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
msw 2015/02/13 05:53:35 nit: remove blank line.
oshima 2015/02/13 21:03:10 Done.
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_display_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
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
msw 2015/02/13 05:53:35 nit: remove blank line.
oshima 2015/02/13 21:03:10 Done.
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_display_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());
msw 2015/02/13 05:53:35 Why remove this? Isn't it still reasonable and cor
oshima 2015/02/13 21:03:10 I removed this because this get called while compu
msw 2015/02/13 21:49:23 I liked the parity of TextIndexToLayoutIndex and L
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::OnLayoutTextAttributeChanged(bool text_changed) {
849 needs_layout_ = true; 924 update_layout_run_list_ = true;
925 OnDisplayTextAttributeChanged();
926 }
927
928 void RenderTextHarfBuzz::OnDisplayTextAttributeChanged() {
929 update_display_text_ = true;
msw 2015/02/13 05:53:35 I'm worried that lazily updating |display_text_| a
oshima 2015/02/13 21:03:10 They're protected, so only implementation can acce
msw 2015/02/13 21:49:23 I don't think you can easily DCHECK the RenderText
oshima 2015/02/13 23:24:11 What I had in mind was to change accessor virtual
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_display_run_list_) {
msw 2015/02/13 05:53:36 nit: optionally split this out to EnsureDisplayRun
oshima 2015/02/13 21:03:10 Let me do that in separate CL.
msw 2015/02/13 21:49:23 Add a TODO.
942 DCHECK(text_elided());
943 const base::string16& elided_text = GetLayoutText();
msw 2015/02/13 05:53:36 nit: display_text = GetDisplayText();
oshima 2015/02/13 21:03:10 Done.
944 display_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, 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 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, 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 } 962 }
963 update_display_run_list_ = false;
msw 2015/02/13 05:53:35 Perhaps set this at the top of the "if (update_dis
oshima 2015/02/13 21:03:11 I moved others. I think this is better to catch un
msw 2015/02/13 21:49:23 Acknowledged.
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()) {
msw 2015/02/13 05:53:36 nit: Maybe optionally split this out to EnsureLine
oshima 2015/02/13 21:03:10 Let me do that in a separate CL, along with Ensure
msw 2015/02/13 21:49:23 Add a TODO.
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
msw 2015/02/13 05:53:35 nit: remove blank line
oshima 2015/02/13 21:03:10 Done.
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_display_run_list_);
msw 2015/02/13 05:53:35 nit: also DCHECK(!update_display_text_) for comple
oshima 2015/02/13 21:03:11 Done.
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
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_display_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_display_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
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
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"));
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 display_run_list_.reset();
1437 update_display_text_ = true;
1438 }
1439 if (update_display_text_) {
1440 update_display_text_ = false;
1441 UpdateDisplayText(layout_run_list_.GetWidth());
1442 update_display_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 == display_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.
msw 2015/02/13 05:53:35 nit: // Clamp indices to the length of the given l
oshima 2015/02/13 21:03:10 Done.
1466 return std::min<size_t>(given_text.length(), i);
1467 }
1468
1469 internal::TextRunList* RenderTextHarfBuzz::GetRunList() {
msw 2015/02/13 05:53:35 nit: maybe return const_cast<RenderText*>(this)->G
oshima 2015/02/13 21:03:11 Done.
1470 DCHECK(!update_layout_run_list_);
1471 DCHECK(!update_display_run_list_);
1472 return text_elided() ? display_run_list_.get() : &layout_run_list_;
1473 }
1474
1475 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const {
1476 DCHECK(!update_layout_run_list_);
1477 DCHECK(!update_display_run_list_);
1478 return text_elided() ? display_run_list_.get() : &layout_run_list_;
1479 }
1480
1333 } // namespace gfx 1481 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698