Chromium Code Reviews| 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" |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 299 style_[i] = styles_[i].GetBreak(position); | 299 style_[i] = styles_[i].GetBreak(position); |
| 300 } | 300 } |
| 301 | 301 |
| 302 } // namespace internal | 302 } // namespace internal |
| 303 | 303 |
| 304 RenderText::~RenderText() { | 304 RenderText::~RenderText() { |
| 305 } | 305 } |
| 306 | 306 |
| 307 void RenderText::SetText(const base::string16& text) { | 307 void RenderText::SetText(const base::string16& text) { |
| 308 DCHECK(!composition_range_.IsValid()); | 308 DCHECK(!composition_range_.IsValid()); |
| 309 if (text_ == text) | |
| 310 return; | |
| 309 text_ = text; | 311 text_ = text; |
| 310 | 312 |
| 313 // TODO: we might be displaying obscured_text... also move somewhere better. | |
|
Alexei Svitkine (slow)
2013/07/09 15:35:13
I think this should be done at the end of UpdateLa
ckocagil
2013/07/13 16:05:10
Done.
| |
| 314 line_breaks_.clear(); | |
| 315 base::i18n::BreakIterator iter(text_, base::i18n::BreakIterator::BREAK_LINE); | |
| 316 bool success = iter.Init(); | |
| 317 CHECK(success); | |
| 318 do { | |
| 319 line_breaks_.push_back(iter.pos()); | |
| 320 } while (iter.Advance()); | |
| 321 | |
| 311 // Adjust ranged styles and colors to accommodate a new text length. | 322 // Adjust ranged styles and colors to accommodate a new text length. |
| 312 const size_t text_length = text_.length(); | 323 const size_t text_length = text_.length(); |
| 313 colors_.SetMax(text_length); | 324 colors_.SetMax(text_length); |
| 314 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) | 325 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) |
| 315 styles_[style].SetMax(text_length); | 326 styles_[style].SetMax(text_length); |
| 316 cached_bounds_and_offset_valid_ = false; | 327 cached_bounds_and_offset_valid_ = false; |
| 317 | 328 |
| 318 // Reset selection model. SetText should always followed by SetSelectionModel | 329 // Reset selection model. SetText should always followed by SetSelectionModel |
| 319 // or SetCursorPosition in upper layer. | 330 // or SetCursorPosition in upper layer. |
| 320 SetSelectionModel(SelectionModel()); | 331 SetSelectionModel(SelectionModel()); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 390 | 401 |
| 391 obscured_reveal_index_ = index; | 402 obscured_reveal_index_ = index; |
| 392 cached_bounds_and_offset_valid_ = false; | 403 cached_bounds_and_offset_valid_ = false; |
| 393 UpdateObscuredText(); | 404 UpdateObscuredText(); |
| 394 ResetLayout(); | 405 ResetLayout(); |
| 395 } | 406 } |
| 396 | 407 |
| 397 void RenderText::SetDisplayRect(const Rect& r) { | 408 void RenderText::SetDisplayRect(const Rect& r) { |
| 398 display_rect_ = r; | 409 display_rect_ = r; |
| 399 cached_bounds_and_offset_valid_ = false; | 410 cached_bounds_and_offset_valid_ = false; |
| 411 lines_valid_ = false; | |
| 400 } | 412 } |
| 401 | 413 |
| 402 void RenderText::SetCursorPosition(size_t position) { | 414 void RenderText::SetCursorPosition(size_t position) { |
| 403 MoveCursorTo(position, false); | 415 MoveCursorTo(position, false); |
| 404 } | 416 } |
| 405 | 417 |
| 406 void RenderText::MoveCursor(BreakType break_type, | 418 void RenderText::MoveCursor(BreakType break_type, |
| 407 VisualCursorDirection direction, | 419 VisualCursorDirection direction, |
| 408 bool select) { | 420 bool select) { |
| 409 SelectionModel position(cursor_position(), selection_model_.caret_affinity()); | 421 SelectionModel position(cursor_position(), selection_model_.caret_affinity()); |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 696 if (insert_mode) { | 708 if (insert_mode) { |
| 697 x = (caret_affinity == CURSOR_BACKWARD) ? xspan.end() : xspan.start(); | 709 x = (caret_affinity == CURSOR_BACKWARD) ? xspan.end() : xspan.start(); |
| 698 } else { // overtype mode | 710 } else { // overtype mode |
| 699 x = xspan.GetMin(); | 711 x = xspan.GetMin(); |
| 700 width = xspan.length(); | 712 width = xspan.length(); |
| 701 } | 713 } |
| 702 } | 714 } |
| 703 return Rect(ToViewPoint(Point(x, 0)), Size(width, size.height())); | 715 return Rect(ToViewPoint(Point(x, 0)), Size(width, size.height())); |
| 704 } | 716 } |
| 705 | 717 |
| 718 std::vector<Rect> RenderText::RangeToViewRects(const ui::Range& x, int y) { | |
| 719 std::vector<Rect> rects; | |
| 720 | |
| 721 int height = GetStringSize().height(); | |
|
msw
2013/07/10 04:01:56
This is fine for the single line case, but each li
ckocagil
2013/07/13 16:05:10
Done.
| |
| 722 | |
| 723 if (!multiline()) { | |
| 724 Point start(x.GetMin(), y); | |
| 725 rects.push_back(Rect(ToViewPoint(start), Size(x.length(), height))); | |
| 726 return rects; | |
| 727 } | |
| 728 | |
| 729 EnsureLayout(); | |
| 730 ComputeLines(); | |
|
msw
2013/07/10 04:01:56
EnsureLayout should ComputeLines as needed, don't
ckocagil
2013/07/13 16:05:10
Done.
| |
| 731 | |
| 732 for (size_t line = 0; line < lines().size(); ++line) { | |
|
msw
2013/07/10 04:01:56
Add a comment to explain what's happening here, it
ckocagil
2013/07/13 16:05:10
Done.
| |
| 733 int line_x = 0; | |
| 734 for (size_t i = 0; i < lines()[line].size(); ++i) { | |
| 735 const internal::LineSegment* segment = lines()[line][i]; | |
| 736 ui::Range intersection = segment->x_pos.Intersect(x); | |
| 737 if (!intersection.is_empty()) { | |
| 738 Rect rect(line_x + intersection.start() - segment->x_pos.start(), | |
| 739 y + line * height, intersection.length(), height); | |
|
msw
2013/07/10 04:01:56
You need to use the proper per-line heights; at le
ckocagil
2013/07/13 16:05:10
Done, it uses per-line heights now.
| |
| 740 rect += GetTextOffset(LineWidth(line)); | |
|
msw
2013/07/10 04:01:56
Cache the line's offset in the outer loop.
ckocagil
2013/07/13 16:05:10
Done.
| |
| 741 rects.push_back(rect); | |
| 742 } | |
| 743 line_x += segment->x_pos.length(); | |
| 744 } | |
| 745 } | |
| 746 | |
| 747 return rects; | |
| 748 } | |
| 749 | |
| 706 const Rect& RenderText::GetUpdatedCursorBounds() { | 750 const Rect& RenderText::GetUpdatedCursorBounds() { |
| 707 UpdateCachedBoundsAndOffset(); | 751 UpdateCachedBoundsAndOffset(); |
| 708 return cursor_bounds_; | 752 return cursor_bounds_; |
| 709 } | 753 } |
| 710 | 754 |
| 711 size_t RenderText::IndexOfAdjacentGrapheme(size_t index, | 755 size_t RenderText::IndexOfAdjacentGrapheme(size_t index, |
| 712 LogicalCursorDirection direction) { | 756 LogicalCursorDirection direction) { |
| 713 if (index > text().length()) | 757 if (index > text().length()) |
| 714 return text().length(); | 758 return text().length(); |
| 715 | 759 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 756 selection_color_(kDefaultColor), | 800 selection_color_(kDefaultColor), |
| 757 selection_background_focused_color_(kDefaultSelectionBackgroundColor), | 801 selection_background_focused_color_(kDefaultSelectionBackgroundColor), |
| 758 selection_background_unfocused_color_(kDefaultSelectionBackgroundColor), | 802 selection_background_unfocused_color_(kDefaultSelectionBackgroundColor), |
| 759 focused_(false), | 803 focused_(false), |
| 760 composition_range_(ui::Range::InvalidRange()), | 804 composition_range_(ui::Range::InvalidRange()), |
| 761 colors_(kDefaultColor), | 805 colors_(kDefaultColor), |
| 762 styles_(NUM_TEXT_STYLES), | 806 styles_(NUM_TEXT_STYLES), |
| 763 composition_and_selection_styles_applied_(false), | 807 composition_and_selection_styles_applied_(false), |
| 764 obscured_(false), | 808 obscured_(false), |
| 765 obscured_reveal_index_(-1), | 809 obscured_reveal_index_(-1), |
| 810 multiline_(false), | |
| 766 fade_head_(false), | 811 fade_head_(false), |
| 767 fade_tail_(false), | 812 fade_tail_(false), |
| 768 background_is_transparent_(false), | 813 background_is_transparent_(false), |
| 769 clip_to_display_rect_(true), | 814 clip_to_display_rect_(true), |
| 770 cached_bounds_and_offset_valid_(false) { | 815 cached_bounds_and_offset_valid_(false), |
| 816 lines_valid_(false) { | |
| 771 } | 817 } |
| 772 | 818 |
| 773 const Vector2d& RenderText::GetUpdatedDisplayOffset() { | 819 const Vector2d& RenderText::GetUpdatedDisplayOffset() { |
| 774 UpdateCachedBoundsAndOffset(); | 820 UpdateCachedBoundsAndOffset(); |
| 775 return display_offset_; | 821 return display_offset_; |
| 776 } | 822 } |
| 777 | 823 |
| 778 SelectionModel RenderText::GetAdjacentSelectionModel( | 824 SelectionModel RenderText::GetAdjacentSelectionModel( |
| 779 const SelectionModel& current, | 825 const SelectionModel& current, |
| 780 BreakType break_type, | 826 BreakType break_type, |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 825 } | 871 } |
| 826 | 872 |
| 827 void RenderText::UndoCompositionAndSelectionStyles() { | 873 void RenderText::UndoCompositionAndSelectionStyles() { |
| 828 // Restore the underline and color breaks to undo the temporary styles. | 874 // Restore the underline and color breaks to undo the temporary styles. |
| 829 DCHECK(composition_and_selection_styles_applied_); | 875 DCHECK(composition_and_selection_styles_applied_); |
| 830 colors_ = saved_colors_; | 876 colors_ = saved_colors_; |
| 831 styles_[UNDERLINE] = saved_underlines_; | 877 styles_[UNDERLINE] = saved_underlines_; |
| 832 composition_and_selection_styles_applied_ = false; | 878 composition_and_selection_styles_applied_ = false; |
| 833 } | 879 } |
| 834 | 880 |
| 835 Vector2d RenderText::GetTextOffset() { | 881 Vector2d RenderText::GetTextOffset(int line_width) { |
| 836 Vector2d offset = display_rect().OffsetFromOrigin(); | 882 Vector2d offset = display_rect().OffsetFromOrigin(); |
| 837 offset.Add(GetUpdatedDisplayOffset()); | 883 if (!multiline()) |
|
msw
2013/07/10 04:01:56
Why ignore the display offset for multi-line? Even
ckocagil
2013/07/13 16:05:10
I ignored it for now because multi-line vertical s
| |
| 838 offset.Add(GetAlignmentOffset()); | 884 offset.Add(GetUpdatedDisplayOffset()); |
| 885 offset.Add(GetAlignmentOffset(line_width)); | |
| 839 return offset; | 886 return offset; |
| 840 } | 887 } |
| 841 | 888 |
| 842 Point RenderText::ToTextPoint(const Point& point) { | 889 Point RenderText::ToTextPoint(const Point& point) { |
| 843 return point - GetTextOffset(); | 890 return point - GetTextOffset(GetContentWidth()); |
| 891 // TODO: implement multiline | |
|
Alexei Svitkine (slow)
2013/07/09 15:35:13
TODO(ckocagil)
ckocagil
2013/07/13 16:05:10
Done.
| |
| 844 } | 892 } |
| 845 | 893 |
| 846 Point RenderText::ToViewPoint(const Point& point) { | 894 Point RenderText::ToViewPoint(const Point& point) { |
| 847 return point + GetTextOffset(); | 895 if (!multiline()) |
| 896 return point + GetTextOffset(GetContentWidth()); | |
| 897 | |
| 898 ComputeLines(); | |
|
msw
2013/07/10 04:01:56
Don't explicitly call this here, EnsureLayout or [
ckocagil
2013/07/13 16:05:10
Done.
| |
| 899 int x = point.x(); | |
| 900 unsigned int line = 0; | |
| 901 while (line < lines_.size() && x > LineWidth(line)) { | |
| 902 x -= LineWidth(line); | |
|
Alexei Svitkine (slow)
2013/07/09 15:35:13
Can you refactor this code to not call LineWidth()
ckocagil
2013/07/13 16:05:10
I will rewrite this method to support RTL soon (be
| |
| 903 ++line; | |
| 904 } | |
| 905 return Point(x, point.y() + line * GetStringSize().height()) + | |
|
msw
2013/07/10 04:01:56
Again, this needs per-line heights.
ckocagil
2013/07/13 16:05:10
Done.
| |
| 906 GetTextOffset(LineWidth(line)); | |
| 848 } | 907 } |
| 849 | 908 |
| 850 Vector2d RenderText::GetAlignmentOffset() { | 909 Vector2d RenderText::GetAlignmentOffset(int line_width) { |
| 910 | |
|
msw
2013/07/10 04:01:56
nit: remove blank line.
ckocagil
2013/07/13 16:05:10
Done.
| |
| 851 Vector2d offset; | 911 Vector2d offset; |
| 852 if (horizontal_alignment_ != ALIGN_LEFT) { | 912 if (horizontal_alignment_ != ALIGN_LEFT) { |
| 853 offset.set_x(display_rect().width() - GetContentWidth()); | 913 offset.set_x(display_rect().width() - (multiline() ? line_width |
|
msw
2013/07/10 04:01:56
Always use |line_width|, you pass in GetContentWid
ckocagil
2013/07/13 16:05:10
I now pass 0 for single-line mode. Single-line mod
| |
| 914 : GetContentWidth())); | |
| 854 if (horizontal_alignment_ == ALIGN_CENTER) | 915 if (horizontal_alignment_ == ALIGN_CENTER) |
| 855 offset.set_x(offset.x() / 2); | 916 offset.set_x(offset.x() / 2); |
| 856 } | 917 } |
| 857 if (vertical_alignment_ != ALIGN_TOP) { | 918 if (vertical_alignment_ != ALIGN_TOP) { |
| 858 offset.set_y(display_rect().height() - GetStringSize().height()); | 919 offset.set_y(display_rect().height() - GetMultilineTextSize().height()); |
| 859 if (vertical_alignment_ == ALIGN_VCENTER) | 920 if (vertical_alignment_ == ALIGN_VCENTER) |
| 860 offset.set_y(offset.y() / 2); | 921 offset.set_y(offset.y() / 2); |
| 861 } | 922 } |
| 862 return offset; | 923 return offset; |
| 863 } | 924 } |
| 864 | 925 |
| 865 void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) { | 926 void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) { |
| 866 if (!fade_head() && !fade_tail()) | 927 if (!fade_head() && !fade_tail()) |
| 867 return; | 928 return; |
| 868 | 929 |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 894 left_part.Inset(0, 0, solid_part.width() - gradient_width, 0); | 955 left_part.Inset(0, 0, solid_part.width() - gradient_width, 0); |
| 895 solid_part.Inset(gradient_width, 0, 0, 0); | 956 solid_part.Inset(gradient_width, 0, 0, 0); |
| 896 } | 957 } |
| 897 if (fade_right) { | 958 if (fade_right) { |
| 898 right_part = solid_part; | 959 right_part = solid_part; |
| 899 right_part.Inset(solid_part.width() - gradient_width, 0, 0, 0); | 960 right_part.Inset(solid_part.width() - gradient_width, 0, 0, 0); |
| 900 solid_part.Inset(0, 0, gradient_width, 0); | 961 solid_part.Inset(0, 0, gradient_width, 0); |
| 901 } | 962 } |
| 902 | 963 |
| 903 Rect text_rect = display_rect(); | 964 Rect text_rect = display_rect(); |
| 904 text_rect.Inset(GetAlignmentOffset().x(), 0, 0, 0); | 965 text_rect.Inset(GetAlignmentOffset(GetContentWidth()).x(), 0, 0, 0); |
| 905 | 966 |
| 906 // TODO(msw): Use the actual text colors corresponding to each faded part. | 967 // TODO(msw): Use the actual text colors corresponding to each faded part. |
| 907 skia::RefPtr<SkShader> shader = CreateFadeShader( | 968 skia::RefPtr<SkShader> shader = CreateFadeShader( |
| 908 text_rect, left_part, right_part, colors_.breaks().front().second); | 969 text_rect, left_part, right_part, colors_.breaks().front().second); |
| 909 if (shader) | 970 if (shader) |
| 910 renderer->SetShader(shader.get(), display_rect()); | 971 renderer->SetShader(shader.get(), display_rect()); |
| 911 } | 972 } |
| 912 | 973 |
| 913 void RenderText::ApplyTextShadows(internal::SkiaTextRenderer* renderer) { | 974 void RenderText::ApplyTextShadows(internal::SkiaTextRenderer* renderer) { |
| 914 skia::RefPtr<SkDrawLooper> looper = CreateShadowDrawLooper(text_shadows_); | 975 skia::RefPtr<SkDrawLooper> looper = CreateShadowDrawLooper(text_shadows_); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1007 void RenderText::DrawSelection(Canvas* canvas) { | 1068 void RenderText::DrawSelection(Canvas* canvas) { |
| 1008 const SkColor color = focused() ? | 1069 const SkColor color = focused() ? |
| 1009 selection_background_focused_color_ : | 1070 selection_background_focused_color_ : |
| 1010 selection_background_unfocused_color_; | 1071 selection_background_unfocused_color_; |
| 1011 const std::vector<Rect> sel = GetSubstringBounds(selection()); | 1072 const std::vector<Rect> sel = GetSubstringBounds(selection()); |
| 1012 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i) | 1073 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i) |
| 1013 canvas->FillRect(*i, color); | 1074 canvas->FillRect(*i, color); |
| 1014 } | 1075 } |
| 1015 | 1076 |
| 1016 } // namespace gfx | 1077 } // namespace gfx |
| OLD | NEW |