Index: ui/gfx/render_text.cc |
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc |
index 1fcf18cede44fce180c344fe8bef925595ee935e..3a56f83fa6e28c47ed638129630502f56ff4b08b 100644 |
--- a/ui/gfx/render_text.cc |
+++ b/ui/gfx/render_text.cc |
@@ -301,6 +301,10 @@ void StyleIterator::UpdatePosition(size_t position) { |
style_[i] = styles_[i].GetBreak(position); |
} |
+LineSegment::LineSegment() : run(0) {} |
+ |
+Line::Line() : preceding_heights(0), baseline(0) {} |
+ |
} // namespace internal |
RenderText::~RenderText() { |
@@ -308,6 +312,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. |
@@ -394,9 +400,18 @@ void RenderText::SetObscuredRevealIndex(int index) { |
ResetLayout(); |
} |
+void RenderText::SetMultiline(bool multiline) { |
+ if (multiline != multiline_) { |
+ multiline_ = multiline; |
+ cached_bounds_and_offset_valid_ = false; |
+ lines_.clear(); |
+ } |
+} |
+ |
void RenderText::SetDisplayRect(const Rect& r) { |
display_rect_ = r; |
cached_bounds_and_offset_valid_ = false; |
+ lines_.clear(); |
} |
void RenderText::SetCursorPosition(size_t position) { |
@@ -684,6 +699,9 @@ void RenderText::DrawSelectedTextForDrag(Canvas* canvas) { |
set_background_is_transparent(saved_background_is_transparent); |
} |
+// TODO(ckocagil): Support multi-line. This function should return the height of |
msw
2013/09/06 23:47:45
nit: move this comment inside the function or to t
ckocagil
2013/09/11 14:59:49
Done, moved inside the function.
|
+// the line the cursor is on. |GetStringSize()| now returns the |
+// multi-line size, eliminate its use here. |
Rect RenderText::GetCursorBounds(const SelectionModel& caret, |
bool insert_mode) { |
EnsureLayout(); |
@@ -775,6 +793,7 @@ RenderText::RenderText() |
obscured_(false), |
obscured_reveal_index_(-1), |
truncate_length_(0), |
+ multiline_(false), |
fade_head_(false), |
fade_tail_(false), |
background_is_transparent_(false), |
@@ -818,6 +837,26 @@ const base::string16& RenderText::GetLayoutText() const { |
return layout_text_.empty() ? text_ : layout_text_; |
} |
+const BreakList<size_t>& RenderText::GetLineBreaks() { |
+ if (line_breaks_.max() != 0) |
+ return line_breaks_; |
+ |
+ const string16& layout_text = GetLayoutText(); |
+ const size_t text_length = layout_text.length(); |
+ line_breaks_.SetValue(0); |
+ line_breaks_.SetMax(text_length); |
+ base::i18n::BreakIterator iter(layout_text, |
+ base::i18n::BreakIterator::BREAK_LINE); |
msw
2013/09/06 23:47:45
nit: out-dent one space.
ckocagil
2013/09/11 14:59:49
Done.
|
+ bool success = iter.Init(); |
msw
2013/09/06 23:47:45
nit: const.
ckocagil
2013/09/11 14:59:49
Done.
|
+ DCHECK(success); |
+ if (success) { |
msw
2013/09/06 23:47:45
optional: I think the first break would always be
ckocagil
2013/09/11 14:59:49
I would rather keep the explicit if block.
|
+ do { |
+ line_breaks_.ApplyValue(iter.pos(), ui::Range(iter.pos(), 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_); |
@@ -844,25 +883,75 @@ 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()); |
msw
2013/09/06 23:47:45
Shouldn't it be okay to add the display offset eve
ckocagil
2013/09/11 14:59:49
I'm disabling it in multiline because I need to te
msw
2013/09/11 17:32:37
I think an additional TODO here would help call ou
ckocagil
2013/09/11 20:31:15
Done.
|
+ 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. |
msw
2013/09/06 23:47:45
nit: capitalize "Implement", consider expanding th
ckocagil
2013/09/11 14:59:49
Done.
|
} |
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. |
msw
2013/09/06 23:47:45
nit: capitalize 'Refactor' and 'RTL'; consider:
//
ckocagil
2013/09/11 14:59:49
Done.
|
+ DCHECK(!lines_.empty()); |
+ int x = point.x(); |
+ size_t line = 0; |
+ while (line < lines_.size() && x > lines_[line].size.width()) { |
msw
2013/09/06 23:47:45
Optionally, you could do:
for (line = 0; line < li
ckocagil
2013/09/11 14:59:49
Done.
|
+ x -= lines_[line].size.width(); |
+ ++line; |
+ } |
+ return Point(x, point.y()) + GetLineOffset(line); |
+} |
+ |
+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 segment 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); |
msw
2013/09/06 23:47:45
nit: const
ckocagil
2013/09/11 14:59:49
Done.
|
+ for (size_t i = 0; i < lines_[line].segments.size(); ++i) { |
+ const internal::LineSegment* segment = &lines_[line].segments[i]; |
+ const ui::Range intersection = segment->x_range.Intersect(x); |
+ if (!intersection.is_empty()) { |
+ Rect rect(line_x + intersection.start() - segment->x_range.start(), |
+ 0, intersection.length(), lines_[line].size.height()); |
+ rects.push_back(rect + offset); |
+ } |
+ line_x += segment->x_range.length(); |
+ } |
+ } |
+ |
+ return rects; |
} |
-Vector2d RenderText::GetAlignmentOffset() { |
+Vector2d RenderText::GetAlignmentOffset(size_t line_number) { |
+ DCHECK_LT(line_number, lines_.size()); |
Vector2d offset; |
if (horizontal_alignment_ != ALIGN_LEFT) { |
- offset.set_x(display_rect().width() - GetContentWidth()); |
+ const int width = lines_[line_number].size.width() + |
+ (cursor_enabled_ ? 1 : 0); |
+ offset.set_x(display_rect().width() - width); |
if (horizontal_alignment_ == ALIGN_CENTER) |
offset.set_x(offset.x() / 2); |
} |
@@ -875,14 +964,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(), |
@@ -914,7 +1002,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( |
@@ -948,6 +1036,7 @@ void RenderText::MoveCursorTo(size_t position, bool select) { |
void RenderText::UpdateLayoutText() { |
layout_text_.clear(); |
+ line_breaks_.SetMax(0); |
if (obscured_) { |
size_t obscured_text_length = |
@@ -984,6 +1073,8 @@ void RenderText::UpdateCachedBoundsAndOffset() { |
if (cached_bounds_and_offset_valid_) |
return; |
+ // TODO(ckocagil): Add vertical offset support for scrolling multi-line text. |
msw
2013/09/06 23:47:45
nit: Address my GetLineOffset comment or remove "V
ckocagil
2013/09/11 14:59:49
Done, removed "vertical".
|
+ |
// 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. |