| 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. See |
| 1017 // http://crbug.com/650120. |
| 1018 if (multiline() || obscured()) |
| 1019 return false; |
| 1020 |
| 1021 // Note: FindCursorPosition will trigger a layout via EnsureLayout. |
| 1022 const SelectionModel model_at_point = FindCursorPosition(point); |
| 1023 const size_t word_index = |
| 1024 GetNearestWordStartBoundary(model_at_point.caret_pos()); |
| 1025 if (word_index >= text().length()) |
| 1026 return false; |
| 1027 |
| 1028 const Range word_range = ExpandRangeToWordBoundary(Range(word_index)); |
| 1029 DCHECK(!word_range.is_reversed()); |
| 1030 DCHECK(!word_range.is_empty()); |
| 1031 |
| 1032 const std::vector<Rect> word_bounds = GetSubstringBounds(word_range); |
| 1033 if (word_bounds.empty()) |
| 1034 return false; |
| 1035 |
| 1036 if (!GetDecoratedTextForRange(word_range, decorated_word)) |
| 1037 return false; |
| 1038 |
| 1039 // Retrieve the baseline origin of the left-most glyph. |
| 1040 const Rect* left_rect = &word_bounds[0]; |
| 1041 for (const Rect& rect : word_bounds) |
| 1042 if (rect.x() < left_rect->x()) |
| 1043 left_rect = ▭ |
| 1044 |
| 1045 *baseline_point = left_rect->origin() + Vector2d(0, GetDisplayTextBaseline()); |
| 1046 return true; |
| 1047 } |
| 1048 |
| 1049 base::string16 RenderText::GetTextFromRange(const Range& range) const { |
| 1050 if (range.IsValid() && range.GetMin() < text().length()) |
| 1051 return text().substr(range.GetMin(), range.length()); |
| 1052 return base::string16(); |
| 1053 } |
| 1054 |
| 1045 RenderText::RenderText() | 1055 RenderText::RenderText() |
| 1046 : horizontal_alignment_(base::i18n::IsRTL() ? ALIGN_RIGHT : ALIGN_LEFT), | 1056 : horizontal_alignment_(base::i18n::IsRTL() ? ALIGN_RIGHT : ALIGN_LEFT), |
| 1047 directionality_mode_(DIRECTIONALITY_FROM_TEXT), | 1057 directionality_mode_(DIRECTIONALITY_FROM_TEXT), |
| 1048 text_direction_(base::i18n::UNKNOWN_DIRECTION), | 1058 text_direction_(base::i18n::UNKNOWN_DIRECTION), |
| 1049 cursor_enabled_(true), | 1059 cursor_enabled_(true), |
| 1050 cursor_visible_(false), | 1060 cursor_visible_(false), |
| 1051 cursor_color_(kDefaultColor), | 1061 cursor_color_(kDefaultColor), |
| 1052 selection_color_(kDefaultColor), | 1062 selection_color_(kDefaultColor), |
| 1053 selection_background_focused_color_(kDefaultSelectionBackgroundColor), | 1063 selection_background_focused_color_(kDefaultSelectionBackgroundColor), |
| 1054 focused_(false), | 1064 focused_(false), |
| (...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1620 } | 1630 } |
| 1621 | 1631 |
| 1622 SetDisplayOffset(display_offset_.x() + delta_x); | 1632 SetDisplayOffset(display_offset_.x() + delta_x); |
| 1623 } | 1633 } |
| 1624 | 1634 |
| 1625 void RenderText::DrawSelection(Canvas* canvas) { | 1635 void RenderText::DrawSelection(Canvas* canvas) { |
| 1626 for (const Rect& s : GetSubstringBounds(selection())) | 1636 for (const Rect& s : GetSubstringBounds(selection())) |
| 1627 canvas->FillRect(s, selection_background_focused_color_); | 1637 canvas->FillRect(s, selection_background_focused_color_); |
| 1628 } | 1638 } |
| 1629 | 1639 |
| 1640 size_t RenderText::GetNearestWordStartBoundary(size_t index) const { |
| 1641 const size_t length = text().length(); |
| 1642 if (obscured()) |
| 1643 return length; |
| 1644 |
| 1645 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); |
| 1646 const bool success = iter.Init(); |
| 1647 DCHECK(success); |
| 1648 if (!success) |
| 1649 return length; |
| 1650 |
| 1651 // First search for the word start boundary in the CURSOR_BACKWARD direction, |
| 1652 // then in the CURSOR_FORWARD direction. |
| 1653 for (int i = std::min<int>(index, (int)length - 1); i >= 0; i--) |
| 1654 if (iter.IsStartOfWord(i)) |
| 1655 return i; |
| 1656 |
| 1657 for (size_t i = index + 1; i < length; i++) |
| 1658 if (iter.IsStartOfWord(i)) |
| 1659 return i; |
| 1660 |
| 1661 return length; |
| 1662 } |
| 1663 |
| 1664 Range RenderText::ExpandRangeToWordBoundary(const Range& range) const { |
| 1665 const size_t length = text().length(); |
| 1666 DCHECK(range.GetMax() <= length); |
| 1667 if (obscured()) |
| 1668 return range.is_reversed() ? Range(length, 0) : Range(0, length); |
| 1669 |
| 1670 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); |
| 1671 const bool success = iter.Init(); |
| 1672 DCHECK(success); |
| 1673 if (!success) |
| 1674 return range; |
| 1675 |
| 1676 size_t range_min = range.GetMin(); |
| 1677 if (range_min == length && range_min != 0) |
| 1678 --range_min; |
| 1679 |
| 1680 for (; range_min != 0; --range_min) { |
| 1681 if (iter.IsStartOfWord(range_min) || iter.IsEndOfWord(range_min)) |
| 1682 break; |
| 1683 } |
| 1684 |
| 1685 size_t range_max = range.GetMax(); |
| 1686 if (range_min == range_max && range_max != length) |
| 1687 ++range_max; |
| 1688 |
| 1689 for (; range_max < length; ++range_max) |
| 1690 if (iter.IsEndOfWord(range_max) || iter.IsStartOfWord(range_max)) |
| 1691 break; |
| 1692 |
| 1693 return range.is_reversed() ? Range(range_max, range_min) |
| 1694 : Range(range_min, range_max); |
| 1695 } |
| 1696 |
| 1630 } // namespace gfx | 1697 } // namespace gfx |
| OLD | NEW |