Index: ui/gfx/render_text.cc |
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc |
index d3c6bea6ffe682b03d68e8e071f991769e5edaa8..25eeb7772f3d24b7e91594e7b626fc9d15000843 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. |
@@ -399,6 +401,7 @@ void RenderText::SetObscuredRevealIndex(int index) { |
void RenderText::SetDisplayRect(const Rect& r) { |
display_rect_ = r; |
cached_bounds_and_offset_valid_ = false; |
+ lines_valid_ = false; |
} |
void RenderText::SetCursorPosition(size_t position) { |
@@ -691,18 +694,52 @@ Rect RenderText::GetCursorBounds(const SelectionModel& caret, |
// since there is nothing to overtype. |
if ((GetTextDirection() == base::i18n::RIGHT_TO_LEFT) == (caret_pos == 0)) |
x = size.width(); |
- } else { |
- size_t grapheme_start = (caret_affinity == CURSOR_FORWARD) ? |
- caret_pos : IndexOfAdjacentGrapheme(caret_pos, CURSOR_BACKWARD); |
- ui::Range xspan(GetGlyphBounds(grapheme_start)); |
- if (insert_mode) { |
- x = (caret_affinity == CURSOR_BACKWARD) ? xspan.end() : xspan.start(); |
- } else { // overtype mode |
- x = xspan.GetMin(); |
- width = xspan.length(); |
+ } else { |
+ size_t grapheme_start = (caret_affinity == CURSOR_FORWARD) ? |
+ caret_pos : IndexOfAdjacentGrapheme(caret_pos, CURSOR_BACKWARD); |
+ ui::Range xspan(GetGlyphBounds(grapheme_start)); |
+ if (insert_mode) { |
+ x = (caret_affinity == CURSOR_BACKWARD) ? xspan.end() : xspan.start(); |
+ } else { // overtype mode |
+ x = xspan.GetMin(); |
+ width = xspan.length(); |
+ } |
+ } |
+ return Rect(ToViewPoint(Point(x, 0)), Size(width, size.height())); |
+} |
+ |
+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.
|
+ std::vector<Rect> rects; |
+ |
+ if (!multiline()) { |
+ Point start(x.GetMin(), 0); |
+ 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.
|
+ 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 Rect(ToViewPoint(Point(x, 0)), Size(width, size.height())); |
+ |
+ return rects; |
} |
const Rect& RenderText::GetUpdatedCursorBounds() { |
@@ -765,11 +802,13 @@ RenderText::RenderText() |
obscured_(false), |
obscured_reveal_index_(-1), |
truncate_length_(0), |
+ multiline_(false), |
fade_head_(false), |
fade_tail_(false), |
background_is_transparent_(false), |
clip_to_display_rect_(true), |
- cached_bounds_and_offset_valid_(false) { |
+ cached_bounds_and_offset_valid_(false), |
+ lines_valid_(false) { |
} |
const Vector2d& RenderText::GetUpdatedDisplayOffset() { |
@@ -834,30 +873,46 @@ void RenderText::UndoCompositionAndSelectionStyles() { |
composition_and_selection_styles_applied_ = false; |
} |
-Vector2d RenderText::GetTextOffset() { |
+Vector2d RenderText::GetLineOffset(int line) { |
Vector2d offset = display_rect().OffsetFromOrigin(); |
- offset.Add(GetUpdatedDisplayOffset()); |
- offset.Add(GetAlignmentOffset()); |
+ if (!multiline()) |
+ offset.Add(GetUpdatedDisplayOffset()); |
+ else |
+ 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
|
+ offset.Add(GetAlignmentOffset(line)); |
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_valid_); |
+ 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() { |
+Vector2d RenderText::GetAlignmentOffset(int line) { |
+ 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.
|
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); |
} |
@@ -865,14 +920,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(GetFont(), display_width); |
@@ -903,7 +957,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( |
@@ -967,12 +1021,23 @@ void RenderText::UpdateLayoutText() { |
iter.setIndex32(truncate_length_ - 1); |
layout_text_.assign(text.substr(0, iter.getIndex()) + ui::kEllipsisUTF16); |
} |
+ |
+ line_breaks_.clear(); |
+ base::i18n::BreakIterator iter(GetLayoutText(), |
+ base::i18n::BreakIterator::BREAK_LINE); |
+ bool success = iter.Init(); |
+ CHECK(success); |
+ do { |
+ line_breaks_.push_back(iter.pos()); |
+ } while (iter.Advance()); |
} |
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. |