Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / renderer_host / input / touch_handle.cc
blobd5bda485dca02ced7e60a57ecea442f74a031c5d
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/input/touch_handle.h"
7 #include <cmath>
9 namespace content {
11 namespace {
13 // Maximum duration of a fade sequence.
14 const double kFadeDurationMs = 200;
16 // Maximum amount of travel for a fade sequence. This avoids handle "ghosting"
17 // when the handle is moving rapidly while the fade is active.
18 const double kFadeDistanceSquared = 20.f * 20.f;
20 // Avoid using an empty touch rect, as it may fail the intersection test event
21 // if it lies within the other rect's bounds.
22 const float kMinTouchMajorForHitTesting = 1.f;
24 // The maximum touch size to use when computing whether a touch point is
25 // targetting a touch handle. This is necessary for devices that misreport
26 // touch radii, preventing inappropriately largely touch sizes from completely
27 // breaking handle dragging behavior.
28 const float kMaxTouchMajorForHitTesting = 36.f;
30 } // namespace
32 // Responsible for rendering a selection or insertion handle for text editing.
33 TouchHandle::TouchHandle(TouchHandleClient* client,
34 TouchHandleOrientation orientation)
35 : drawable_(client->CreateDrawable()),
36 client_(client),
37 orientation_(orientation),
38 deferred_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
39 alpha_(0.f),
40 animate_deferred_fade_(false),
41 enabled_(true),
42 is_visible_(false),
43 is_dragging_(false) {
44 DCHECK_NE(orientation, TOUCH_HANDLE_ORIENTATION_UNDEFINED);
45 drawable_->SetEnabled(enabled_);
46 drawable_->SetOrientation(orientation_);
47 drawable_->SetAlpha(alpha_);
48 drawable_->SetVisible(is_visible_);
49 drawable_->SetFocus(position_);
52 TouchHandle::~TouchHandle() {
55 void TouchHandle::SetEnabled(bool enabled) {
56 if (enabled_ == enabled)
57 return;
58 if (!enabled) {
59 EndDrag();
60 EndFade();
62 enabled_ = enabled;
63 drawable_->SetEnabled(enabled);
66 void TouchHandle::SetVisible(bool visible, AnimationStyle animation_style) {
67 DCHECK(enabled_);
68 if (is_visible_ == visible)
69 return;
71 is_visible_ = visible;
73 // Handle repositioning may have been deferred while previously invisible.
74 if (visible)
75 drawable_->SetFocus(position_);
77 bool animate = animation_style != ANIMATION_NONE;
78 if (is_dragging_) {
79 animate_deferred_fade_ = animate;
80 return;
83 if (animate)
84 BeginFade();
85 else
86 EndFade();
89 void TouchHandle::SetPosition(const gfx::PointF& position) {
90 DCHECK(enabled_);
91 if (position_ == position)
92 return;
93 position_ = position;
94 // Suppress repositioning a handle while invisible or fading out to prevent it
95 // from "ghosting" outside the visible bounds. The position will be pushed to
96 // the drawable when the handle regains visibility (see |SetVisible()|).
97 if (is_visible_)
98 drawable_->SetFocus(position_);
101 void TouchHandle::SetOrientation(TouchHandleOrientation orientation) {
102 DCHECK(enabled_);
103 DCHECK_NE(orientation, TOUCH_HANDLE_ORIENTATION_UNDEFINED);
104 if (is_dragging_) {
105 deferred_orientation_ = orientation;
106 return;
108 DCHECK_EQ(deferred_orientation_, TOUCH_HANDLE_ORIENTATION_UNDEFINED);
109 if (orientation_ == orientation)
110 return;
112 orientation_ = orientation;
113 drawable_->SetOrientation(orientation);
116 bool TouchHandle::WillHandleTouchEvent(const ui::MotionEvent& event) {
117 if (!enabled_)
118 return false;
120 if (!is_dragging_ && event.GetAction() != ui::MotionEvent::ACTION_DOWN)
121 return false;
123 switch (event.GetAction()) {
124 case ui::MotionEvent::ACTION_DOWN: {
125 if (!is_visible_)
126 return false;
127 const float touch_size = std::max(
128 kMinTouchMajorForHitTesting,
129 std::min(kMaxTouchMajorForHitTesting, event.GetTouchMajor()));
130 const gfx::RectF touch_rect(event.GetX() - touch_size * .5f,
131 event.GetY() - touch_size * .5f,
132 touch_size,
133 touch_size);
134 if (!drawable_->IntersectsWith(touch_rect))
135 return false;
136 touch_down_position_ = gfx::PointF(event.GetX(), event.GetY());
137 touch_to_focus_offset_ = position_ - touch_down_position_;
138 touch_down_time_ = event.GetEventTime();
139 BeginDrag();
140 } break;
142 case ui::MotionEvent::ACTION_MOVE: {
143 gfx::PointF new_position =
144 gfx::PointF(event.GetX(), event.GetY()) + touch_to_focus_offset_;
145 client_->OnHandleDragUpdate(*this, new_position);
146 } break;
148 case ui::MotionEvent::ACTION_UP: {
149 // TODO(jdduke): Use the platform touch slop distance and tap delay to
150 // properly detect a tap, crbug.com/394093.
151 base::TimeDelta delay = event.GetEventTime() - touch_down_time_;
152 if (delay < base::TimeDelta::FromMilliseconds(180))
153 client_->OnHandleTapped(*this);
155 EndDrag();
156 } break;
158 case ui::MotionEvent::ACTION_CANCEL:
159 EndDrag();
160 break;
162 default:
163 break;
165 return true;
168 bool TouchHandle::Animate(base::TimeTicks frame_time) {
169 if (fade_end_time_ == base::TimeTicks())
170 return false;
172 DCHECK(enabled_);
174 float time_u =
175 1.f - (fade_end_time_ - frame_time).InMillisecondsF() / kFadeDurationMs;
176 float position_u =
177 (position_ - fade_start_position_).LengthSquared() / kFadeDistanceSquared;
178 float u = std::max(time_u, position_u);
179 SetAlpha(is_visible_ ? u : 1.f - u);
181 if (u >= 1.f) {
182 EndFade();
183 return false;
186 return true;
189 void TouchHandle::BeginDrag() {
190 DCHECK(enabled_);
191 if (is_dragging_)
192 return;
193 EndFade();
194 is_dragging_ = true;
195 client_->OnHandleDragBegin(*this);
198 void TouchHandle::EndDrag() {
199 DCHECK(enabled_);
200 if (!is_dragging_)
201 return;
203 is_dragging_ = false;
204 client_->OnHandleDragEnd(*this);
206 if (deferred_orientation_ != TOUCH_HANDLE_ORIENTATION_UNDEFINED) {
207 TouchHandleOrientation deferred_orientation = deferred_orientation_;
208 deferred_orientation_ = TOUCH_HANDLE_ORIENTATION_UNDEFINED;
209 SetOrientation(deferred_orientation);
212 if (animate_deferred_fade_) {
213 BeginFade();
214 } else {
215 // As drawable visibility assignment is deferred while dragging, push the
216 // change by forcing fade completion.
217 EndFade();
221 void TouchHandle::BeginFade() {
222 DCHECK(enabled_);
223 DCHECK(!is_dragging_);
224 animate_deferred_fade_ = false;
225 const float target_alpha = is_visible_ ? 1.f : 0.f;
226 if (target_alpha == alpha_) {
227 EndFade();
228 return;
231 drawable_->SetVisible(true);
232 fade_end_time_ = base::TimeTicks::Now() +
233 base::TimeDelta::FromMillisecondsD(
234 kFadeDurationMs * std::abs(target_alpha - alpha_));
235 fade_start_position_ = position_;
236 client_->SetNeedsAnimate();
239 void TouchHandle::EndFade() {
240 DCHECK(enabled_);
241 animate_deferred_fade_ = false;
242 fade_end_time_ = base::TimeTicks();
243 SetAlpha(is_visible_ ? 1.f : 0.f);
244 drawable_->SetVisible(is_visible_);
247 void TouchHandle::SetAlpha(float alpha) {
248 alpha = std::max(0.f, std::min(1.f, alpha));
249 if (alpha_ == alpha)
250 return;
251 alpha_ = alpha;
252 drawable_->SetAlpha(alpha);
255 } // namespace content