Commit 1c77b2b6 authored by ellyjones's avatar ellyjones Committed by Commit bot

Textfield: suppress cursor repaints when there's a selection

Without this, we do a considerable amount of repainting every timer tick.

BUG=645262

Review-Url: https://codereview.chromium.org/2322303002
Cr-Commit-Position: refs/heads/master@{#420667}
parent d9adeff1
......@@ -255,7 +255,6 @@ Textfield::Textfield()
text_input_flags_(0),
performing_user_action_(false),
skip_input_method_cancel_composition_(false),
cursor_visible_(false),
drop_cursor_visible_(false),
initiating_drag_(false),
aggregated_clicks_(0),
......@@ -855,6 +854,8 @@ int Textfield::OnDragUpdated(const ui::DropTargetEvent& event) {
OnCaretBoundsChanged();
SchedulePaint();
StopBlinkingCursor();
if (initiating_drag_) {
if (in_selection)
return ui::DragDropTypes::DRAG_NONE;
......@@ -866,6 +867,8 @@ int Textfield::OnDragUpdated(const ui::DropTargetEvent& event) {
void Textfield::OnDragExited() {
drop_cursor_visible_ = false;
if (ShouldBlinkCursor())
StartBlinkingCursor();
SchedulePaint();
}
......@@ -977,30 +980,26 @@ void Textfield::OnPaint(gfx::Canvas* canvas) {
void Textfield::OnFocus() {
GetRenderText()->set_focused(true);
cursor_visible_ = true;
if (ShouldShowCursor())
GetRenderText()->set_cursor_visible(true);
SchedulePaint();
if (GetInputMethod())
GetInputMethod()->SetFocusedTextInputClient(this);
OnCaretBoundsChanged();
const size_t caret_blink_ms = Textfield::GetCaretBlinkMs();
if (caret_blink_ms != 0) {
cursor_repaint_timer_.Start(FROM_HERE,
base::TimeDelta::FromMilliseconds(caret_blink_ms), this,
&Textfield::UpdateCursor);
}
if (ShouldBlinkCursor())
StartBlinkingCursor();
View::OnFocus();
SchedulePaint();
}
void Textfield::OnBlur() {
GetRenderText()->set_focused(false);
gfx::RenderText* render_text = GetRenderText();
render_text->set_focused(false);
if (GetInputMethod())
GetInputMethod()->DetachTextInputClient(this);
cursor_repaint_timer_.Stop();
if (cursor_visible_) {
cursor_visible_ = false;
StopBlinkingCursor();
if (render_text->cursor_visible()) {
render_text->set_cursor_visible(false);
RepaintCursor();
}
......@@ -1801,10 +1800,12 @@ void Textfield::UpdateAfterChange(bool text_changed, bool cursor_changed) {
NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true);
}
if (cursor_changed) {
cursor_visible_ = true;
GetRenderText()->set_cursor_visible(ShouldShowCursor());
RepaintCursor();
if (cursor_repaint_timer_.IsRunning())
cursor_repaint_timer_.Reset();
if (ShouldBlinkCursor())
StartBlinkingCursor();
else
StopBlinkingCursor();
if (!text_changed) {
// TEXT_CHANGED implies TEXT_SELECTION_CHANGED, so we only need to fire
// this if only the selection changed.
......@@ -1817,12 +1818,6 @@ void Textfield::UpdateAfterChange(bool text_changed, bool cursor_changed) {
}
}
void Textfield::UpdateCursor() {
const size_t caret_blink_ms = Textfield::GetCaretBlinkMs();
cursor_visible_ = !cursor_visible_ || (caret_blink_ms == 0);
RepaintCursor();
}
void Textfield::RepaintCursor() {
gfx::Rect r(GetRenderText()->GetUpdatedCursorBounds());
r.Inset(-1, -1, -1, -1);
......@@ -1843,9 +1838,6 @@ void Textfield::PaintTextAndCursor(gfx::Canvas* canvas) {
render_text->display_rect());
}
// Draw the text, cursor, and selection.
render_text->set_cursor_visible(cursor_visible_ && !drop_cursor_visible_ &&
!HasSelection());
render_text->Draw(canvas);
// Draw the detached drop cursor that marks where the text will be dropped.
......@@ -2046,4 +2038,31 @@ void Textfield::OnKeypressUnhandled() {
PlatformStyle::OnTextfieldKeypressUnhandled();
}
bool Textfield::ShouldShowCursor() const {
return HasFocus() && !HasSelection() && enabled() && !read_only() &&
!drop_cursor_visible_;
}
bool Textfield::ShouldBlinkCursor() const {
return ShouldShowCursor() && Textfield::GetCaretBlinkMs() != 0;
}
void Textfield::StartBlinkingCursor() {
DCHECK(ShouldBlinkCursor());
cursor_blink_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(
Textfield::GetCaretBlinkMs()),
this, &Textfield::OnCursorBlinkTimerFired);
}
void Textfield::StopBlinkingCursor() {
cursor_blink_timer_.Stop();
}
void Textfield::OnCursorBlinkTimerFired() {
DCHECK(ShouldBlinkCursor());
gfx::RenderText* render_text = GetRenderText();
render_text->set_cursor_visible(!render_text->cursor_visible());
RepaintCursor();
}
} // namespace views
......@@ -399,6 +399,22 @@ class VIEWS_EXPORT Textfield : public View,
// to insert text into a readonly text field.
void OnKeypressUnhandled();
// Returns true if an insertion cursor should be visible (a vertical bar,
// placed at the point new text will be inserted).
bool ShouldShowCursor() const;
// Returns true if an insertion cursor should be visible and blinking.
bool ShouldBlinkCursor() const;
// Starts and stops blinking the cursor, respectively. These are both
// idempotent if the cursor is already blinking/not blinking.
void StartBlinkingCursor();
void StopBlinkingCursor();
// Callback for the cursor blink timer. Called every
// Textfield::GetCaretBlinkMs().
void OnCursorBlinkTimerFired();
// The text model.
std::unique_ptr<TextfieldModel> model_;
......@@ -456,9 +472,8 @@ class VIEWS_EXPORT Textfield : public View,
// True if InputMethod::CancelComposition() should not be called.
bool skip_input_method_cancel_composition_;
// The text editing cursor repaint timer and visibility.
base::RepeatingTimer cursor_repaint_timer_;
bool cursor_visible_;
// Insertion cursor repaint timer and visibility.
base::RepeatingTimer cursor_blink_timer_;
// The drop cursor is a visual cue for where dragged text will be dropped.
bool drop_cursor_visible_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment