OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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.h" | 5 #include "ui/gfx/render_text.h" |
6 | 6 |
7 #include <limits.h> | 7 #include <limits.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <climits> | 10 #include <climits> |
(...skipping 703 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
714 } | 714 } |
715 | 715 |
716 void RenderText::SelectAll(bool reversed) { | 716 void RenderText::SelectAll(bool reversed) { |
717 const size_t length = text().length(); | 717 const size_t length = text().length(); |
718 const Range all = reversed ? Range(length, 0) : Range(0, length); | 718 const Range all = reversed ? Range(length, 0) : Range(0, length); |
719 const bool success = SelectRange(all); | 719 const bool success = SelectRange(all); |
720 DCHECK(success); | 720 DCHECK(success); |
721 } | 721 } |
722 | 722 |
723 void RenderText::SelectWord() { | 723 void RenderText::SelectWord() { |
724 if (obscured_) { | 724 SelectRange(ExpandRangeToWordBoundary(selection())); |
725 SelectAll(false); | |
726 return; | |
727 } | |
728 | |
729 size_t selection_max = selection().GetMax(); | |
730 | |
731 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); | |
732 bool success = iter.Init(); | |
733 DCHECK(success); | |
734 if (!success) | |
735 return; | |
736 | |
737 size_t selection_min = selection().GetMin(); | |
738 if (selection_min == text().length() && selection_min != 0) | |
739 --selection_min; | |
740 | |
741 for (; selection_min != 0; --selection_min) { | |
742 if (iter.IsStartOfWord(selection_min) || | |
743 iter.IsEndOfWord(selection_min)) | |
744 break; | |
745 } | |
746 | |
747 if (selection_min == selection_max && selection_max != text().length()) | |
748 ++selection_max; | |
749 | |
750 for (; selection_max < text().length(); ++selection_max) | |
751 if (iter.IsEndOfWord(selection_max) || iter.IsStartOfWord(selection_max)) | |
752 break; | |
753 | |
754 const bool reversed = selection().is_reversed(); | |
755 MoveCursorTo(reversed ? selection_max : selection_min, false); | |
756 MoveCursorTo(reversed ? selection_min : selection_max, true); | |
757 } | 725 } |
758 | 726 |
759 void RenderText::SetCompositionRange(const Range& composition_range) { | 727 void RenderText::SetCompositionRange(const Range& composition_range) { |
760 CHECK(!composition_range.IsValid() || | 728 CHECK(!composition_range.IsValid() || |
761 Range(0, text_.length()).Contains(composition_range)); | 729 Range(0, text_.length()).Contains(composition_range)); |
762 composition_range_.set_end(composition_range.end()); | 730 composition_range_.set_end(composition_range.end()); |
763 composition_range_.set_start(composition_range.start()); | 731 composition_range_.set_start(composition_range.start()); |
764 // TODO(oshima|msw): Altering composition underlines shouldn't | 732 // TODO(oshima|msw): Altering composition underlines shouldn't |
765 // require layout changes. It's currently necessary because | 733 // require layout changes. It's currently necessary because |
766 // RenderTextHarfBuzz paints text decorations by run, and | 734 // RenderTextHarfBuzz paints text decorations by run, and |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1035 Vector2d offset = display_rect().OffsetFromOrigin(); | 1003 Vector2d offset = display_rect().OffsetFromOrigin(); |
1036 // TODO(ckocagil): Apply the display offset for multiline scrolling. | 1004 // TODO(ckocagil): Apply the display offset for multiline scrolling. |
1037 if (!multiline()) | 1005 if (!multiline()) |
1038 offset.Add(GetUpdatedDisplayOffset()); | 1006 offset.Add(GetUpdatedDisplayOffset()); |
1039 else | 1007 else |
1040 offset.Add(Vector2d(0, lines_[line_number].preceding_heights)); | 1008 offset.Add(Vector2d(0, lines_[line_number].preceding_heights)); |
1041 offset.Add(GetAlignmentOffset(line_number)); | 1009 offset.Add(GetAlignmentOffset(line_number)); |
1042 return offset; | 1010 return offset; |
1043 } | 1011 } |
1044 | 1012 |
1013 bool RenderText::GetDecoratedWordAtPoint(const Point& point, | |
1014 DecoratedText* decorated_word, | |
1015 Point* baseline_point) { | |
1016 // FindCursorPosition doesn't currently support multiline. | |
1017 if (multiline() || obscured()) | |
1018 return false; | |
1019 | |
1020 const SelectionModel model_at_point = FindCursorPosition(point); | |
1021 const size_t word_index = | |
1022 GetNearestWordStartBoundary(model_at_point.caret_pos()); | |
1023 if (word_index >= text().length()) | |
1024 return false; | |
1025 | |
1026 const Range word_range = ExpandRangeToWordBoundary(Range(word_index)); | |
1027 DCHECK(!word_range.is_reversed()); | |
1028 DCHECK(!word_range.is_empty()); | |
1029 | |
1030 if (!GetDecoratedTextForRange(word_range, decorated_word)) | |
1031 return false; | |
1032 | |
1033 const std::vector<Rect> word_bounds = GetSubstringBounds(word_range); | |
karandeepb
2016/09/22 08:17:39
Had to change the approach here and use GetSubstri
| |
1034 if (word_bounds.empty()) | |
1035 return false; | |
1036 | |
1037 const Rect* left_rect = &word_bounds[0]; | |
1038 for (const Rect& rect : word_bounds) | |
1039 if (rect.x() < left_rect->x()) | |
1040 left_rect = ▭ | |
1041 | |
1042 *baseline_point = left_rect->origin() + Vector2d(0, GetDisplayTextBaseline()); | |
1043 return true; | |
1044 } | |
1045 | |
1046 base::string16 RenderText::GetTextFromRange(const Range& range) const { | |
1047 if (range.IsValid() && range.GetMin() < text().length()) | |
1048 return text().substr(range.GetMin(), range.length()); | |
1049 return base::string16(); | |
1050 } | |
1051 | |
1045 RenderText::RenderText() | 1052 RenderText::RenderText() |
1046 : horizontal_alignment_(base::i18n::IsRTL() ? ALIGN_RIGHT : ALIGN_LEFT), | 1053 : horizontal_alignment_(base::i18n::IsRTL() ? ALIGN_RIGHT : ALIGN_LEFT), |
1047 directionality_mode_(DIRECTIONALITY_FROM_TEXT), | 1054 directionality_mode_(DIRECTIONALITY_FROM_TEXT), |
1048 text_direction_(base::i18n::UNKNOWN_DIRECTION), | 1055 text_direction_(base::i18n::UNKNOWN_DIRECTION), |
1049 cursor_enabled_(true), | 1056 cursor_enabled_(true), |
1050 cursor_visible_(false), | 1057 cursor_visible_(false), |
1051 cursor_color_(kDefaultColor), | 1058 cursor_color_(kDefaultColor), |
1052 selection_color_(kDefaultColor), | 1059 selection_color_(kDefaultColor), |
1053 selection_background_focused_color_(kDefaultSelectionBackgroundColor), | 1060 selection_background_focused_color_(kDefaultSelectionBackgroundColor), |
1054 focused_(false), | 1061 focused_(false), |
(...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1620 } | 1627 } |
1621 | 1628 |
1622 SetDisplayOffset(display_offset_.x() + delta_x); | 1629 SetDisplayOffset(display_offset_.x() + delta_x); |
1623 } | 1630 } |
1624 | 1631 |
1625 void RenderText::DrawSelection(Canvas* canvas) { | 1632 void RenderText::DrawSelection(Canvas* canvas) { |
1626 for (const Rect& s : GetSubstringBounds(selection())) | 1633 for (const Rect& s : GetSubstringBounds(selection())) |
1627 canvas->FillRect(s, selection_background_focused_color_); | 1634 canvas->FillRect(s, selection_background_focused_color_); |
1628 } | 1635 } |
1629 | 1636 |
1637 size_t RenderText::GetNearestWordStartBoundary(size_t index) const { | |
1638 const size_t length = text().length(); | |
1639 if (obscured()) | |
1640 return length; | |
1641 | |
1642 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); | |
1643 const bool success = iter.Init(); | |
1644 DCHECK(success); | |
1645 if (!success) | |
1646 return length; | |
1647 | |
1648 // First search for the word start boundary in the CURSOR_BACKWARD direction, | |
1649 // then in the CURSOR_FORWARD direction. | |
1650 for (int i = std::min<int>(index, (int)length - 1); i >= 0; i--) | |
1651 if (iter.IsStartOfWord(i)) | |
1652 return i; | |
1653 | |
1654 for (size_t i = index + 1; i < length; i++) | |
1655 if (iter.IsStartOfWord(i)) | |
1656 return i; | |
1657 | |
1658 return length; | |
1659 } | |
1660 | |
1661 Range RenderText::ExpandRangeToWordBoundary(const Range& range) const { | |
1662 const size_t length = text().length(); | |
1663 DCHECK(range.GetMax() <= length); | |
1664 if (obscured()) | |
1665 return range.is_reversed() ? Range(length, 0) : Range(0, length); | |
1666 | |
1667 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); | |
1668 const bool success = iter.Init(); | |
1669 DCHECK(success); | |
1670 if (!success) | |
1671 return range; | |
1672 | |
1673 size_t range_min = range.GetMin(); | |
1674 if (range_min == length && range_min != 0) | |
1675 --range_min; | |
1676 | |
1677 for (; range_min != 0; --range_min) { | |
1678 if (iter.IsStartOfWord(range_min) || iter.IsEndOfWord(range_min)) | |
1679 break; | |
1680 } | |
1681 | |
1682 size_t range_max = range.GetMax(); | |
1683 if (range_min == range_max && range_max != length) | |
1684 ++range_max; | |
1685 | |
1686 for (; range_max < length; ++range_max) | |
1687 if (iter.IsEndOfWord(range_max) || iter.IsStartOfWord(range_max)) | |
1688 break; | |
1689 | |
1690 return range.is_reversed() ? Range(range_max, range_min) | |
1691 : Range(range_min, range_max); | |
1692 } | |
1693 | |
1630 } // namespace gfx | 1694 } // namespace gfx |
OLD | NEW |