Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(219)

Side by Side Diff: ui/gfx/render_text.cc

Issue 16867016: Windows implementation of multiline RenderText (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: comments addressed Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 283 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 range = range.Intersect(styles_[i].GetRange(style_[i])); 294 range = range.Intersect(styles_[i].GetRange(style_[i]));
295 return range; 295 return range;
296 } 296 }
297 297
298 void StyleIterator::UpdatePosition(size_t position) { 298 void StyleIterator::UpdatePosition(size_t position) {
299 color_ = colors_.GetBreak(position); 299 color_ = colors_.GetBreak(position);
300 for (size_t i = 0; i < NUM_TEXT_STYLES; ++i) 300 for (size_t i = 0; i < NUM_TEXT_STYLES; ++i)
301 style_[i] = styles_[i].GetBreak(position); 301 style_[i] = styles_[i].GetBreak(position);
302 } 302 }
303 303
304 Line::Line() : width(0), height(0), preceding_heights(0), baseline(0) {}
305
306 Line::Line(Line& other) {
307 *this = other;
308 }
309
310 Line& Line::operator=(Line& other) {
311 width = other.width;
312 height = other.height;
313 preceding_heights = other.preceding_heights;
314 baseline = other.baseline;
315 segments.swap(other.segments);
316 return *this;
317 }
318
304 } // namespace internal 319 } // namespace internal
305 320
306 RenderText::~RenderText() { 321 RenderText::~RenderText() {
307 } 322 }
308 323
309 void RenderText::SetText(const base::string16& text) { 324 void RenderText::SetText(const base::string16& text) {
310 DCHECK(!composition_range_.IsValid()); 325 DCHECK(!composition_range_.IsValid());
326 if (text_ == text)
327 return;
311 text_ = text; 328 text_ = text;
312 329
313 // Adjust ranged styles and colors to accommodate a new text length. 330 // Adjust ranged styles and colors to accommodate a new text length.
314 const size_t text_length = text_.length(); 331 const size_t text_length = text_.length();
315 colors_.SetMax(text_length); 332 colors_.SetMax(text_length);
316 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) 333 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style)
317 styles_[style].SetMax(text_length); 334 styles_[style].SetMax(text_length);
318 cached_bounds_and_offset_valid_ = false; 335 cached_bounds_and_offset_valid_ = false;
319 336
320 // Reset selection model. SetText should always followed by SetSelectionModel 337 // Reset selection model. SetText should always followed by SetSelectionModel
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 void RenderText::SetObscured(bool obscured) { 394 void RenderText::SetObscured(bool obscured) {
378 if (obscured != obscured_) { 395 if (obscured != obscured_) {
379 obscured_ = obscured; 396 obscured_ = obscured;
380 obscured_reveal_index_ = -1; 397 obscured_reveal_index_ = -1;
381 cached_bounds_and_offset_valid_ = false; 398 cached_bounds_and_offset_valid_ = false;
382 UpdateLayoutText(); 399 UpdateLayoutText();
383 ResetLayout(); 400 ResetLayout();
384 } 401 }
385 } 402 }
386 403
404 void RenderText::SetMultiline(bool multiline) {
405 if (multiline != multiline_) {
406 multiline_ = multiline;
407 cached_bounds_and_offset_valid_ = false;
408 ResetLayout();
409 }
410 }
411
387 void RenderText::SetObscuredRevealIndex(int index) { 412 void RenderText::SetObscuredRevealIndex(int index) {
388 if (obscured_reveal_index_ == index) 413 if (obscured_reveal_index_ == index)
389 return; 414 return;
390 415
391 obscured_reveal_index_ = index; 416 obscured_reveal_index_ = index;
392 cached_bounds_and_offset_valid_ = false; 417 cached_bounds_and_offset_valid_ = false;
393 UpdateLayoutText(); 418 UpdateLayoutText();
394 ResetLayout(); 419 ResetLayout();
395 } 420 }
396 421
397 void RenderText::SetDisplayRect(const Rect& r) { 422 void RenderText::SetDisplayRect(const Rect& r) {
398 display_rect_ = r; 423 display_rect_ = r;
399 cached_bounds_and_offset_valid_ = false; 424 cached_bounds_and_offset_valid_ = false;
425 lines_.clear();
400 } 426 }
401 427
402 void RenderText::SetCursorPosition(size_t position) { 428 void RenderText::SetCursorPosition(size_t position) {
403 MoveCursorTo(position, false); 429 MoveCursorTo(position, false);
404 } 430 }
405 431
406 void RenderText::MoveCursor(BreakType break_type, 432 void RenderText::MoveCursor(BreakType break_type,
407 VisualCursorDirection direction, 433 VisualCursorDirection direction,
408 bool select) { 434 bool select) {
409 SelectionModel position(cursor_position(), selection_model_.caret_affinity()); 435 SelectionModel position(cursor_position(), selection_model_.caret_affinity());
(...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after
756 selection_color_(kDefaultColor), 782 selection_color_(kDefaultColor),
757 selection_background_focused_color_(kDefaultSelectionBackgroundColor), 783 selection_background_focused_color_(kDefaultSelectionBackgroundColor),
758 focused_(false), 784 focused_(false),
759 composition_range_(ui::Range::InvalidRange()), 785 composition_range_(ui::Range::InvalidRange()),
760 colors_(kDefaultColor), 786 colors_(kDefaultColor),
761 styles_(NUM_TEXT_STYLES), 787 styles_(NUM_TEXT_STYLES),
762 composition_and_selection_styles_applied_(false), 788 composition_and_selection_styles_applied_(false),
763 obscured_(false), 789 obscured_(false),
764 obscured_reveal_index_(-1), 790 obscured_reveal_index_(-1),
765 truncate_length_(0), 791 truncate_length_(0),
792 multiline_(false),
766 fade_head_(false), 793 fade_head_(false),
767 fade_tail_(false), 794 fade_tail_(false),
768 background_is_transparent_(false), 795 background_is_transparent_(false),
769 clip_to_display_rect_(true), 796 clip_to_display_rect_(true),
770 cached_bounds_and_offset_valid_(false) { 797 cached_bounds_and_offset_valid_(false) {
771 } 798 }
772 799
773 const Vector2d& RenderText::GetUpdatedDisplayOffset() { 800 const Vector2d& RenderText::GetUpdatedDisplayOffset() {
774 UpdateCachedBoundsAndOffset(); 801 UpdateCachedBoundsAndOffset();
775 return display_offset_; 802 return display_offset_;
(...skipping 23 matching lines...) Expand all
799 void RenderText::SetSelectionModel(const SelectionModel& model) { 826 void RenderText::SetSelectionModel(const SelectionModel& model) {
800 DCHECK_LE(model.selection().GetMax(), text().length()); 827 DCHECK_LE(model.selection().GetMax(), text().length());
801 selection_model_ = model; 828 selection_model_ = model;
802 cached_bounds_and_offset_valid_ = false; 829 cached_bounds_and_offset_valid_ = false;
803 } 830 }
804 831
805 const base::string16& RenderText::GetLayoutText() const { 832 const base::string16& RenderText::GetLayoutText() const {
806 return layout_text_.empty() ? text_ : layout_text_; 833 return layout_text_.empty() ? text_ : layout_text_;
807 } 834 }
808 835
836 const BreakList<size_t>& RenderText::GetLineBreaks() {
837 if (line_breaks_.max() == 0) {
838 const string16& layout_text = GetLayoutText();
839 line_breaks_.SetValue(0);
840 line_breaks_.SetMax(layout_text.length());
841 base::i18n::BreakIterator iter(layout_text,
842 base::i18n::BreakIterator::BREAK_LINE);
843 bool success = iter.Init();
844 CHECK(success);
845 do {
846 line_breaks_.ApplyValue(iter.pos(), ui::Range(iter.pos(),
847 layout_text.length()));
848 } while (iter.Advance());
849 }
850 return line_breaks_;
851 }
852
809 void RenderText::ApplyCompositionAndSelectionStyles() { 853 void RenderText::ApplyCompositionAndSelectionStyles() {
810 // Save the underline and color breaks to undo the temporary styles later. 854 // Save the underline and color breaks to undo the temporary styles later.
811 DCHECK(!composition_and_selection_styles_applied_); 855 DCHECK(!composition_and_selection_styles_applied_);
812 saved_colors_ = colors_; 856 saved_colors_ = colors_;
813 saved_underlines_ = styles_[UNDERLINE]; 857 saved_underlines_ = styles_[UNDERLINE];
814 858
815 // Apply an underline to the composition range in |underlines|. 859 // Apply an underline to the composition range in |underlines|.
816 if (composition_range_.IsValid() && !composition_range_.is_empty()) 860 if (composition_range_.IsValid() && !composition_range_.is_empty())
817 styles_[UNDERLINE].ApplyValue(true, composition_range_); 861 styles_[UNDERLINE].ApplyValue(true, composition_range_);
818 862
819 // Apply the selected text color to the [un-reversed] selection range. 863 // Apply the selected text color to the [un-reversed] selection range.
820 if (!selection().is_empty()) { 864 if (!selection().is_empty()) {
821 const ui::Range range(selection().GetMin(), selection().GetMax()); 865 const ui::Range range(selection().GetMin(), selection().GetMax());
822 colors_.ApplyValue(selection_color_, range); 866 colors_.ApplyValue(selection_color_, range);
823 } 867 }
824 composition_and_selection_styles_applied_ = true; 868 composition_and_selection_styles_applied_ = true;
825 } 869 }
826 870
827 void RenderText::UndoCompositionAndSelectionStyles() { 871 void RenderText::UndoCompositionAndSelectionStyles() {
828 // Restore the underline and color breaks to undo the temporary styles. 872 // Restore the underline and color breaks to undo the temporary styles.
829 DCHECK(composition_and_selection_styles_applied_); 873 DCHECK(composition_and_selection_styles_applied_);
830 colors_ = saved_colors_; 874 colors_ = saved_colors_;
831 styles_[UNDERLINE] = saved_underlines_; 875 styles_[UNDERLINE] = saved_underlines_;
832 composition_and_selection_styles_applied_ = false; 876 composition_and_selection_styles_applied_ = false;
833 } 877 }
834 878
835 Vector2d RenderText::GetTextOffset() { 879 Vector2d RenderText::GetLineOffset(size_t line_number) {
836 Vector2d offset = display_rect().OffsetFromOrigin(); 880 Vector2d offset = display_rect().OffsetFromOrigin();
837 offset.Add(GetUpdatedDisplayOffset()); 881 if (!multiline())
838 offset.Add(GetAlignmentOffset()); 882 offset.Add(GetUpdatedDisplayOffset());
883 else
884 offset.Add(Vector2d(0, lines()[line_number].preceding_heights));
885 offset.Add(GetAlignmentOffset(line_number));
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 - GetLineOffset(0);
891 // TODO(ckocagil): implement multiline.
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 + GetLineOffset(0);
897
898 // TODO(ckocagil): refactor this to traverse all line segments to support rtl.
899 DCHECK(!lines_.empty());
900 int x = point.x();
901 unsigned int line = 0;
902 while (line < lines_.size() && x > lines()[line].width) {
903 x -= lines()[line].width;
904 ++line;
905 }
906 return Point(x, point.y()) + GetLineOffset(line);
848 } 907 }
849 908
850 Vector2d RenderText::GetAlignmentOffset() { 909 std::vector<Rect> RenderText::TextBoundsToViewBounds(const ui::Range& x) {
910 std::vector<Rect> rects;
911
912 if (!multiline()) {
913 rects.push_back(Rect(ToViewPoint(Point(x.GetMin(), 0)),
914 Size(x.length(), GetStringSize().height())));
915 return rects;
916 }
917
918 EnsureLayout();
919
920 // Each line segments keeps its position in text coordinates. Traverse all
921 // line segments and if the segment intersects with the given range, add the
922 // view rect corresponding to the intersection to |rects|.
923 for (size_t line = 0; line < lines().size(); ++line) {
924 int line_x = 0;
925 Vector2d offset = GetLineOffset(line);
926 for (size_t i = 0; i < lines()[line].segments.size(); ++i) {
927 const internal::LineSegment* segment = lines()[line].segments[i];
928 ui::Range intersection = segment->x_pos.Intersect(x);
929 if (!intersection.is_empty()) {
930 Rect rect(line_x + intersection.start() - segment->x_pos.start(),
931 0, intersection.length(), lines()[line].height);
932 rect += offset;
933 rects.push_back(rect);
934 }
935 line_x += segment->x_pos.length();
936 }
937 }
938
939 return rects;
940 }
941
942
943 Vector2d RenderText::GetAlignmentOffset(size_t line_number) {
944 DCHECK(!lines_.empty());
945 const int width = lines()[line_number].width;
851 Vector2d offset; 946 Vector2d offset;
852 if (horizontal_alignment_ != ALIGN_LEFT) { 947 if (horizontal_alignment_ != ALIGN_LEFT) {
853 offset.set_x(display_rect().width() - GetContentWidth()); 948 offset.set_x(display_rect().width() - width);
854 if (horizontal_alignment_ == ALIGN_CENTER) 949 if (horizontal_alignment_ == ALIGN_CENTER)
855 offset.set_x(offset.x() / 2); 950 offset.set_x(offset.x() / 2);
856 } 951 }
857 if (vertical_alignment_ != ALIGN_TOP) { 952 if (vertical_alignment_ != ALIGN_TOP) {
858 offset.set_y(display_rect().height() - GetStringSize().height()); 953 offset.set_y(display_rect().height() - GetMultilineTextSize().height());
859 if (vertical_alignment_ == ALIGN_VCENTER) 954 if (vertical_alignment_ == ALIGN_VCENTER)
860 offset.set_y(offset.y() / 2); 955 offset.set_y(offset.y() / 2);
861 } 956 }
862 return offset; 957 return offset;
863 } 958 }
864 959
865 void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) { 960 void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) {
866 if (!fade_head() && !fade_tail()) 961 if (multiline() || !fade_head() && !fade_tail())
867 return; 962 return;
868 963
869 const int text_width = GetStringSize().width();
870 const int display_width = display_rect().width(); 964 const int display_width = display_rect().width();
871 965
872 // If the text fits as-is, no need to fade. 966 // If the text fits as-is, no need to fade.
873 if (text_width <= display_width) 967 if (GetStringSize().width() <= display_width)
874 return; 968 return;
875 969
876 int gradient_width = CalculateFadeGradientWidth(GetPrimaryFont(), 970 int gradient_width = CalculateFadeGradientWidth(GetPrimaryFont(),
877 display_width); 971 display_width);
878 if (gradient_width == 0) 972 if (gradient_width == 0)
879 return; 973 return;
880 974
881 bool fade_left = fade_head(); 975 bool fade_left = fade_head();
882 bool fade_right = fade_tail(); 976 bool fade_right = fade_tail();
883 // Under RTL, |fade_right| == |fade_head|. 977 // Under RTL, |fade_right| == |fade_head|.
(...skipping 11 matching lines...) Expand all
895 left_part.Inset(0, 0, solid_part.width() - gradient_width, 0); 989 left_part.Inset(0, 0, solid_part.width() - gradient_width, 0);
896 solid_part.Inset(gradient_width, 0, 0, 0); 990 solid_part.Inset(gradient_width, 0, 0, 0);
897 } 991 }
898 if (fade_right) { 992 if (fade_right) {
899 right_part = solid_part; 993 right_part = solid_part;
900 right_part.Inset(solid_part.width() - gradient_width, 0, 0, 0); 994 right_part.Inset(solid_part.width() - gradient_width, 0, 0, 0);
901 solid_part.Inset(0, 0, gradient_width, 0); 995 solid_part.Inset(0, 0, gradient_width, 0);
902 } 996 }
903 997
904 Rect text_rect = display_rect(); 998 Rect text_rect = display_rect();
905 text_rect.Inset(GetAlignmentOffset().x(), 0, 0, 0); 999 text_rect.Inset(GetAlignmentOffset(0).x(), 0, 0, 0);
906 1000
907 // TODO(msw): Use the actual text colors corresponding to each faded part. 1001 // TODO(msw): Use the actual text colors corresponding to each faded part.
908 skia::RefPtr<SkShader> shader = CreateFadeShader( 1002 skia::RefPtr<SkShader> shader = CreateFadeShader(
909 text_rect, left_part, right_part, colors_.breaks().front().second); 1003 text_rect, left_part, right_part, colors_.breaks().front().second);
910 if (shader) 1004 if (shader)
911 renderer->SetShader(shader.get(), display_rect()); 1005 renderer->SetShader(shader.get(), display_rect());
912 } 1006 }
913 1007
914 void RenderText::ApplyTextShadows(internal::SkiaTextRenderer* renderer) { 1008 void RenderText::ApplyTextShadows(internal::SkiaTextRenderer* renderer) {
915 skia::RefPtr<SkDrawLooper> looper = CreateShadowDrawLooper(text_shadows_); 1009 skia::RefPtr<SkDrawLooper> looper = CreateShadowDrawLooper(text_shadows_);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
959 } 1053 }
960 } 1054 }
961 1055
962 const base::string16& text = obscured_ ? layout_text_ : text_; 1056 const base::string16& text = obscured_ ? layout_text_ : text_;
963 if (truncate_length_ > 0 && truncate_length_ < text.length()) { 1057 if (truncate_length_ > 0 && truncate_length_ < text.length()) {
964 // Truncate the text at a valid character break and append an ellipsis. 1058 // Truncate the text at a valid character break and append an ellipsis.
965 icu::StringCharacterIterator iter(text.c_str()); 1059 icu::StringCharacterIterator iter(text.c_str());
966 iter.setIndex32(truncate_length_ - 1); 1060 iter.setIndex32(truncate_length_ - 1);
967 layout_text_.assign(text.substr(0, iter.getIndex()) + ui::kEllipsisUTF16); 1061 layout_text_.assign(text.substr(0, iter.getIndex()) + ui::kEllipsisUTF16);
968 } 1062 }
1063
1064 line_breaks_.SetMax(0);
969 } 1065 }
970 1066
971 void RenderText::UpdateCachedBoundsAndOffset() { 1067 void RenderText::UpdateCachedBoundsAndOffset() {
972 if (cached_bounds_and_offset_valid_) 1068 if (cached_bounds_and_offset_valid_)
973 return; 1069 return;
974 1070
1071 // TODO(ckocagil): Add vertical offset support for scrolling multi-line text.
1072
975 // First, set the valid flag true to calculate the current cursor bounds using 1073 // First, set the valid flag true to calculate the current cursor bounds using
976 // the stale |display_offset_|. Applying |delta_offset| at the end of this 1074 // the stale |display_offset_|. Applying |delta_offset| at the end of this
977 // function will set |cursor_bounds_| and |display_offset_| to correct values. 1075 // function will set |cursor_bounds_| and |display_offset_| to correct values.
978 cached_bounds_and_offset_valid_ = true; 1076 cached_bounds_and_offset_valid_ = true;
979 cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_); 1077 cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_);
980 1078
981 // Update |display_offset_| to ensure the current cursor is visible. 1079 // Update |display_offset_| to ensure the current cursor is visible.
982 const int display_width = display_rect_.width(); 1080 const int display_width = display_rect_.width();
983 const int content_width = GetContentWidth(); 1081 const int content_width = GetContentWidth();
984 1082
(...skipping 30 matching lines...) Expand all
1015 cursor_bounds_ += delta_offset; 1113 cursor_bounds_ += delta_offset;
1016 } 1114 }
1017 1115
1018 void RenderText::DrawSelection(Canvas* canvas) { 1116 void RenderText::DrawSelection(Canvas* canvas) {
1019 const std::vector<Rect> sel = GetSubstringBounds(selection()); 1117 const std::vector<Rect> sel = GetSubstringBounds(selection());
1020 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i) 1118 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i)
1021 canvas->FillRect(*i, selection_background_focused_color_); 1119 canvas->FillRect(*i, selection_background_focused_color_);
1022 } 1120 }
1023 1121
1024 } // namespace gfx 1122 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text.h ('k') | ui/gfx/render_text_win.h » ('j') | ui/gfx/render_text_win.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698