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 <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/i18n/break_iterator.h" | 9 #include "base/i18n/break_iterator.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 12 #include "third_party/icu/public/common/unicode/rbbi.h" |
12 #include "third_party/icu/public/common/unicode/utf16.h" | 13 #include "third_party/icu/public/common/unicode/utf16.h" |
13 #include "third_party/skia/include/core/SkTypeface.h" | 14 #include "third_party/skia/include/core/SkTypeface.h" |
14 #include "third_party/skia/include/effects/SkGradientShader.h" | 15 #include "third_party/skia/include/effects/SkGradientShader.h" |
| 16 #include "ui/base/text/text_elider.h" |
15 #include "ui/base/text/utf16_indexing.h" | 17 #include "ui/base/text/utf16_indexing.h" |
16 #include "ui/gfx/canvas.h" | 18 #include "ui/gfx/canvas.h" |
17 #include "ui/gfx/insets.h" | 19 #include "ui/gfx/insets.h" |
18 #include "ui/gfx/skia_util.h" | 20 #include "ui/gfx/skia_util.h" |
19 #include "ui/gfx/text_constants.h" | 21 #include "ui/gfx/text_constants.h" |
20 | 22 |
21 namespace gfx { | 23 namespace gfx { |
22 | 24 |
23 namespace { | 25 namespace { |
24 | 26 |
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
317 | 319 |
318 // Reset selection model. SetText should always followed by SetSelectionModel | 320 // Reset selection model. SetText should always followed by SetSelectionModel |
319 // or SetCursorPosition in upper layer. | 321 // or SetCursorPosition in upper layer. |
320 SetSelectionModel(SelectionModel()); | 322 SetSelectionModel(SelectionModel()); |
321 | 323 |
322 // Invalidate the cached text direction if it depends on the text contents. | 324 // Invalidate the cached text direction if it depends on the text contents. |
323 if (directionality_mode_ == DIRECTIONALITY_FROM_TEXT) | 325 if (directionality_mode_ == DIRECTIONALITY_FROM_TEXT) |
324 text_direction_ = base::i18n::UNKNOWN_DIRECTION; | 326 text_direction_ = base::i18n::UNKNOWN_DIRECTION; |
325 | 327 |
326 obscured_reveal_index_ = -1; | 328 obscured_reveal_index_ = -1; |
327 UpdateObscuredText(); | 329 UpdateLayoutText(); |
328 ResetLayout(); | 330 ResetLayout(); |
329 } | 331 } |
330 | 332 |
331 void RenderText::SetHorizontalAlignment(HorizontalAlignment alignment) { | 333 void RenderText::SetHorizontalAlignment(HorizontalAlignment alignment) { |
332 if (horizontal_alignment_ != alignment) { | 334 if (horizontal_alignment_ != alignment) { |
333 horizontal_alignment_ = alignment; | 335 horizontal_alignment_ = alignment; |
334 display_offset_ = Vector2d(); | 336 display_offset_ = Vector2d(); |
335 cached_bounds_and_offset_valid_ = false; | 337 cached_bounds_and_offset_valid_ = false; |
336 } | 338 } |
337 } | 339 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
372 void RenderText::ToggleInsertMode() { | 374 void RenderText::ToggleInsertMode() { |
373 insert_mode_ = !insert_mode_; | 375 insert_mode_ = !insert_mode_; |
374 cached_bounds_and_offset_valid_ = false; | 376 cached_bounds_and_offset_valid_ = false; |
375 } | 377 } |
376 | 378 |
377 void RenderText::SetObscured(bool obscured) { | 379 void RenderText::SetObscured(bool obscured) { |
378 if (obscured != obscured_) { | 380 if (obscured != obscured_) { |
379 obscured_ = obscured; | 381 obscured_ = obscured; |
380 obscured_reveal_index_ = -1; | 382 obscured_reveal_index_ = -1; |
381 cached_bounds_and_offset_valid_ = false; | 383 cached_bounds_and_offset_valid_ = false; |
382 UpdateObscuredText(); | 384 UpdateLayoutText(); |
383 ResetLayout(); | 385 ResetLayout(); |
384 } | 386 } |
385 } | 387 } |
386 | 388 |
387 void RenderText::SetObscuredRevealIndex(int index) { | 389 void RenderText::SetObscuredRevealIndex(int index) { |
388 if (obscured_reveal_index_ == index) | 390 if (obscured_reveal_index_ == index) |
389 return; | 391 return; |
390 | 392 |
391 obscured_reveal_index_ = index; | 393 obscured_reveal_index_ = index; |
392 cached_bounds_and_offset_valid_ = false; | 394 cached_bounds_and_offset_valid_ = false; |
393 UpdateObscuredText(); | 395 UpdateLayoutText(); |
394 ResetLayout(); | 396 ResetLayout(); |
395 } | 397 } |
396 | 398 |
397 void RenderText::SetDisplayRect(const Rect& r) { | 399 void RenderText::SetDisplayRect(const Rect& r) { |
398 display_rect_ = r; | 400 display_rect_ = r; |
399 cached_bounds_and_offset_valid_ = false; | 401 cached_bounds_and_offset_valid_ = false; |
400 } | 402 } |
401 | 403 |
402 void RenderText::SetCursorPosition(size_t position) { | 404 void RenderText::SetCursorPosition(size_t position) { |
403 MoveCursorTo(position, false); | 405 MoveCursorTo(position, false); |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
702 } | 704 } |
703 return Rect(ToViewPoint(Point(x, 0)), Size(width, size.height())); | 705 return Rect(ToViewPoint(Point(x, 0)), Size(width, size.height())); |
704 } | 706 } |
705 | 707 |
706 const Rect& RenderText::GetUpdatedCursorBounds() { | 708 const Rect& RenderText::GetUpdatedCursorBounds() { |
707 UpdateCachedBoundsAndOffset(); | 709 UpdateCachedBoundsAndOffset(); |
708 return cursor_bounds_; | 710 return cursor_bounds_; |
709 } | 711 } |
710 | 712 |
711 size_t RenderText::IndexOfAdjacentGrapheme(size_t index, | 713 size_t RenderText::IndexOfAdjacentGrapheme(size_t index, |
712 LogicalCursorDirection direction) { | 714 LogicalCursorDirection direction) { |
713 if (index > text().length()) | 715 if (index > text().length()) |
714 return text().length(); | 716 return text().length(); |
715 | 717 |
716 EnsureLayout(); | 718 EnsureLayout(); |
717 | 719 |
718 if (direction == CURSOR_FORWARD) { | 720 if (direction == CURSOR_FORWARD) { |
719 while (index < text().length()) { | 721 while (index < text().length()) { |
720 index++; | 722 index++; |
721 if (IsCursorablePosition(index)) | 723 if (IsCursorablePosition(index)) |
722 return index; | 724 return index; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
756 selection_color_(kDefaultColor), | 758 selection_color_(kDefaultColor), |
757 selection_background_focused_color_(kDefaultSelectionBackgroundColor), | 759 selection_background_focused_color_(kDefaultSelectionBackgroundColor), |
758 selection_background_unfocused_color_(kDefaultSelectionBackgroundColor), | 760 selection_background_unfocused_color_(kDefaultSelectionBackgroundColor), |
759 focused_(false), | 761 focused_(false), |
760 composition_range_(ui::Range::InvalidRange()), | 762 composition_range_(ui::Range::InvalidRange()), |
761 colors_(kDefaultColor), | 763 colors_(kDefaultColor), |
762 styles_(NUM_TEXT_STYLES), | 764 styles_(NUM_TEXT_STYLES), |
763 composition_and_selection_styles_applied_(false), | 765 composition_and_selection_styles_applied_(false), |
764 obscured_(false), | 766 obscured_(false), |
765 obscured_reveal_index_(-1), | 767 obscured_reveal_index_(-1), |
| 768 truncate_length_(0), |
766 fade_head_(false), | 769 fade_head_(false), |
767 fade_tail_(false), | 770 fade_tail_(false), |
768 background_is_transparent_(false), | 771 background_is_transparent_(false), |
769 clip_to_display_rect_(true), | 772 clip_to_display_rect_(true), |
770 cached_bounds_and_offset_valid_(false) { | 773 cached_bounds_and_offset_valid_(false) { |
771 } | 774 } |
772 | 775 |
773 const Vector2d& RenderText::GetUpdatedDisplayOffset() { | 776 const Vector2d& RenderText::GetUpdatedDisplayOffset() { |
774 UpdateCachedBoundsAndOffset(); | 777 UpdateCachedBoundsAndOffset(); |
775 return display_offset_; | 778 return display_offset_; |
(...skipping 20 matching lines...) Expand all Loading... |
796 return SelectionModel(0, CURSOR_BACKWARD); | 799 return SelectionModel(0, CURSOR_BACKWARD); |
797 } | 800 } |
798 | 801 |
799 void RenderText::SetSelectionModel(const SelectionModel& model) { | 802 void RenderText::SetSelectionModel(const SelectionModel& model) { |
800 DCHECK_LE(model.selection().GetMax(), text().length()); | 803 DCHECK_LE(model.selection().GetMax(), text().length()); |
801 selection_model_ = model; | 804 selection_model_ = model; |
802 cached_bounds_and_offset_valid_ = false; | 805 cached_bounds_and_offset_valid_ = false; |
803 } | 806 } |
804 | 807 |
805 const base::string16& RenderText::GetLayoutText() const { | 808 const base::string16& RenderText::GetLayoutText() const { |
806 return obscured() ? obscured_text_ : text(); | 809 return layout_text_.empty() ? text_ : layout_text_; |
807 } | 810 } |
808 | 811 |
809 void RenderText::ApplyCompositionAndSelectionStyles() { | 812 void RenderText::ApplyCompositionAndSelectionStyles() { |
810 // Save the underline and color breaks to undo the temporary styles later. | 813 // Save the underline and color breaks to undo the temporary styles later. |
811 DCHECK(!composition_and_selection_styles_applied_); | 814 DCHECK(!composition_and_selection_styles_applied_); |
812 saved_colors_ = colors_; | 815 saved_colors_ = colors_; |
813 saved_underlines_ = styles_[UNDERLINE]; | 816 saved_underlines_ = styles_[UNDERLINE]; |
814 | 817 |
815 // Apply an underline to the composition range in |underlines|. | 818 // Apply an underline to the composition range in |underlines|. |
816 if (composition_range_.IsValid() && !composition_range_.is_empty()) | 819 if (composition_range_.IsValid() && !composition_range_.is_empty()) |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
926 } | 929 } |
927 | 930 |
928 void RenderText::MoveCursorTo(size_t position, bool select) { | 931 void RenderText::MoveCursorTo(size_t position, bool select) { |
929 size_t cursor = std::min(position, text().length()); | 932 size_t cursor = std::min(position, text().length()); |
930 if (IsCursorablePosition(cursor)) | 933 if (IsCursorablePosition(cursor)) |
931 SetSelectionModel(SelectionModel( | 934 SetSelectionModel(SelectionModel( |
932 ui::Range(select ? selection().start() : cursor, cursor), | 935 ui::Range(select ? selection().start() : cursor, cursor), |
933 (cursor == 0) ? CURSOR_FORWARD : CURSOR_BACKWARD)); | 936 (cursor == 0) ? CURSOR_FORWARD : CURSOR_BACKWARD)); |
934 } | 937 } |
935 | 938 |
936 void RenderText::UpdateObscuredText() { | 939 void RenderText::UpdateLayoutText() { |
937 if (!obscured_) | 940 layout_text_.clear(); |
938 return; | |
939 | 941 |
940 const size_t obscured_text_length = | 942 if (obscured_) { |
941 static_cast<size_t>(ui::UTF16IndexToOffset(text_, 0, text_.length())); | 943 size_t obscured_text_length = |
942 obscured_text_.assign(obscured_text_length, kPasswordReplacementChar); | 944 static_cast<size_t>(ui::UTF16IndexToOffset(text_, 0, text_.length())); |
| 945 layout_text_.assign(obscured_text_length, kPasswordReplacementChar); |
943 | 946 |
944 if (obscured_reveal_index_ >= 0 && | 947 if (obscured_reveal_index_ >= 0 && |
945 obscured_reveal_index_ < static_cast<int>(text_.length())) { | 948 obscured_reveal_index_ < static_cast<int>(text_.length())) { |
946 // Gets the index range in |text_| to be revealed. | 949 // Gets the index range in |text_| to be revealed. |
947 size_t start = obscured_reveal_index_; | 950 size_t start = obscured_reveal_index_; |
948 U16_SET_CP_START(text_.data(), 0, start); | 951 U16_SET_CP_START(text_.data(), 0, start); |
949 size_t end = start; | 952 size_t end = start; |
950 UChar32 unused_char; | 953 UChar32 unused_char; |
951 U16_NEXT(text_.data(), end, text_.length(), unused_char); | 954 U16_NEXT(text_.data(), end, text_.length(), unused_char); |
952 | 955 |
953 // Gets the index in |obscured_text_| to be replaced. | 956 // Gets the index in |layout_text_| to be replaced. |
954 const size_t cp_start = | 957 const size_t cp_start = |
955 static_cast<size_t>(ui::UTF16IndexToOffset(text_, 0, start)); | 958 static_cast<size_t>(ui::UTF16IndexToOffset(text_, 0, start)); |
956 obscured_text_.replace(cp_start, 1, text_.substr(start, end - start)); | 959 if (layout_text_.length() > cp_start) |
| 960 layout_text_.replace(cp_start, 1, text_.substr(start, end - start)); |
| 961 } |
| 962 } |
| 963 |
| 964 const base::string16& text = obscured_ ? layout_text_ : text_; |
| 965 if (truncate_length_ > 0 && truncate_length_ < text.length()) { |
| 966 // Truncate the text at a valid character break and append an ellipsis. |
| 967 icu::StringCharacterIterator iter(text.c_str()); |
| 968 iter.setIndex32(truncate_length_ - 1); |
| 969 layout_text_.assign(text.substr(0, iter.getIndex()) + ui::kEllipsisUTF16); |
957 } | 970 } |
958 } | 971 } |
959 | 972 |
960 void RenderText::UpdateCachedBoundsAndOffset() { | 973 void RenderText::UpdateCachedBoundsAndOffset() { |
961 if (cached_bounds_and_offset_valid_) | 974 if (cached_bounds_and_offset_valid_) |
962 return; | 975 return; |
963 | 976 |
964 // First, set the valid flag true to calculate the current cursor bounds using | 977 // First, set the valid flag true to calculate the current cursor bounds using |
965 // the stale |display_offset_|. Applying |delta_offset| at the end of this | 978 // the stale |display_offset_|. Applying |delta_offset| at the end of this |
966 // function will set |cursor_bounds_| and |display_offset_| to correct values. | 979 // function will set |cursor_bounds_| and |display_offset_| to correct values. |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1007 void RenderText::DrawSelection(Canvas* canvas) { | 1020 void RenderText::DrawSelection(Canvas* canvas) { |
1008 const SkColor color = focused() ? | 1021 const SkColor color = focused() ? |
1009 selection_background_focused_color_ : | 1022 selection_background_focused_color_ : |
1010 selection_background_unfocused_color_; | 1023 selection_background_unfocused_color_; |
1011 const std::vector<Rect> sel = GetSubstringBounds(selection()); | 1024 const std::vector<Rect> sel = GetSubstringBounds(selection()); |
1012 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i) | 1025 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i) |
1013 canvas->FillRect(*i, color); | 1026 canvas->FillRect(*i, color); |
1014 } | 1027 } |
1015 | 1028 |
1016 } // namespace gfx | 1029 } // namespace gfx |
OLD | NEW |