Index: ui/gfx/render_text.cc |
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc |
index fce00b589bde6b241fb900d7c6efe8b58e815043..2855a072205a3ea668a9b8397b0a154604357311 100644 |
--- a/ui/gfx/render_text.cc |
+++ b/ui/gfx/render_text.cc |
@@ -130,10 +130,6 @@ void SelectionModel::Init(size_t start, |
RenderText::~RenderText() { |
} |
-void RenderText::set_display_rect(const Rect& r) { |
- display_rect_ = r; |
-} |
- |
void RenderText::SetText(const string16& text) { |
size_t old_text_length = text_.length(); |
text_ = text; |
@@ -161,6 +157,7 @@ void RenderText::SetText(const string16& text) { |
#ifndef NDEBUG |
CheckStyleRanges(style_ranges_, text_.length()); |
#endif |
+ cached_bounds_and_offset_valid_ = false; |
} |
void RenderText::SetSelectionModel(const SelectionModel& sel) { |
@@ -171,7 +168,12 @@ void RenderText::SetSelectionModel(const SelectionModel& sel) { |
selection_model_.set_caret_pos(std::min(sel.caret_pos(), text().length())); |
selection_model_.set_caret_placement(sel.caret_placement()); |
- cursor_bounds_valid_ = false; |
+ cached_bounds_and_offset_valid_ = false; |
+} |
+ |
+void RenderText::SetDisplayRect(const Rect& r) { |
+ display_rect_ = r; |
+ cached_bounds_and_offset_valid_ = false; |
} |
size_t RenderText::GetCursorPosition() const { |
@@ -328,8 +330,8 @@ void RenderText::ApplyStyleRange(StyleRange style_range) { |
#ifndef NDEBUG |
CheckStyleRanges(style_ranges_, text_.length()); |
#endif |
- // TODO(xji): only invalidate cursor_bounds if font or underline change. |
- cursor_bounds_valid_ = false; |
+ // TODO(xji): only invalidate if font or underline changes. |
+ cached_bounds_and_offset_valid_ = false; |
} |
void RenderText::ApplyDefaultStyle() { |
@@ -337,7 +339,7 @@ void RenderText::ApplyDefaultStyle() { |
StyleRange style = StyleRange(default_style_); |
style.range.set_end(text_.length()); |
style_ranges_.push_back(style); |
- cursor_bounds_valid_ = false; |
+ cached_bounds_and_offset_valid_ = false; |
} |
base::i18n::TextDirection RenderText::GetTextDirection() const { |
@@ -347,7 +349,7 @@ base::i18n::TextDirection RenderText::GetTextDirection() const { |
} |
int RenderText::GetStringWidth() { |
- return GetSubstringBounds(0, text_.length())[0].width(); |
+ return default_style_.font.GetStringWidth(text()); |
} |
void RenderText::Draw(Canvas* canvas) { |
@@ -363,10 +365,6 @@ void RenderText::Draw(Canvas* canvas) { |
for (std::vector<Rect>::const_iterator i = selection.begin(); |
i < selection.end(); ++i) { |
Rect r(*i); |
- r.Offset(display_rect_.origin()); |
- r.Offset(display_offset_); |
- // Center the rect vertically in |display_rect_|. |
- r.Offset(Point(0, (display_rect_.height() - r.height()) / 2)); |
canvas->FillRectInt(selection_color, r.x(), r.y(), r.width(), r.height()); |
} |
@@ -376,7 +374,7 @@ void RenderText::Draw(Canvas* canvas) { |
// Draw the text. |
Rect bounds(display_rect_); |
- bounds.Offset(display_offset_); |
+ bounds.Offset(GetUpdatedDisplayOffset()); |
for (StyleRanges::const_iterator i = style_ranges.begin(); |
i < style_ranges.end(); ++i) { |
const Font& font = !i->underline ? i->font : |
@@ -403,16 +401,10 @@ void RenderText::Draw(Canvas* canvas) { |
} |
// Paint cursor. Replace cursor is drawn as rectangle for now. |
- if (cursor_visible() && focused()) { |
- bounds = CursorBounds(); |
- bounds.Offset(display_offset_); |
- if (!bounds.IsEmpty()) |
- canvas->DrawRectInt(kCursorColor, |
- bounds.x(), |
- bounds.y(), |
- bounds.width(), |
- bounds.height()); |
- } |
+ Rect cursor(GetUpdatedCursorBounds()); |
+ if (cursor_visible() && focused() && !cursor.IsEmpty()) |
+ canvas->DrawRectInt(kCursorColor, cursor.x(), cursor.y(), |
+ cursor.width(), cursor.height()); |
} |
SelectionModel RenderText::FindCursorPosition(const Point& point) { |
@@ -422,7 +414,7 @@ SelectionModel RenderText::FindCursorPosition(const Point& point) { |
int right = font.GetStringWidth(text()); |
int right_pos = text().length(); |
- int x = point.x(); |
+ int x = point.x() - (display_rect_.x() + GetUpdatedDisplayOffset().x()); |
if (x <= left) return SelectionModel(left_pos); |
if (x >= right) return SelectionModel(right_pos); |
// binary searching the cursor position. |
@@ -444,36 +436,29 @@ SelectionModel RenderText::FindCursorPosition(const Point& point) { |
return SelectionModel(left_pos); |
} |
-std::vector<Rect> RenderText::GetSubstringBounds( |
- size_t from, size_t to) const { |
+std::vector<Rect> RenderText::GetSubstringBounds(size_t from, size_t to) { |
size_t start = std::min(from, to); |
size_t end = std::max(from, to); |
const Font& font = default_style_.font; |
int start_x = font.GetStringWidth(text().substr(0, start)); |
int end_x = font.GetStringWidth(text().substr(0, end)); |
- std::vector<Rect> bounds; |
- bounds.push_back(Rect(start_x, 0, end_x - start_x, font.GetHeight())); |
- return bounds; |
+ Rect rect(start_x, 0, end_x - start_x, font.GetHeight()); |
+ rect.Offset(display_rect_.origin()); |
+ rect.Offset(GetUpdatedDisplayOffset()); |
+ // Center the rect vertically in |display_rect_|. |
+ rect.Offset(Point(0, (display_rect_.height() - rect.height()) / 2)); |
+ return std::vector<Rect>(1, rect); |
} |
Rect RenderText::GetCursorBounds(const SelectionModel& selection, |
bool insert_mode) { |
- size_t cursor_pos = selection.selection_end(); |
- const Font& font = default_style_.font; |
- int x = font.GetStringWidth(text_.substr(0U, cursor_pos)); |
- DCHECK_GE(x, 0); |
- int h = std::min(display_rect_.height(), font.GetHeight()); |
- Rect bounds(x, (display_rect_.height() - h) / 2, 1, h); |
- if (!insert_mode && text_.length() != cursor_pos) |
- bounds.set_width(font.GetStringWidth(text_.substr(0, cursor_pos + 1)) - x); |
- return bounds; |
-} |
- |
-const Rect& RenderText::CursorBounds() { |
- if (cursor_bounds_valid_ == false) { |
- UpdateCursorBoundsAndDisplayOffset(); |
- cursor_bounds_valid_ = true; |
- } |
+ size_t from = selection.selection_end(); |
+ size_t to = insert_mode ? from : std::min(text_.length(), from + 1); |
+ return GetSubstringBounds(from, to)[0]; |
+} |
+ |
+const Rect& RenderText::GetUpdatedCursorBounds() { |
+ UpdateCachedBoundsAndOffset(); |
return cursor_bounds_; |
} |
@@ -481,14 +466,19 @@ RenderText::RenderText() |
: text_(), |
selection_model_(), |
cursor_bounds_(), |
- cursor_bounds_valid_(false), |
cursor_visible_(false), |
insert_mode_(true), |
composition_range_(), |
style_ranges_(), |
default_style_(), |
display_rect_(), |
- display_offset_() { |
+ display_offset_(), |
+ cached_bounds_and_offset_valid_(false) { |
+} |
+ |
+const Point& RenderText::GetUpdatedDisplayOffset() { |
+ UpdateCachedBoundsAndOffset(); |
+ return display_offset_; |
} |
SelectionModel RenderText::GetLeftSelectionModel(const SelectionModel& current, |
@@ -584,21 +574,31 @@ bool RenderText::IsPositionAtWordSelectionBoundary(size_t pos) { |
(!u_isalnum(text()[pos - 1]) && u_isalnum(text()[pos])); |
} |
-void RenderText::UpdateCursorBoundsAndDisplayOffset() { |
- cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode()); |
+void RenderText::UpdateCachedBoundsAndOffset() { |
+ if (cached_bounds_and_offset_valid_) |
+ return; |
+ // 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. |
+ cached_bounds_and_offset_valid_ = true; |
+ cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_); |
+ cursor_bounds_.set_width(std::max(cursor_bounds_.width(), 1)); |
// Update |display_offset_| to ensure the current cursor is visible. |
int display_width = display_rect_.width(); |
int string_width = GetStringWidth(); |
+ int delta_offset = 0; |
if (string_width < display_width) { |
// Show all text whenever the text fits to the size. |
- display_offset_.set_x(0); |
- } else if ((display_offset_.x() + cursor_bounds_.right()) > display_width) { |
+ delta_offset = -display_offset_.x(); |
+ } else if (cursor_bounds_.right() > display_rect_.right()) { |
// Pan to show the cursor when it overflows to the right, |
- display_offset_.set_x(display_width - cursor_bounds_.right()); |
- } else if ((display_offset_.x() + cursor_bounds_.x()) < 0) { |
+ delta_offset = display_rect_.right() - cursor_bounds_.right(); |
+ } else if (cursor_bounds_.x() < display_rect_.x()) { |
// Pan to show the cursor when it overflows to the left. |
- display_offset_.set_x(-cursor_bounds_.x()); |
+ delta_offset = display_rect_.x() - cursor_bounds_.x(); |
} |
+ display_offset_.Offset(delta_offset, 0); |
+ cursor_bounds_.Offset(delta_offset, 0); |
} |
} // namespace gfx |