| 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 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 416 params.subpixel_rendering != FontRenderParams::SUBPIXEL_RENDERING_NONE); | 416 params.subpixel_rendering != FontRenderParams::SUBPIXEL_RENDERING_NONE); |
| 417 paint->setSubpixelText(params.subpixel_positioning); | 417 paint->setSubpixelText(params.subpixel_positioning); |
| 418 paint->setAutohinted(params.autohinter); | 418 paint->setAutohinted(params.autohinter); |
| 419 paint->setHinting(FontRenderParamsHintingToSkPaintHinting(params.hinting)); | 419 paint->setHinting(FontRenderParamsHintingToSkPaintHinting(params.hinting)); |
| 420 } | 420 } |
| 421 | 421 |
| 422 } // namespace internal | 422 } // namespace internal |
| 423 | 423 |
| 424 // static | 424 // static |
| 425 constexpr base::char16 RenderText::kPasswordReplacementChar; | 425 constexpr base::char16 RenderText::kPasswordReplacementChar; |
| 426 constexpr bool RenderText::kDragToEndIfOutsideVerticalBounds; |
| 426 | 427 |
| 427 RenderText::~RenderText() { | 428 RenderText::~RenderText() { |
| 428 } | 429 } |
| 429 | 430 |
| 430 // static | 431 // static |
| 431 RenderText* RenderText::CreateInstance() { | 432 RenderText* RenderText::CreateInstance() { |
| 432 #if defined(OS_MACOSX) | 433 #if defined(OS_MACOSX) |
| 433 const bool use_native = !base::CommandLine::ForCurrentProcess()->HasSwitch( | 434 const bool use_native = !base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 434 switches::kEnableHarfBuzzRenderText); | 435 switches::kEnableHarfBuzzRenderText); |
| 435 if (use_native) | 436 if (use_native) |
| (...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 808 text_direction_ = base::i18n::UNKNOWN_DIRECTION; | 809 text_direction_ = base::i18n::UNKNOWN_DIRECTION; |
| 809 cached_bounds_and_offset_valid_ = false; | 810 cached_bounds_and_offset_valid_ = false; |
| 810 OnLayoutTextAttributeChanged(false); | 811 OnLayoutTextAttributeChanged(false); |
| 811 } | 812 } |
| 812 | 813 |
| 813 base::i18n::TextDirection RenderText::GetDisplayTextDirection() { | 814 base::i18n::TextDirection RenderText::GetDisplayTextDirection() { |
| 814 return GetTextDirection(GetDisplayText()); | 815 return GetTextDirection(GetDisplayText()); |
| 815 } | 816 } |
| 816 | 817 |
| 817 VisualCursorDirection RenderText::GetVisualDirectionOfLogicalEnd() { | 818 VisualCursorDirection RenderText::GetVisualDirectionOfLogicalEnd() { |
| 818 return GetDisplayTextDirection() == base::i18n::LEFT_TO_RIGHT ? | 819 return GetDisplayTextDirection() == base::i18n::LEFT_TO_RIGHT ? CURSOR_RIGHT |
| 819 CURSOR_RIGHT : CURSOR_LEFT; | 820 : CURSOR_LEFT; |
| 821 } |
| 822 |
| 823 VisualCursorDirection RenderText::GetVisualDirectionOfLogicalBeginning() { |
| 824 return GetDisplayTextDirection() == base::i18n::RIGHT_TO_LEFT ? CURSOR_RIGHT |
| 825 : CURSOR_LEFT; |
| 820 } | 826 } |
| 821 | 827 |
| 822 SizeF RenderText::GetStringSizeF() { | 828 SizeF RenderText::GetStringSizeF() { |
| 823 return SizeF(GetStringSize()); | 829 return SizeF(GetStringSize()); |
| 824 } | 830 } |
| 825 | 831 |
| 826 float RenderText::GetContentWidthF() { | 832 float RenderText::GetContentWidthF() { |
| 827 const float string_size = GetStringSizeF().width(); | 833 const float string_size = GetStringSizeF().width(); |
| 828 // The cursor is drawn one pixel beyond the int-enclosed text bounds. | 834 // The cursor is drawn one pixel beyond the int-enclosed text bounds. |
| 829 return cursor_enabled_ ? std::ceil(string_size) + 1 : string_size; | 835 return cursor_enabled_ ? std::ceil(string_size) + 1 : string_size; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 887 (index < text().length() && | 893 (index < text().length() && |
| 888 (truncate_length_ == 0 || index < truncate_length_) && | 894 (truncate_length_ == 0 || index < truncate_length_) && |
| 889 IsValidCodePointIndex(text(), index)); | 895 IsValidCodePointIndex(text(), index)); |
| 890 } | 896 } |
| 891 | 897 |
| 892 Rect RenderText::GetCursorBounds(const SelectionModel& caret, | 898 Rect RenderText::GetCursorBounds(const SelectionModel& caret, |
| 893 bool insert_mode) { | 899 bool insert_mode) { |
| 894 // TODO(ckocagil): Support multiline. This function should return the height | 900 // TODO(ckocagil): Support multiline. This function should return the height |
| 895 // of the line the cursor is on. |GetStringSize()| now returns | 901 // of the line the cursor is on. |GetStringSize()| now returns |
| 896 // the multiline size, eliminate its use here. | 902 // the multiline size, eliminate its use here. |
| 897 | 903 DCHECK(!multiline_); |
| 898 EnsureLayout(); | 904 EnsureLayout(); |
| 899 size_t caret_pos = caret.caret_pos(); | 905 size_t caret_pos = caret.caret_pos(); |
| 900 DCHECK(IsValidLogicalIndex(caret_pos)); | 906 DCHECK(IsValidLogicalIndex(caret_pos)); |
| 901 // In overtype mode, ignore the affinity and always indicate that we will | 907 // In overtype mode, ignore the affinity and always indicate that we will |
| 902 // overtype the next character. | 908 // overtype the next character. |
| 903 LogicalCursorDirection caret_affinity = | 909 LogicalCursorDirection caret_affinity = |
| 904 insert_mode ? caret.caret_affinity() : CURSOR_FORWARD; | 910 insert_mode ? caret.caret_affinity() : CURSOR_FORWARD; |
| 905 int x = 0, width = 1; | 911 int x = 0, width = 1; |
| 906 Size size = GetStringSize(); | 912 Size size = GetStringSize(); |
| 907 if (caret_pos == (caret_affinity == CURSOR_BACKWARD ? 0 : text().length())) { | 913 if (caret_pos == (caret_affinity == CURSOR_BACKWARD ? 0 : text().length())) { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 955 } | 961 } |
| 956 | 962 |
| 957 SelectionModel RenderText::GetSelectionModelForSelectionStart() const { | 963 SelectionModel RenderText::GetSelectionModelForSelectionStart() const { |
| 958 const Range& sel = selection(); | 964 const Range& sel = selection(); |
| 959 if (sel.is_empty()) | 965 if (sel.is_empty()) |
| 960 return selection_model_; | 966 return selection_model_; |
| 961 return SelectionModel(sel.start(), | 967 return SelectionModel(sel.start(), |
| 962 sel.is_reversed() ? CURSOR_BACKWARD : CURSOR_FORWARD); | 968 sel.is_reversed() ? CURSOR_BACKWARD : CURSOR_FORWARD); |
| 963 } | 969 } |
| 964 | 970 |
| 971 std::vector<Rect> RenderText::GetSubstringBoundsForTesting( |
| 972 const gfx::Range& range) { |
| 973 return GetSubstringBounds(range); |
| 974 } |
| 975 |
| 965 const Vector2d& RenderText::GetUpdatedDisplayOffset() { | 976 const Vector2d& RenderText::GetUpdatedDisplayOffset() { |
| 966 UpdateCachedBoundsAndOffset(); | 977 UpdateCachedBoundsAndOffset(); |
| 967 return display_offset_; | 978 return display_offset_; |
| 968 } | 979 } |
| 969 | 980 |
| 970 void RenderText::SetDisplayOffset(int horizontal_offset) { | 981 void RenderText::SetDisplayOffset(int horizontal_offset) { |
| 971 const int extra_content = GetContentWidth() - display_rect_.width(); | 982 const int extra_content = GetContentWidth() - display_rect_.width(); |
| 972 const int cursor_width = cursor_enabled_ ? 1 : 0; | 983 const int cursor_width = cursor_enabled_ ? 1 : 0; |
| 973 | 984 |
| 974 int min_offset = 0; | 985 int min_offset = 0; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 997 horizontal_offset = min_offset; | 1008 horizontal_offset = min_offset; |
| 998 else if (horizontal_offset > max_offset) | 1009 else if (horizontal_offset > max_offset) |
| 999 horizontal_offset = max_offset; | 1010 horizontal_offset = max_offset; |
| 1000 | 1011 |
| 1001 cached_bounds_and_offset_valid_ = true; | 1012 cached_bounds_and_offset_valid_ = true; |
| 1002 display_offset_.set_x(horizontal_offset); | 1013 display_offset_.set_x(horizontal_offset); |
| 1003 cursor_bounds_ = GetCursorBounds(selection_model_, true); | 1014 cursor_bounds_ = GetCursorBounds(selection_model_, true); |
| 1004 } | 1015 } |
| 1005 | 1016 |
| 1006 Vector2d RenderText::GetLineOffset(size_t line_number) { | 1017 Vector2d RenderText::GetLineOffset(size_t line_number) { |
| 1018 EnsureLayout(); |
| 1007 Vector2d offset = display_rect().OffsetFromOrigin(); | 1019 Vector2d offset = display_rect().OffsetFromOrigin(); |
| 1008 // TODO(ckocagil): Apply the display offset for multiline scrolling. | 1020 // TODO(ckocagil): Apply the display offset for multiline scrolling. |
| 1009 if (!multiline()) | 1021 if (!multiline()) { |
| 1010 offset.Add(GetUpdatedDisplayOffset()); | 1022 offset.Add(GetUpdatedDisplayOffset()); |
| 1011 else | 1023 } else { |
| 1024 DCHECK_LT(line_number, lines().size()); |
| 1012 offset.Add(Vector2d(0, lines_[line_number].preceding_heights)); | 1025 offset.Add(Vector2d(0, lines_[line_number].preceding_heights)); |
| 1026 } |
| 1013 offset.Add(GetAlignmentOffset(line_number)); | 1027 offset.Add(GetAlignmentOffset(line_number)); |
| 1014 return offset; | 1028 return offset; |
| 1015 } | 1029 } |
| 1016 | 1030 |
| 1017 bool RenderText::GetDecoratedWordAtPoint(const Point& point, | 1031 bool RenderText::GetDecoratedWordAtPoint(const Point& point, |
| 1018 DecoratedText* decorated_word, | 1032 DecoratedText* decorated_word, |
| 1019 Point* baseline_point) { | 1033 Point* baseline_point) { |
| 1020 // FindCursorPosition doesn't currently support multiline. See | 1034 // FindCursorPosition doesn't currently support multiline. See |
| 1021 // http://crbug.com/650120. | 1035 // http://crbug.com/650120. |
| 1022 if (multiline() || obscured()) | 1036 if (multiline() || obscured()) |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1098 return AdjacentWordSelectionModel(current, direction); | 1112 return AdjacentWordSelectionModel(current, direction); |
| 1099 } | 1113 } |
| 1100 | 1114 |
| 1101 SelectionModel RenderText::EdgeSelectionModel( | 1115 SelectionModel RenderText::EdgeSelectionModel( |
| 1102 VisualCursorDirection direction) { | 1116 VisualCursorDirection direction) { |
| 1103 if (direction == GetVisualDirectionOfLogicalEnd()) | 1117 if (direction == GetVisualDirectionOfLogicalEnd()) |
| 1104 return SelectionModel(text().length(), CURSOR_FORWARD); | 1118 return SelectionModel(text().length(), CURSOR_FORWARD); |
| 1105 return SelectionModel(0, CURSOR_BACKWARD); | 1119 return SelectionModel(0, CURSOR_BACKWARD); |
| 1106 } | 1120 } |
| 1107 | 1121 |
| 1122 SelectionModel RenderText::LineSelectionModel(size_t line_index, |
| 1123 VisualCursorDirection direction) { |
| 1124 const internal::Line& line = lines()[line_index]; |
| 1125 if (line.segments.empty()) { |
| 1126 // Only the last line can be empty. |
| 1127 DCHECK_EQ(lines().size() - 1, line_index); |
| 1128 return EdgeSelectionModel(GetVisualDirectionOfLogicalEnd()); |
| 1129 } |
| 1130 |
| 1131 size_t max_index = 0; |
| 1132 size_t min_index = text().length(); |
| 1133 for (const auto& segment : line.segments) { |
| 1134 min_index = std::min<size_t>(min_index, segment.char_range.GetMin()); |
| 1135 max_index = std::max<size_t>(max_index, segment.char_range.GetMax()); |
| 1136 } |
| 1137 |
| 1138 return direction == GetVisualDirectionOfLogicalEnd() |
| 1139 ? SelectionModel(DisplayIndexToTextIndex(max_index), |
| 1140 CURSOR_FORWARD) |
| 1141 : SelectionModel(DisplayIndexToTextIndex(min_index), |
| 1142 CURSOR_BACKWARD); |
| 1143 } |
| 1144 |
| 1108 void RenderText::SetSelectionModel(const SelectionModel& model) { | 1145 void RenderText::SetSelectionModel(const SelectionModel& model) { |
| 1109 DCHECK_LE(model.selection().GetMax(), text().length()); | 1146 DCHECK_LE(model.selection().GetMax(), text().length()); |
| 1110 selection_model_ = model; | 1147 selection_model_ = model; |
| 1111 cached_bounds_and_offset_valid_ = false; | 1148 cached_bounds_and_offset_valid_ = false; |
| 1112 } | 1149 } |
| 1113 | 1150 |
| 1114 void RenderText::OnTextColorChanged() { | 1151 void RenderText::OnTextColorChanged() { |
| 1115 } | 1152 } |
| 1116 | 1153 |
| 1117 void RenderText::UpdateDisplayText(float text_width) { | 1154 void RenderText::UpdateDisplayText(float text_width) { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1206 } | 1243 } |
| 1207 | 1244 |
| 1208 void RenderText::UndoCompositionAndSelectionStyles() { | 1245 void RenderText::UndoCompositionAndSelectionStyles() { |
| 1209 // Restore the underline and color breaks to undo the temporary styles. | 1246 // Restore the underline and color breaks to undo the temporary styles. |
| 1210 DCHECK(composition_and_selection_styles_applied_); | 1247 DCHECK(composition_and_selection_styles_applied_); |
| 1211 colors_ = saved_colors_; | 1248 colors_ = saved_colors_; |
| 1212 styles_[UNDERLINE] = saved_underlines_; | 1249 styles_[UNDERLINE] = saved_underlines_; |
| 1213 composition_and_selection_styles_applied_ = false; | 1250 composition_and_selection_styles_applied_ = false; |
| 1214 } | 1251 } |
| 1215 | 1252 |
| 1216 Point RenderText::ToTextPoint(const Point& point) { | |
| 1217 return point - GetLineOffset(0); | |
| 1218 // TODO(ckocagil): Convert multiline view space points to text space. | |
| 1219 } | |
| 1220 | |
| 1221 Point RenderText::ToViewPoint(const Point& point) { | 1253 Point RenderText::ToViewPoint(const Point& point) { |
| 1222 if (!multiline()) | 1254 if (!multiline()) |
| 1223 return point + GetLineOffset(0); | 1255 return point + GetLineOffset(0); |
| 1224 | 1256 |
| 1225 // TODO(ckocagil): Traverse individual line segments for RTL support. | 1257 // TODO(ckocagil): Traverse individual line segments for RTL support. |
| 1226 DCHECK(!lines_.empty()); | 1258 DCHECK(!lines_.empty()); |
| 1227 int x = point.x(); | 1259 int x = point.x(); |
| 1228 size_t line = 0; | 1260 size_t line = 0; |
| 1229 for (; line < lines_.size() && x > lines_[line].size.width(); ++line) | 1261 for (; line < lines_.size() && x > lines_[line].size.width(); ++line) |
| 1230 x -= lines_[line].size.width(); | 1262 x -= lines_[line].size.width(); |
| 1263 |
| 1264 // If |point| is outside the text space, clip it to the end of the last line. |
| 1265 if (line == lines_.size()) |
| 1266 x = lines_[--line].size.width(); |
| 1231 return Point(x, point.y()) + GetLineOffset(line); | 1267 return Point(x, point.y()) + GetLineOffset(line); |
| 1232 } | 1268 } |
| 1233 | 1269 |
| 1234 std::vector<Rect> RenderText::TextBoundsToViewBounds(const Range& x) { | |
| 1235 std::vector<Rect> rects; | |
| 1236 | |
| 1237 if (!multiline()) { | |
| 1238 rects.push_back(Rect(ToViewPoint(Point(x.GetMin(), 0)), | |
| 1239 Size(x.length(), GetStringSize().height()))); | |
| 1240 return rects; | |
| 1241 } | |
| 1242 | |
| 1243 EnsureLayout(); | |
| 1244 | |
| 1245 // Each line segment keeps its position in text coordinates. Traverse all line | |
| 1246 // segments and if the segment intersects with the given range, add the view | |
| 1247 // rect corresponding to the intersection to |rects|. | |
| 1248 for (size_t line = 0; line < lines_.size(); ++line) { | |
| 1249 int line_x = 0; | |
| 1250 const Vector2d offset = GetLineOffset(line); | |
| 1251 for (size_t i = 0; i < lines_[line].segments.size(); ++i) { | |
| 1252 const internal::LineSegment* segment = &lines_[line].segments[i]; | |
| 1253 const Range intersection = segment->x_range.Intersect(x).Ceil(); | |
| 1254 if (!intersection.is_empty()) { | |
| 1255 Rect rect(line_x + intersection.start() - segment->x_range.start(), | |
| 1256 0, intersection.length(), lines_[line].size.height()); | |
| 1257 rects.push_back(rect + offset); | |
| 1258 } | |
| 1259 line_x += segment->x_range.length(); | |
| 1260 } | |
| 1261 } | |
| 1262 | |
| 1263 return rects; | |
| 1264 } | |
| 1265 | |
| 1266 HorizontalAlignment RenderText::GetCurrentHorizontalAlignment() { | 1270 HorizontalAlignment RenderText::GetCurrentHorizontalAlignment() { |
| 1267 if (horizontal_alignment_ != ALIGN_TO_HEAD) | 1271 if (horizontal_alignment_ != ALIGN_TO_HEAD) |
| 1268 return horizontal_alignment_; | 1272 return horizontal_alignment_; |
| 1269 return GetDisplayTextDirection() == base::i18n::RIGHT_TO_LEFT ? | 1273 return GetDisplayTextDirection() == base::i18n::RIGHT_TO_LEFT ? |
| 1270 ALIGN_RIGHT : ALIGN_LEFT; | 1274 ALIGN_RIGHT : ALIGN_LEFT; |
| 1271 } | 1275 } |
| 1272 | 1276 |
| 1273 Vector2d RenderText::GetAlignmentOffset(size_t line_number) { | 1277 Vector2d RenderText::GetAlignmentOffset(size_t line_number) { |
| 1274 // TODO(ckocagil): Enable |lines_| usage on RenderTextMac. | 1278 // TODO(ckocagil): Enable |lines_| usage on RenderTextMac. |
| 1275 if (MultilineSupported() && multiline_) | 1279 if (MultilineSupported() && multiline_) |
| (...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1688 | 1692 |
| 1689 for (; range_max < length; ++range_max) | 1693 for (; range_max < length; ++range_max) |
| 1690 if (iter.IsEndOfWord(range_max) || iter.IsStartOfWord(range_max)) | 1694 if (iter.IsEndOfWord(range_max) || iter.IsStartOfWord(range_max)) |
| 1691 break; | 1695 break; |
| 1692 | 1696 |
| 1693 return range.is_reversed() ? Range(range_max, range_min) | 1697 return range.is_reversed() ? Range(range_max, range_min) |
| 1694 : Range(range_min, range_max); | 1698 : Range(range_min, range_max); |
| 1695 } | 1699 } |
| 1696 | 1700 |
| 1697 } // namespace gfx | 1701 } // namespace gfx |
| OLD | NEW |