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

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: fit whole runs, remove single-line stuff Created 7 years, 5 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 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 style_[i] = styles_[i].GetBreak(position); 301 style_[i] = styles_[i].GetBreak(position);
302 } 302 }
303 303
304 } // namespace internal 304 } // namespace internal
305 305
306 RenderText::~RenderText() { 306 RenderText::~RenderText() {
307 } 307 }
308 308
309 void RenderText::SetText(const base::string16& text) { 309 void RenderText::SetText(const base::string16& text) {
310 DCHECK(!composition_range_.IsValid()); 310 DCHECK(!composition_range_.IsValid());
311 if (text_ == text)
312 return;
311 text_ = text; 313 text_ = text;
312 314
313 // Adjust ranged styles and colors to accommodate a new text length. 315 // Adjust ranged styles and colors to accommodate a new text length.
314 const size_t text_length = text_.length(); 316 const size_t text_length = text_.length();
315 colors_.SetMax(text_length); 317 colors_.SetMax(text_length);
316 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) 318 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style)
317 styles_[style].SetMax(text_length); 319 styles_[style].SetMax(text_length);
318 cached_bounds_and_offset_valid_ = false; 320 cached_bounds_and_offset_valid_ = false;
319 321
320 // Reset selection model. SetText should always followed by SetSelectionModel 322 // Reset selection model. SetText should always followed by SetSelectionModel
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 394
393 obscured_reveal_index_ = index; 395 obscured_reveal_index_ = index;
394 cached_bounds_and_offset_valid_ = false; 396 cached_bounds_and_offset_valid_ = false;
395 UpdateLayoutText(); 397 UpdateLayoutText();
396 ResetLayout(); 398 ResetLayout();
397 } 399 }
398 400
399 void RenderText::SetDisplayRect(const Rect& r) { 401 void RenderText::SetDisplayRect(const Rect& r) {
400 display_rect_ = r; 402 display_rect_ = r;
401 cached_bounds_and_offset_valid_ = false; 403 cached_bounds_and_offset_valid_ = false;
404 lines_valid_ = false;
402 } 405 }
403 406
404 void RenderText::SetCursorPosition(size_t position) { 407 void RenderText::SetCursorPosition(size_t position) {
405 MoveCursorTo(position, false); 408 MoveCursorTo(position, false);
406 } 409 }
407 410
408 void RenderText::MoveCursor(BreakType break_type, 411 void RenderText::MoveCursor(BreakType break_type,
409 VisualCursorDirection direction, 412 VisualCursorDirection direction,
410 bool select) { 413 bool select) {
411 SelectionModel position(cursor_position(), selection_model_.caret_affinity()); 414 SelectionModel position(cursor_position(), selection_model_.caret_affinity());
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
698 if (insert_mode) { 701 if (insert_mode) {
699 x = (caret_affinity == CURSOR_BACKWARD) ? xspan.end() : xspan.start(); 702 x = (caret_affinity == CURSOR_BACKWARD) ? xspan.end() : xspan.start();
700 } else { // overtype mode 703 } else { // overtype mode
701 x = xspan.GetMin(); 704 x = xspan.GetMin();
702 width = xspan.length(); 705 width = xspan.length();
703 } 706 }
704 } 707 }
705 return Rect(ToViewPoint(Point(x, 0)), Size(width, size.height())); 708 return Rect(ToViewPoint(Point(x, 0)), Size(width, size.height()));
706 } 709 }
707 710
711 std::vector<Rect> RenderText::RangeToViewRects(const ui::Range& x) {
msw 2013/07/17 06:47:18 This function should be defined in the order it's
ckocagil 2013/07/19 19:40:50 Done.
712 std::vector<Rect> rects;
713
714 if (!multiline()) {
715 Point start(x.GetMin(), 0);
716 rects.push_back(Rect(ToViewPoint(start), Size(x.length(),
msw 2013/07/17 06:47:18 nit: inline start and break the line before 'Size(
ckocagil 2013/07/19 19:40:50 Done.
717 GetStringSize().height())));
718 return rects;
719 }
720
721 EnsureLayout();
722
723 // Each line segments keeps its position in text coordinates. Traverse all
724 // line segments and if the segment intersects with the given range, add the
725 // view rect corresponding to the intersection to |rects|.
726 for (size_t line = 0; line < lines().size(); ++line) {
727 int line_x = 0;
728 Vector2d offset = GetLineOffset(line);
729 for (size_t i = 0; i < lines()[line].segments.size(); ++i) {
730 const internal::LineSegment* segment = lines()[line].segments[i];
731 ui::Range intersection = segment->x_pos.Intersect(x);
732 if (!intersection.is_empty()) {
733 Rect rect(line_x + intersection.start() - segment->x_pos.start(),
734 0, intersection.length(), lines()[line].height);
735 rect += offset;
736 rects.push_back(rect);
737 }
738 line_x += segment->x_pos.length();
739 }
740 }
741
742 return rects;
743 }
744
708 const Rect& RenderText::GetUpdatedCursorBounds() { 745 const Rect& RenderText::GetUpdatedCursorBounds() {
709 UpdateCachedBoundsAndOffset(); 746 UpdateCachedBoundsAndOffset();
710 return cursor_bounds_; 747 return cursor_bounds_;
711 } 748 }
712 749
713 size_t RenderText::IndexOfAdjacentGrapheme(size_t index, 750 size_t RenderText::IndexOfAdjacentGrapheme(size_t index,
714 LogicalCursorDirection direction) { 751 LogicalCursorDirection direction) {
715 if (index > text().length()) 752 if (index > text().length())
716 return text().length(); 753 return text().length();
717 754
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
758 selection_color_(kDefaultColor), 795 selection_color_(kDefaultColor),
759 selection_background_focused_color_(kDefaultSelectionBackgroundColor), 796 selection_background_focused_color_(kDefaultSelectionBackgroundColor),
760 focused_(false), 797 focused_(false),
761 composition_range_(ui::Range::InvalidRange()), 798 composition_range_(ui::Range::InvalidRange()),
762 colors_(kDefaultColor), 799 colors_(kDefaultColor),
763 styles_(NUM_TEXT_STYLES), 800 styles_(NUM_TEXT_STYLES),
764 composition_and_selection_styles_applied_(false), 801 composition_and_selection_styles_applied_(false),
765 obscured_(false), 802 obscured_(false),
766 obscured_reveal_index_(-1), 803 obscured_reveal_index_(-1),
767 truncate_length_(0), 804 truncate_length_(0),
805 multiline_(false),
768 fade_head_(false), 806 fade_head_(false),
769 fade_tail_(false), 807 fade_tail_(false),
770 background_is_transparent_(false), 808 background_is_transparent_(false),
771 clip_to_display_rect_(true), 809 clip_to_display_rect_(true),
772 cached_bounds_and_offset_valid_(false) { 810 cached_bounds_and_offset_valid_(false),
811 lines_valid_(false) {
773 } 812 }
774 813
775 const Vector2d& RenderText::GetUpdatedDisplayOffset() { 814 const Vector2d& RenderText::GetUpdatedDisplayOffset() {
776 UpdateCachedBoundsAndOffset(); 815 UpdateCachedBoundsAndOffset();
777 return display_offset_; 816 return display_offset_;
778 } 817 }
779 818
780 SelectionModel RenderText::GetAdjacentSelectionModel( 819 SelectionModel RenderText::GetAdjacentSelectionModel(
781 const SelectionModel& current, 820 const SelectionModel& current,
782 BreakType break_type, 821 BreakType break_type,
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
827 } 866 }
828 867
829 void RenderText::UndoCompositionAndSelectionStyles() { 868 void RenderText::UndoCompositionAndSelectionStyles() {
830 // Restore the underline and color breaks to undo the temporary styles. 869 // Restore the underline and color breaks to undo the temporary styles.
831 DCHECK(composition_and_selection_styles_applied_); 870 DCHECK(composition_and_selection_styles_applied_);
832 colors_ = saved_colors_; 871 colors_ = saved_colors_;
833 styles_[UNDERLINE] = saved_underlines_; 872 styles_[UNDERLINE] = saved_underlines_;
834 composition_and_selection_styles_applied_ = false; 873 composition_and_selection_styles_applied_ = false;
835 } 874 }
836 875
837 Vector2d RenderText::GetTextOffset() { 876 Vector2d RenderText::GetLineOffset(int line) {
838 Vector2d offset = display_rect().OffsetFromOrigin(); 877 Vector2d offset = display_rect().OffsetFromOrigin();
839 offset.Add(GetUpdatedDisplayOffset()); 878 if (!multiline())
840 offset.Add(GetAlignmentOffset()); 879 offset.Add(GetUpdatedDisplayOffset());
880 else
881 offset.Add(Vector2d(0, lines()[line].preceding_heights));
msw 2013/07/17 06:47:18 Does this need to add a per-line horizontal offset
ckocagil 2013/07/19 19:40:50 Which horizontal offset? I don't see your point.
msw 2013/08/15 02:44:17 Nevermind! The line's alignment offset is added ri
882 offset.Add(GetAlignmentOffset(line));
841 return offset; 883 return offset;
842 } 884 }
843 885
844 Point RenderText::ToTextPoint(const Point& point) { 886 Point RenderText::ToTextPoint(const Point& point) {
845 return point - GetTextOffset(); 887 return point - GetLineOffset(0);
888 // TODO(ckocagil): implement multiline.
846 } 889 }
847 890
848 Point RenderText::ToViewPoint(const Point& point) { 891 Point RenderText::ToViewPoint(const Point& point) {
849 return point + GetTextOffset(); 892 if (!multiline())
893 return point + GetLineOffset(0);
894
895 // TODO(ckocagil): refactor this to traverse all line segments to support rtl.
896 DCHECK(lines_valid_);
897 int x = point.x();
898 unsigned int line = 0;
899 while (line < lines_.size() && x > lines()[line].width) {
900 x -= lines()[line].width;
901 ++line;
902 }
903 return Point(x, point.y()) + GetLineOffset(line);
850 } 904 }
851 905
852 Vector2d RenderText::GetAlignmentOffset() { 906 Vector2d RenderText::GetAlignmentOffset(int line) {
907 int width = lines()[line].width;
msw 2013/07/17 06:47:18 nit: make this const, maybe DCHECK lines_ validity
ckocagil 2013/07/19 19:40:50 Done.
853 Vector2d offset; 908 Vector2d offset;
854 if (horizontal_alignment_ != ALIGN_LEFT) { 909 if (horizontal_alignment_ != ALIGN_LEFT) {
855 offset.set_x(display_rect().width() - GetContentWidth()); 910 offset.set_x(display_rect().width() - width);
856 if (horizontal_alignment_ == ALIGN_CENTER) 911 if (horizontal_alignment_ == ALIGN_CENTER)
857 offset.set_x(offset.x() / 2); 912 offset.set_x(offset.x() / 2);
858 } 913 }
859 if (vertical_alignment_ != ALIGN_TOP) { 914 if (vertical_alignment_ != ALIGN_TOP) {
860 offset.set_y(display_rect().height() - GetStringSize().height()); 915 offset.set_y(display_rect().height() - GetMultilineTextSize().height());
861 if (vertical_alignment_ == ALIGN_VCENTER) 916 if (vertical_alignment_ == ALIGN_VCENTER)
862 offset.set_y(offset.y() / 2); 917 offset.set_y(offset.y() / 2);
863 } 918 }
864 return offset; 919 return offset;
865 } 920 }
866 921
867 void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) { 922 void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) {
868 if (!fade_head() && !fade_tail()) 923 if (multiline() || !fade_head() && !fade_tail())
869 return; 924 return;
870 925
871 const int text_width = GetStringSize().width();
872 const int display_width = display_rect().width(); 926 const int display_width = display_rect().width();
873 927
874 // If the text fits as-is, no need to fade. 928 // If the text fits as-is, no need to fade.
875 if (text_width <= display_width) 929 if (GetStringSize().width() <= display_width)
876 return; 930 return;
877 931
878 int gradient_width = CalculateFadeGradientWidth(GetFont(), display_width); 932 int gradient_width = CalculateFadeGradientWidth(GetFont(), display_width);
879 if (gradient_width == 0) 933 if (gradient_width == 0)
880 return; 934 return;
881 935
882 bool fade_left = fade_head(); 936 bool fade_left = fade_head();
883 bool fade_right = fade_tail(); 937 bool fade_right = fade_tail();
884 // Under RTL, |fade_right| == |fade_head|. 938 // Under RTL, |fade_right| == |fade_head|.
885 // TODO(asvitkine): This is currently not based on GetTextDirection() because 939 // TODO(asvitkine): This is currently not based on GetTextDirection() because
(...skipping 10 matching lines...) Expand all
896 left_part.Inset(0, 0, solid_part.width() - gradient_width, 0); 950 left_part.Inset(0, 0, solid_part.width() - gradient_width, 0);
897 solid_part.Inset(gradient_width, 0, 0, 0); 951 solid_part.Inset(gradient_width, 0, 0, 0);
898 } 952 }
899 if (fade_right) { 953 if (fade_right) {
900 right_part = solid_part; 954 right_part = solid_part;
901 right_part.Inset(solid_part.width() - gradient_width, 0, 0, 0); 955 right_part.Inset(solid_part.width() - gradient_width, 0, 0, 0);
902 solid_part.Inset(0, 0, gradient_width, 0); 956 solid_part.Inset(0, 0, gradient_width, 0);
903 } 957 }
904 958
905 Rect text_rect = display_rect(); 959 Rect text_rect = display_rect();
906 text_rect.Inset(GetAlignmentOffset().x(), 0, 0, 0); 960 text_rect.Inset(GetAlignmentOffset(0).x(), 0, 0, 0);
907 961
908 // TODO(msw): Use the actual text colors corresponding to each faded part. 962 // TODO(msw): Use the actual text colors corresponding to each faded part.
909 skia::RefPtr<SkShader> shader = CreateFadeShader( 963 skia::RefPtr<SkShader> shader = CreateFadeShader(
910 text_rect, left_part, right_part, colors_.breaks().front().second); 964 text_rect, left_part, right_part, colors_.breaks().front().second);
911 if (shader) 965 if (shader)
912 renderer->SetShader(shader.get(), display_rect()); 966 renderer->SetShader(shader.get(), display_rect());
913 } 967 }
914 968
915 void RenderText::ApplyTextShadows(internal::SkiaTextRenderer* renderer) { 969 void RenderText::ApplyTextShadows(internal::SkiaTextRenderer* renderer) {
916 skia::RefPtr<SkDrawLooper> looper = CreateShadowDrawLooper(text_shadows_); 970 skia::RefPtr<SkDrawLooper> looper = CreateShadowDrawLooper(text_shadows_);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
960 } 1014 }
961 } 1015 }
962 1016
963 const base::string16& text = obscured_ ? layout_text_ : text_; 1017 const base::string16& text = obscured_ ? layout_text_ : text_;
964 if (truncate_length_ > 0 && truncate_length_ < text.length()) { 1018 if (truncate_length_ > 0 && truncate_length_ < text.length()) {
965 // Truncate the text at a valid character break and append an ellipsis. 1019 // Truncate the text at a valid character break and append an ellipsis.
966 icu::StringCharacterIterator iter(text.c_str()); 1020 icu::StringCharacterIterator iter(text.c_str());
967 iter.setIndex32(truncate_length_ - 1); 1021 iter.setIndex32(truncate_length_ - 1);
968 layout_text_.assign(text.substr(0, iter.getIndex()) + ui::kEllipsisUTF16); 1022 layout_text_.assign(text.substr(0, iter.getIndex()) + ui::kEllipsisUTF16);
969 } 1023 }
1024
1025 line_breaks_.clear();
1026 base::i18n::BreakIterator iter(GetLayoutText(),
1027 base::i18n::BreakIterator::BREAK_LINE);
1028 bool success = iter.Init();
1029 CHECK(success);
1030 do {
1031 line_breaks_.push_back(iter.pos());
1032 } while (iter.Advance());
970 } 1033 }
971 1034
972 void RenderText::UpdateCachedBoundsAndOffset() { 1035 void RenderText::UpdateCachedBoundsAndOffset() {
973 if (cached_bounds_and_offset_valid_) 1036 if (cached_bounds_and_offset_valid_)
974 return; 1037 return;
975 1038
1039 // TODO(ckocagil): Add vertical offset support for scrolling multi-line text.
1040
976 // First, set the valid flag true to calculate the current cursor bounds using 1041 // First, set the valid flag true to calculate the current cursor bounds using
977 // the stale |display_offset_|. Applying |delta_offset| at the end of this 1042 // the stale |display_offset_|. Applying |delta_offset| at the end of this
978 // function will set |cursor_bounds_| and |display_offset_| to correct values. 1043 // function will set |cursor_bounds_| and |display_offset_| to correct values.
979 cached_bounds_and_offset_valid_ = true; 1044 cached_bounds_and_offset_valid_ = true;
980 cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_); 1045 cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_);
981 1046
982 // Update |display_offset_| to ensure the current cursor is visible. 1047 // Update |display_offset_| to ensure the current cursor is visible.
983 const int display_width = display_rect_.width(); 1048 const int display_width = display_rect_.width();
984 const int content_width = GetContentWidth(); 1049 const int content_width = GetContentWidth();
985 1050
(...skipping 30 matching lines...) Expand all
1016 cursor_bounds_ += delta_offset; 1081 cursor_bounds_ += delta_offset;
1017 } 1082 }
1018 1083
1019 void RenderText::DrawSelection(Canvas* canvas) { 1084 void RenderText::DrawSelection(Canvas* canvas) {
1020 const std::vector<Rect> sel = GetSubstringBounds(selection()); 1085 const std::vector<Rect> sel = GetSubstringBounds(selection());
1021 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i) 1086 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i)
1022 canvas->FillRect(*i, selection_background_focused_color_); 1087 canvas->FillRect(*i, selection_background_focused_color_);
1023 } 1088 }
1024 1089
1025 } // namespace gfx 1090 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698