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 #include <set> | 8 #include <set> |
9 | 9 |
10 #include "base/i18n/bidi_line_iterator.h" | 10 #include "base/i18n/bidi_line_iterator.h" |
(...skipping 628 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
639 GetClusterAtImpl(pos, range, glyph_to_char.rbegin(), glyph_to_char.rend(), | 639 GetClusterAtImpl(pos, range, glyph_to_char.rbegin(), glyph_to_char.rend(), |
640 true, chars, glyphs); | 640 true, chars, glyphs); |
641 return; | 641 return; |
642 } | 642 } |
643 | 643 |
644 GetClusterAtImpl(pos, range, glyph_to_char.begin(), glyph_to_char.end(), | 644 GetClusterAtImpl(pos, range, glyph_to_char.begin(), glyph_to_char.end(), |
645 false, chars, glyphs); | 645 false, chars, glyphs); |
646 } | 646 } |
647 | 647 |
648 RangeF TextRunHarfBuzz::GetGraphemeBounds( | 648 RangeF TextRunHarfBuzz::GetGraphemeBounds( |
649 base::i18n::BreakIterator* grapheme_iterator, | 649 RenderTextHarfBuzz* render_text, |
msw
2016/09/30 19:10:17
nit: fits on line above (git cl format)
Alexei Svitkine (slow)
2016/09/30 19:14:16
Done.
| |
650 size_t text_index) { | 650 size_t text_index) { |
651 DCHECK_LT(text_index, range.end()); | 651 DCHECK_LT(text_index, range.end()); |
652 if (glyph_count == 0) | 652 if (glyph_count == 0) |
653 return RangeF(preceding_run_widths, preceding_run_widths + width); | 653 return RangeF(preceding_run_widths, preceding_run_widths + width); |
654 | 654 |
655 Range chars; | 655 Range chars; |
656 Range glyphs; | 656 Range glyphs; |
657 GetClusterAt(text_index, &chars, &glyphs); | 657 GetClusterAt(text_index, &chars, &glyphs); |
658 const float cluster_begin_x = positions[glyphs.start()].x(); | 658 const float cluster_begin_x = positions[glyphs.start()].x(); |
659 const float cluster_end_x = glyphs.end() < glyph_count ? | 659 const float cluster_end_x = glyphs.end() < glyph_count ? |
660 positions[glyphs.end()].x() : SkFloatToScalar(width); | 660 positions[glyphs.end()].x() : SkFloatToScalar(width); |
661 | 661 |
662 // A cluster consists of a number of code points and corresponds to a number | 662 // A cluster consists of a number of code points and corresponds to a number |
663 // of glyphs that should be drawn together. A cluster can contain multiple | 663 // of glyphs that should be drawn together. A cluster can contain multiple |
664 // graphemes. In order to place the cursor at a grapheme boundary inside the | 664 // graphemes. In order to place the cursor at a grapheme boundary inside the |
665 // cluster, we simply divide the cluster width by the number of graphemes. | 665 // cluster, we simply divide the cluster width by the number of graphemes. |
666 if (chars.length() > 1 && grapheme_iterator) { | 666 // Note: The first call to GetGraphemeIterator() can be expensive, so avoid |
667 // doing it unless it's actually needed (when length > 1). | |
668 if (chars.length() > 1 && render_text->GetGraphemeIterator()) { | |
667 int before = 0; | 669 int before = 0; |
668 int total = 0; | 670 int total = 0; |
671 base::i18n::BreakIterator* grapheme_iterator = | |
672 render_text->GetGraphemeIterator(); | |
669 for (size_t i = chars.start(); i < chars.end(); ++i) { | 673 for (size_t i = chars.start(); i < chars.end(); ++i) { |
670 if (grapheme_iterator->IsGraphemeBoundary(i)) { | 674 if (grapheme_iterator->IsGraphemeBoundary(i)) { |
671 if (i < text_index) | 675 if (i < text_index) |
672 ++before; | 676 ++before; |
673 ++total; | 677 ++total; |
674 } | 678 } |
675 } | 679 } |
676 DCHECK_GT(total, 0); | 680 DCHECK_GT(total, 0); |
677 if (total > 1) { | 681 if (total > 1) { |
678 if (is_rtl) | 682 if (is_rtl) |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
862 Range RenderTextHarfBuzz::GetGlyphBounds(size_t index) { | 866 Range RenderTextHarfBuzz::GetGlyphBounds(size_t index) { |
863 EnsureLayout(); | 867 EnsureLayout(); |
864 const size_t run_index = | 868 const size_t run_index = |
865 GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD)); | 869 GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD)); |
866 internal::TextRunList* run_list = GetRunList(); | 870 internal::TextRunList* run_list = GetRunList(); |
867 // Return edge bounds if the index is invalid or beyond the layout text size. | 871 // Return edge bounds if the index is invalid or beyond the layout text size. |
868 if (run_index >= run_list->size()) | 872 if (run_index >= run_list->size()) |
869 return Range(GetStringSize().width()); | 873 return Range(GetStringSize().width()); |
870 const size_t layout_index = TextIndexToDisplayIndex(index); | 874 const size_t layout_index = TextIndexToDisplayIndex(index); |
871 internal::TextRunHarfBuzz* run = run_list->runs()[run_index]; | 875 internal::TextRunHarfBuzz* run = run_list->runs()[run_index]; |
872 RangeF bounds = | 876 RangeF bounds = run->GetGraphemeBounds(this, layout_index); |
873 run->GetGraphemeBounds(GetGraphemeIterator(), layout_index); | |
874 // If cursor is enabled, extend the last glyph up to the rightmost cursor | 877 // If cursor is enabled, extend the last glyph up to the rightmost cursor |
875 // position since clients expect them to be contiguous. | 878 // position since clients expect them to be contiguous. |
876 if (cursor_enabled() && run_index == run_list->size() - 1 && | 879 if (cursor_enabled() && run_index == run_list->size() - 1 && |
877 index == (run->is_rtl ? run->range.start() : run->range.end() - 1)) | 880 index == (run->is_rtl ? run->range.start() : run->range.end() - 1)) |
878 bounds.set_end(std::ceil(bounds.end())); | 881 bounds.set_end(std::ceil(bounds.end())); |
879 return run->is_rtl ? RangeF(bounds.end(), bounds.start()).Round() | 882 return run->is_rtl ? RangeF(bounds.end(), bounds.start()).Round() |
880 : bounds.Round(); | 883 : bounds.Round(); |
881 } | 884 } |
882 | 885 |
886 base::i18n::BreakIterator* RenderTextHarfBuzz::GetGraphemeIterator() { | |
887 if (update_grapheme_iterator_) { | |
888 update_grapheme_iterator_ = false; | |
889 grapheme_iterator_.reset(new base::i18n::BreakIterator( | |
890 GetDisplayText(), | |
891 base::i18n::BreakIterator::BREAK_CHARACTER)); | |
892 if (!grapheme_iterator_->Init()) | |
893 grapheme_iterator_.reset(); | |
894 } | |
895 return grapheme_iterator_.get(); | |
896 } | |
897 | |
883 int RenderTextHarfBuzz::GetDisplayTextBaseline() { | 898 int RenderTextHarfBuzz::GetDisplayTextBaseline() { |
884 EnsureLayout(); | 899 EnsureLayout(); |
885 return lines()[0].baseline; | 900 return lines()[0].baseline; |
886 } | 901 } |
887 | 902 |
888 SelectionModel RenderTextHarfBuzz::AdjacentCharSelectionModel( | 903 SelectionModel RenderTextHarfBuzz::AdjacentCharSelectionModel( |
889 const SelectionModel& selection, | 904 const SelectionModel& selection, |
890 VisualCursorDirection direction) { | 905 VisualCursorDirection direction) { |
891 DCHECK(!update_display_run_list_); | 906 DCHECK(!update_display_run_list_); |
892 | 907 |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1012 for (size_t i = 0; i < run_list->size(); ++i) { | 1027 for (size_t i = 0; i < run_list->size(); ++i) { |
1013 internal::TextRunHarfBuzz* run = | 1028 internal::TextRunHarfBuzz* run = |
1014 run_list->runs()[run_list->visual_to_logical(i)]; | 1029 run_list->runs()[run_list->visual_to_logical(i)]; |
1015 Range intersection = run->range.Intersect(layout_range); | 1030 Range intersection = run->range.Intersect(layout_range); |
1016 if (!intersection.IsValid()) | 1031 if (!intersection.IsValid()) |
1017 continue; | 1032 continue; |
1018 DCHECK(!intersection.is_reversed()); | 1033 DCHECK(!intersection.is_reversed()); |
1019 const size_t left_index = | 1034 const size_t left_index = |
1020 run->is_rtl ? intersection.end() - 1 : intersection.start(); | 1035 run->is_rtl ? intersection.end() - 1 : intersection.start(); |
1021 const Range leftmost_character_x = | 1036 const Range leftmost_character_x = |
1022 run->GetGraphemeBounds(GetGraphemeIterator(), left_index).Round(); | 1037 run->GetGraphemeBounds(this, left_index).Round(); |
1023 const size_t right_index = | 1038 const size_t right_index = |
1024 run->is_rtl ? intersection.start() : intersection.end() - 1; | 1039 run->is_rtl ? intersection.start() : intersection.end() - 1; |
1025 const Range rightmost_character_x = | 1040 const Range rightmost_character_x = |
1026 run->GetGraphemeBounds(GetGraphemeIterator(), right_index).Round(); | 1041 run->GetGraphemeBounds(this, right_index).Round(); |
1027 Range range_x(leftmost_character_x.start(), rightmost_character_x.end()); | 1042 Range range_x(leftmost_character_x.start(), rightmost_character_x.end()); |
1028 DCHECK(!range_x.is_reversed()); | 1043 DCHECK(!range_x.is_reversed()); |
1029 if (range_x.is_empty()) | 1044 if (range_x.is_empty()) |
1030 continue; | 1045 continue; |
1031 | 1046 |
1032 // Union this with the last range if they're adjacent. | 1047 // Union this with the last range if they're adjacent. |
1033 DCHECK(bounds.empty() || bounds.back().GetMax() <= range_x.GetMin()); | 1048 DCHECK(bounds.empty() || bounds.back().GetMax() <= range_x.GetMin()); |
1034 if (!bounds.empty() && bounds.back().GetMax() == range_x.GetMin()) { | 1049 if (!bounds.empty() && bounds.back().GetMax() == range_x.GetMin()) { |
1035 range_x = Range(bounds.back().GetMin(), range_x.GetMax()); | 1050 range_x = Range(bounds.back().GetMin(), range_x.GetMax()); |
1036 bounds.pop_back(); | 1051 bounds.pop_back(); |
(...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1561 update_display_text_ = true; | 1576 update_display_text_ = true; |
1562 update_layout_run_list_ = false; | 1577 update_layout_run_list_ = false; |
1563 } | 1578 } |
1564 if (update_display_text_) { | 1579 if (update_display_text_) { |
1565 UpdateDisplayText(multiline() ? 0 : layout_run_list_.width()); | 1580 UpdateDisplayText(multiline() ? 0 : layout_run_list_.width()); |
1566 update_display_text_ = false; | 1581 update_display_text_ = false; |
1567 update_display_run_list_ = text_elided(); | 1582 update_display_run_list_ = text_elided(); |
1568 } | 1583 } |
1569 } | 1584 } |
1570 | 1585 |
1571 base::i18n::BreakIterator* RenderTextHarfBuzz::GetGraphemeIterator() { | |
1572 if (update_grapheme_iterator_) { | |
1573 update_grapheme_iterator_ = false; | |
1574 grapheme_iterator_.reset(new base::i18n::BreakIterator( | |
1575 GetDisplayText(), | |
1576 base::i18n::BreakIterator::BREAK_CHARACTER)); | |
1577 if (!grapheme_iterator_->Init()) | |
1578 grapheme_iterator_.reset(); | |
1579 } | |
1580 return grapheme_iterator_.get(); | |
1581 } | |
1582 | |
1583 internal::TextRunList* RenderTextHarfBuzz::GetRunList() { | 1586 internal::TextRunList* RenderTextHarfBuzz::GetRunList() { |
1584 DCHECK(!update_layout_run_list_); | 1587 DCHECK(!update_layout_run_list_); |
1585 DCHECK(!update_display_run_list_); | 1588 DCHECK(!update_display_run_list_); |
1586 return text_elided() ? display_run_list_.get() : &layout_run_list_; | 1589 return text_elided() ? display_run_list_.get() : &layout_run_list_; |
1587 } | 1590 } |
1588 | 1591 |
1589 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const { | 1592 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const { |
1590 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList(); | 1593 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList(); |
1591 } | 1594 } |
1592 | 1595 |
1593 } // namespace gfx | 1596 } // namespace gfx |
OLD | NEW |