| Index: ui/gfx/render_text.cc
|
| diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc
|
| index 14bdcfa93cbe5194debc6e005416df6a77de0bf2..991fc30882358191f46d76c73319ce4d83848083 100644
|
| --- a/ui/gfx/render_text.cc
|
| +++ b/ui/gfx/render_text.cc
|
| @@ -308,6 +308,8 @@ RenderText::~RenderText() {
|
|
|
| void RenderText::SetText(const base::string16& text) {
|
| DCHECK(!composition_range_.IsValid());
|
| + if (text_ == text)
|
| + return;
|
| text_ = text;
|
|
|
| // Adjust ranged styles and colors to accommodate a new text length.
|
| @@ -384,6 +386,14 @@ void RenderText::SetObscured(bool obscured) {
|
| }
|
| }
|
|
|
| +void RenderText::SetMultiline(bool multiline) {
|
| + if (multiline != multiline_) {
|
| + multiline_ = multiline;
|
| + cached_bounds_and_offset_valid_ = false;
|
| + ResetLayout();
|
| + }
|
| +}
|
| +
|
| void RenderText::SetObscuredRevealIndex(int index) {
|
| if (obscured_reveal_index_ == index)
|
| return;
|
| @@ -397,6 +407,7 @@ void RenderText::SetObscuredRevealIndex(int index) {
|
| void RenderText::SetDisplayRect(const Rect& r) {
|
| display_rect_ = r;
|
| cached_bounds_and_offset_valid_ = false;
|
| + lines_.clear();
|
| }
|
|
|
| void RenderText::SetCursorPosition(size_t position) {
|
| @@ -763,6 +774,7 @@ RenderText::RenderText()
|
| obscured_(false),
|
| obscured_reveal_index_(-1),
|
| truncate_length_(0),
|
| + multiline_(false),
|
| fade_head_(false),
|
| fade_tail_(false),
|
| background_is_transparent_(false),
|
| @@ -806,6 +818,23 @@ const base::string16& RenderText::GetLayoutText() const {
|
| return layout_text_.empty() ? text_ : layout_text_;
|
| }
|
|
|
| +const BreakList<size_t>& RenderText::GetLineBreaks() {
|
| + if (line_breaks_.max() == 0) {
|
| + const string16& layout_text = GetLayoutText();
|
| + line_breaks_.SetValue(0);
|
| + line_breaks_.SetMax(layout_text.length());
|
| + base::i18n::BreakIterator iter(layout_text,
|
| + base::i18n::BreakIterator::BREAK_LINE);
|
| + bool success = iter.Init();
|
| + CHECK(success);
|
| + do {
|
| + line_breaks_.ApplyValue(iter.pos(), ui::Range(iter.pos(),
|
| + layout_text.length()));
|
| + } while (iter.Advance());
|
| + }
|
| + return line_breaks_;
|
| +}
|
| +
|
| void RenderText::ApplyCompositionAndSelectionStyles() {
|
| // Save the underline and color breaks to undo the temporary styles later.
|
| DCHECK(!composition_and_selection_styles_applied_);
|
| @@ -832,30 +861,81 @@ void RenderText::UndoCompositionAndSelectionStyles() {
|
| composition_and_selection_styles_applied_ = false;
|
| }
|
|
|
| -Vector2d RenderText::GetTextOffset() {
|
| +Vector2d RenderText::GetLineOffset(size_t line_number) {
|
| Vector2d offset = display_rect().OffsetFromOrigin();
|
| - offset.Add(GetUpdatedDisplayOffset());
|
| - offset.Add(GetAlignmentOffset());
|
| + if (!multiline())
|
| + offset.Add(GetUpdatedDisplayOffset());
|
| + else
|
| + offset.Add(Vector2d(0, lines()[line_number].preceding_heights));
|
| + offset.Add(GetAlignmentOffset(line_number));
|
| return offset;
|
| }
|
|
|
| Point RenderText::ToTextPoint(const Point& point) {
|
| - return point - GetTextOffset();
|
| + return point - GetLineOffset(0);
|
| + // TODO(ckocagil): implement multiline.
|
| }
|
|
|
| Point RenderText::ToViewPoint(const Point& point) {
|
| - return point + GetTextOffset();
|
| + if (!multiline())
|
| + return point + GetLineOffset(0);
|
| +
|
| + // TODO(ckocagil): refactor this to traverse all line segments to support rtl.
|
| + DCHECK(!lines_.empty());
|
| + int x = point.x();
|
| + unsigned int line = 0;
|
| + while (line < lines_.size() && x > lines()[line].width) {
|
| + x -= lines()[line].width;
|
| + ++line;
|
| + }
|
| + return Point(x, point.y()) + GetLineOffset(line);
|
| }
|
|
|
| -Vector2d RenderText::GetAlignmentOffset() {
|
| +std::vector<Rect> RenderText::TextBoundsToViewBounds(const ui::Range& x) {
|
| + std::vector<Rect> rects;
|
| +
|
| + if (!multiline()) {
|
| + rects.push_back(Rect(ToViewPoint(Point(x.GetMin(), 0)),
|
| + Size(x.length(), GetStringSize().height())));
|
| + return rects;
|
| + }
|
| +
|
| + EnsureLayout();
|
| +
|
| + // Each line segments keeps its position in text coordinates. Traverse all
|
| + // line segments and if the segment intersects with the given range, add the
|
| + // view rect corresponding to the intersection to |rects|.
|
| + for (size_t line = 0; line < lines().size(); ++line) {
|
| + int line_x = 0;
|
| + Vector2d offset = GetLineOffset(line);
|
| + for (size_t i = 0; i < lines()[line].segments.size(); ++i) {
|
| + const internal::LineSegment* segment = lines()[line].segments[i];
|
| + ui::Range intersection = segment->x_pos.Intersect(x);
|
| + if (!intersection.is_empty()) {
|
| + Rect rect(line_x + intersection.start() - segment->x_pos.start(),
|
| + 0, intersection.length(), lines()[line].height);
|
| + rect += offset;
|
| + rects.push_back(rect);
|
| + }
|
| + line_x += segment->x_pos.length();
|
| + }
|
| + }
|
| +
|
| + return rects;
|
| +}
|
| +
|
| +
|
| +Vector2d RenderText::GetAlignmentOffset(size_t line_number) {
|
| + DCHECK(!lines_.empty());
|
| + const int width = lines()[line_number].width;
|
| Vector2d offset;
|
| if (horizontal_alignment_ != ALIGN_LEFT) {
|
| - offset.set_x(display_rect().width() - GetContentWidth());
|
| + offset.set_x(display_rect().width() - width);
|
| if (horizontal_alignment_ == ALIGN_CENTER)
|
| offset.set_x(offset.x() / 2);
|
| }
|
| if (vertical_alignment_ != ALIGN_TOP) {
|
| - offset.set_y(display_rect().height() - GetStringSize().height());
|
| + offset.set_y(display_rect().height() - GetMultilineTextSize().height());
|
| if (vertical_alignment_ == ALIGN_VCENTER)
|
| offset.set_y(offset.y() / 2);
|
| }
|
| @@ -863,14 +943,13 @@ Vector2d RenderText::GetAlignmentOffset() {
|
| }
|
|
|
| void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) {
|
| - if (!fade_head() && !fade_tail())
|
| + if (multiline() || !fade_head() && !fade_tail())
|
| return;
|
|
|
| - const int text_width = GetStringSize().width();
|
| const int display_width = display_rect().width();
|
|
|
| // If the text fits as-is, no need to fade.
|
| - if (text_width <= display_width)
|
| + if (GetStringSize().width() <= display_width)
|
| return;
|
|
|
| int gradient_width = CalculateFadeGradientWidth(GetPrimaryFont(),
|
| @@ -902,7 +981,7 @@ void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) {
|
| }
|
|
|
| Rect text_rect = display_rect();
|
| - text_rect.Inset(GetAlignmentOffset().x(), 0, 0, 0);
|
| + text_rect.Inset(GetAlignmentOffset(0).x(), 0, 0, 0);
|
|
|
| // TODO(msw): Use the actual text colors corresponding to each faded part.
|
| skia::RefPtr<SkShader> shader = CreateFadeShader(
|
| @@ -966,12 +1045,16 @@ void RenderText::UpdateLayoutText() {
|
| iter.setIndex32(truncate_length_ - 1);
|
| layout_text_.assign(text.substr(0, iter.getIndex()) + ui::kEllipsisUTF16);
|
| }
|
| +
|
| + line_breaks_.SetMax(0);
|
| }
|
|
|
| void RenderText::UpdateCachedBoundsAndOffset() {
|
| if (cached_bounds_and_offset_valid_)
|
| return;
|
|
|
| + // TODO(ckocagil): Add vertical offset support for scrolling multi-line text.
|
| +
|
| // First, set the valid flag true to calculate the current cursor bounds using
|
| // the stale |display_offset_|. Applying |delta_offset| at the end of this
|
| // function will set |cursor_bounds_| and |display_offset_| to correct values.
|
|
|