| 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 |