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

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: rebased 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 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 UpdateLayoutText(); 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;
402 lines_.clear();
400 } 403 }
401 404
402 void RenderText::SetCursorPosition(size_t position) { 405 void RenderText::SetCursorPosition(size_t position) {
403 MoveCursorTo(position, false); 406 MoveCursorTo(position, false);
404 } 407 }
405 408
406 void RenderText::MoveCursor(BreakType break_type, 409 void RenderText::MoveCursor(BreakType break_type,
407 VisualCursorDirection direction, 410 VisualCursorDirection direction,
408 bool select) { 411 bool select) {
409 SelectionModel position(cursor_position(), selection_model_.caret_affinity()); 412 SelectionModel position(cursor_position(), selection_model_.caret_affinity());
(...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after
756 selection_color_(kDefaultColor), 759 selection_color_(kDefaultColor),
757 selection_background_focused_color_(kDefaultSelectionBackgroundColor), 760 selection_background_focused_color_(kDefaultSelectionBackgroundColor),
758 focused_(false), 761 focused_(false),
759 composition_range_(ui::Range::InvalidRange()), 762 composition_range_(ui::Range::InvalidRange()),
760 colors_(kDefaultColor), 763 colors_(kDefaultColor),
761 styles_(NUM_TEXT_STYLES), 764 styles_(NUM_TEXT_STYLES),
762 composition_and_selection_styles_applied_(false), 765 composition_and_selection_styles_applied_(false),
763 obscured_(false), 766 obscured_(false),
764 obscured_reveal_index_(-1), 767 obscured_reveal_index_(-1),
765 truncate_length_(0), 768 truncate_length_(0),
769 multiline_(false),
766 fade_head_(false), 770 fade_head_(false),
767 fade_tail_(false), 771 fade_tail_(false),
768 background_is_transparent_(false), 772 background_is_transparent_(false),
769 clip_to_display_rect_(true), 773 clip_to_display_rect_(true),
770 cached_bounds_and_offset_valid_(false) { 774 cached_bounds_and_offset_valid_(false) {
771 } 775 }
772 776
773 const Vector2d& RenderText::GetUpdatedDisplayOffset() { 777 const Vector2d& RenderText::GetUpdatedDisplayOffset() {
774 UpdateCachedBoundsAndOffset(); 778 UpdateCachedBoundsAndOffset();
775 return display_offset_; 779 return display_offset_;
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
825 } 829 }
826 830
827 void RenderText::UndoCompositionAndSelectionStyles() { 831 void RenderText::UndoCompositionAndSelectionStyles() {
828 // Restore the underline and color breaks to undo the temporary styles. 832 // Restore the underline and color breaks to undo the temporary styles.
829 DCHECK(composition_and_selection_styles_applied_); 833 DCHECK(composition_and_selection_styles_applied_);
830 colors_ = saved_colors_; 834 colors_ = saved_colors_;
831 styles_[UNDERLINE] = saved_underlines_; 835 styles_[UNDERLINE] = saved_underlines_;
832 composition_and_selection_styles_applied_ = false; 836 composition_and_selection_styles_applied_ = false;
833 } 837 }
834 838
835 Vector2d RenderText::GetTextOffset() { 839 Vector2d RenderText::GetLineOffset(size_t line_number) {
836 Vector2d offset = display_rect().OffsetFromOrigin(); 840 Vector2d offset = display_rect().OffsetFromOrigin();
837 offset.Add(GetUpdatedDisplayOffset()); 841 if (!multiline())
838 offset.Add(GetAlignmentOffset()); 842 offset.Add(GetUpdatedDisplayOffset());
843 else
844 offset.Add(Vector2d(0, lines()[line_number].preceding_heights));
845 offset.Add(GetAlignmentOffset(line_number));
839 return offset; 846 return offset;
840 } 847 }
841 848
842 Point RenderText::ToTextPoint(const Point& point) { 849 Point RenderText::ToTextPoint(const Point& point) {
843 return point - GetTextOffset(); 850 return point - GetLineOffset(0);
851 // TODO(ckocagil): implement multiline.
844 } 852 }
845 853
846 Point RenderText::ToViewPoint(const Point& point) { 854 Point RenderText::ToViewPoint(const Point& point) {
847 return point + GetTextOffset(); 855 if (!multiline())
856 return point + GetLineOffset(0);
857
858 // TODO(ckocagil): refactor this to traverse all line segments to support rtl.
859 DCHECK(!lines_.empty());
860 int x = point.x();
861 unsigned int line = 0;
862 while (line < lines_.size() && x > lines()[line].width) {
863 x -= lines()[line].width;
864 ++line;
865 }
866 return Point(x, point.y()) + GetLineOffset(line);
848 } 867 }
849 868
850 Vector2d RenderText::GetAlignmentOffset() { 869 std::vector<Rect> RenderText::TextBoundsToViewBounds(const ui::Range& x) {
870 std::vector<Rect> rects;
871
872 if (!multiline()) {
873 rects.push_back(Rect(ToViewPoint(Point(x.GetMin(), 0)),
874 Size(x.length(), GetStringSize().height())));
875 return rects;
876 }
877
878 EnsureLayout();
879
880 // Each line segments keeps its position in text coordinates. Traverse all
881 // line segments and if the segment intersects with the given range, add the
882 // view rect corresponding to the intersection to |rects|.
883 for (size_t line = 0; line < lines().size(); ++line) {
884 int line_x = 0;
885 Vector2d offset = GetLineOffset(line);
886 for (size_t i = 0; i < lines()[line].segments.size(); ++i) {
887 const internal::LineSegment* segment = lines()[line].segments[i];
888 ui::Range intersection = segment->x_pos.Intersect(x);
889 if (!intersection.is_empty()) {
890 Rect rect(line_x + intersection.start() - segment->x_pos.start(),
891 0, intersection.length(), lines()[line].height);
892 rect += offset;
893 rects.push_back(rect);
894 }
895 line_x += segment->x_pos.length();
896 }
897 }
898
899 return rects;
900 }
901
902
903 Vector2d RenderText::GetAlignmentOffset(size_t line_number) {
904 DCHECK(!lines_.empty());
905 const int width = lines()[line_number].width;
851 Vector2d offset; 906 Vector2d offset;
852 if (horizontal_alignment_ != ALIGN_LEFT) { 907 if (horizontal_alignment_ != ALIGN_LEFT) {
853 offset.set_x(display_rect().width() - GetContentWidth()); 908 offset.set_x(display_rect().width() - width);
854 if (horizontal_alignment_ == ALIGN_CENTER) 909 if (horizontal_alignment_ == ALIGN_CENTER)
855 offset.set_x(offset.x() / 2); 910 offset.set_x(offset.x() / 2);
856 } 911 }
857 if (vertical_alignment_ != ALIGN_TOP) { 912 if (vertical_alignment_ != ALIGN_TOP) {
858 offset.set_y(display_rect().height() - GetStringSize().height()); 913 offset.set_y(display_rect().height() - GetMultilineTextSize().height());
859 if (vertical_alignment_ == ALIGN_VCENTER) 914 if (vertical_alignment_ == ALIGN_VCENTER)
860 offset.set_y(offset.y() / 2); 915 offset.set_y(offset.y() / 2);
861 } 916 }
862 return offset; 917 return offset;
863 } 918 }
864 919
865 void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) { 920 void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) {
866 if (!fade_head() && !fade_tail()) 921 if (multiline() || !fade_head() && !fade_tail())
867 return; 922 return;
868 923
869 const int text_width = GetStringSize().width();
870 const int display_width = display_rect().width(); 924 const int display_width = display_rect().width();
871 925
872 // If the text fits as-is, no need to fade. 926 // If the text fits as-is, no need to fade.
873 if (text_width <= display_width) 927 if (GetStringSize().width() <= display_width)
874 return; 928 return;
875 929
876 int gradient_width = CalculateFadeGradientWidth(GetFont(), display_width); 930 int gradient_width = CalculateFadeGradientWidth(GetFont(), display_width);
877 if (gradient_width == 0) 931 if (gradient_width == 0)
878 return; 932 return;
879 933
880 bool fade_left = fade_head(); 934 bool fade_left = fade_head();
881 bool fade_right = fade_tail(); 935 bool fade_right = fade_tail();
882 // Under RTL, |fade_right| == |fade_head|. 936 // Under RTL, |fade_right| == |fade_head|.
883 // TODO(asvitkine): This is currently not based on GetTextDirection() because 937 // TODO(asvitkine): This is currently not based on GetTextDirection() because
(...skipping 10 matching lines...) Expand all
894 left_part.Inset(0, 0, solid_part.width() - gradient_width, 0); 948 left_part.Inset(0, 0, solid_part.width() - gradient_width, 0);
895 solid_part.Inset(gradient_width, 0, 0, 0); 949 solid_part.Inset(gradient_width, 0, 0, 0);
896 } 950 }
897 if (fade_right) { 951 if (fade_right) {
898 right_part = solid_part; 952 right_part = solid_part;
899 right_part.Inset(solid_part.width() - gradient_width, 0, 0, 0); 953 right_part.Inset(solid_part.width() - gradient_width, 0, 0, 0);
900 solid_part.Inset(0, 0, gradient_width, 0); 954 solid_part.Inset(0, 0, gradient_width, 0);
901 } 955 }
902 956
903 Rect text_rect = display_rect(); 957 Rect text_rect = display_rect();
904 text_rect.Inset(GetAlignmentOffset().x(), 0, 0, 0); 958 text_rect.Inset(GetAlignmentOffset(0).x(), 0, 0, 0);
905 959
906 // TODO(msw): Use the actual text colors corresponding to each faded part. 960 // TODO(msw): Use the actual text colors corresponding to each faded part.
907 skia::RefPtr<SkShader> shader = CreateFadeShader( 961 skia::RefPtr<SkShader> shader = CreateFadeShader(
908 text_rect, left_part, right_part, colors_.breaks().front().second); 962 text_rect, left_part, right_part, colors_.breaks().front().second);
909 if (shader) 963 if (shader)
910 renderer->SetShader(shader.get(), display_rect()); 964 renderer->SetShader(shader.get(), display_rect());
911 } 965 }
912 966
913 void RenderText::ApplyTextShadows(internal::SkiaTextRenderer* renderer) { 967 void RenderText::ApplyTextShadows(internal::SkiaTextRenderer* renderer) {
914 skia::RefPtr<SkDrawLooper> looper = CreateShadowDrawLooper(text_shadows_); 968 skia::RefPtr<SkDrawLooper> looper = CreateShadowDrawLooper(text_shadows_);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
958 } 1012 }
959 } 1013 }
960 1014
961 const base::string16& text = obscured_ ? layout_text_ : text_; 1015 const base::string16& text = obscured_ ? layout_text_ : text_;
962 if (truncate_length_ > 0 && truncate_length_ < text.length()) { 1016 if (truncate_length_ > 0 && truncate_length_ < text.length()) {
963 // Truncate the text at a valid character break and append an ellipsis. 1017 // Truncate the text at a valid character break and append an ellipsis.
964 icu::StringCharacterIterator iter(text.c_str()); 1018 icu::StringCharacterIterator iter(text.c_str());
965 iter.setIndex32(truncate_length_ - 1); 1019 iter.setIndex32(truncate_length_ - 1);
966 layout_text_.assign(text.substr(0, iter.getIndex()) + ui::kEllipsisUTF16); 1020 layout_text_.assign(text.substr(0, iter.getIndex()) + ui::kEllipsisUTF16);
967 } 1021 }
1022
1023 const string16& layout_text = GetLayoutText();
1024 line_breaks_.SetValue(0);
1025 line_breaks_.SetMax(layout_text.length());
1026 base::i18n::BreakIterator iter(layout_text,
1027 base::i18n::BreakIterator::BREAK_LINE);
Alexei Svitkine (slow) 2013/07/22 20:52:05 There's a comment in download_item_view.cc that BR
ckocagil 2013/08/07 12:59:20 Done, it's completely lazy now.
1028 bool success = iter.Init();
1029 CHECK(success);
1030 do {
1031 line_breaks_.ApplyValue(iter.pos(),
1032 ui::Range(iter.pos(), layout_text.length()));
1033 } while (iter.Advance());
968 } 1034 }
969 1035
970 void RenderText::UpdateCachedBoundsAndOffset() { 1036 void RenderText::UpdateCachedBoundsAndOffset() {
971 if (cached_bounds_and_offset_valid_) 1037 if (cached_bounds_and_offset_valid_)
972 return; 1038 return;
973 1039
1040 // TODO(ckocagil): Add vertical offset support for scrolling multi-line text.
1041
974 // First, set the valid flag true to calculate the current cursor bounds using 1042 // First, set the valid flag true to calculate the current cursor bounds using
975 // the stale |display_offset_|. Applying |delta_offset| at the end of this 1043 // the stale |display_offset_|. Applying |delta_offset| at the end of this
976 // function will set |cursor_bounds_| and |display_offset_| to correct values. 1044 // function will set |cursor_bounds_| and |display_offset_| to correct values.
977 cached_bounds_and_offset_valid_ = true; 1045 cached_bounds_and_offset_valid_ = true;
978 cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_); 1046 cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_);
979 1047
980 // Update |display_offset_| to ensure the current cursor is visible. 1048 // Update |display_offset_| to ensure the current cursor is visible.
981 const int display_width = display_rect_.width(); 1049 const int display_width = display_rect_.width();
982 const int content_width = GetContentWidth(); 1050 const int content_width = GetContentWidth();
983 1051
(...skipping 30 matching lines...) Expand all
1014 cursor_bounds_ += delta_offset; 1082 cursor_bounds_ += delta_offset;
1015 } 1083 }
1016 1084
1017 void RenderText::DrawSelection(Canvas* canvas) { 1085 void RenderText::DrawSelection(Canvas* canvas) {
1018 const std::vector<Rect> sel = GetSubstringBounds(selection()); 1086 const std::vector<Rect> sel = GetSubstringBounds(selection());
1019 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i) 1087 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i)
1020 canvas->FillRect(*i, selection_background_focused_color_); 1088 canvas->FillRect(*i, selection_background_focused_color_);
1021 } 1089 }
1022 1090
1023 } // namespace gfx 1091 } // 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.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698