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 |