Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1193)

Side by Side Diff: content/renderer/input/input_scroll_elasticity_controller.cc

Issue 704463003: Move overscroll bounce to impl thread (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/renderer/input/input_scroll_elasticity_controller.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #include "content/renderer/input/input_scroll_elasticity_controller.h"
2
3 namespace content {
4
5 static const float scrollVelocityZeroingTimeout = 0.10f;
6 static const float rubberbandDirectionLockStretchRatio = 1;
7 static const float rubberbandMinimumRequiredDeltaBeforeStretch = 10;
8
9 static const float rubberbandStiffness = 20;
10 static const float rubberbandAmplitude = 0.31f;
11 static const float rubberbandPeriod = 1.6f;
12
13 static float elasticDeltaForTimeDelta(float initialPosition, float initialVeloci ty, float elapsedTime)
14 {
15 float amplitude = rubberbandAmplitude;
16 float period = rubberbandPeriod;
17 float criticalDampeningFactor = expf((-elapsedTime * rubberbandStiffness) / period);
18
19 return (initialPosition + (-initialVelocity * elapsedTime * amplitude)) * cr iticalDampeningFactor;
20 }
21
22 static float elasticDeltaForReboundDelta(float delta)
23 {
24 float stiffness = std::max(rubberbandStiffness, 1.0f);
25 return delta / stiffness;
26 }
27
28 static float reboundDeltaForElasticDelta(float delta)
29 {
30 return delta * rubberbandStiffness;
31 }
32
33 static float scrollWheelMultiplier()
34 {
35 static float multiplier = -1;
36 if (multiplier < 0) {
37 // XXX
38 // multiplier = [[NSUserDefaults standardUserDefaults] floatForKey:@"NSS crollWheelMultiplier"];
39 if (multiplier <= 0)
40 multiplier = 1;
41 }
42 return multiplier;
43 }
44
45 InputScrollElasticityController::InputScrollElasticityController(cc::ScrollElast icityControllerClient* client)
46 : m_client(client)
47 , m_inScrollGesture(false)
48 , m_hasScrolled(false)
49 , m_momentumScrollInProgress(false)
50 , m_ignoreMomentumScrolls(false)
51 , m_snapRubberbandTimerIsActive(false) { }
52
53 InputScrollElasticityController::~InputScrollElasticityController() { }
54
55 void InputScrollElasticityController::WillShutdown() {
56 m_client = NULL;
57 }
58
59 void InputScrollElasticityController::Animate(base::TimeTicks time) {
60 snapRubberBandTimerFired();
61 }
62
63 bool InputScrollElasticityController::handleWheelEvent(const blink::WebMouseWhee lEvent& wheelEvent)
64 {
65 if (wheelEvent.phase == blink::WebMouseWheelEvent::PhaseMayBegin)
66 return false;
67
68 if (wheelEvent.phase == blink::WebMouseWheelEvent::PhaseBegan) {
69 m_inScrollGesture = true;
70 m_hasScrolled = false;
71 m_momentumScrollInProgress = false;
72 m_ignoreMomentumScrolls = false;
73 m_lastMomentumScrollTimestamp = base::Time();
74 m_momentumVelocity = gfx::Vector2dF();
75
76 gfx::Vector2dF stretchAmount = m_client->stretchAmount();
77 m_stretchScrollForce.set_x(reboundDeltaForElasticDelta(stretchAmount.x() ));
78 m_stretchScrollForce.set_y(reboundDeltaForElasticDelta(stretchAmount.y() ));
79 m_overflowScrollDelta = gfx::Vector2dF();
80
81 stopSnapRubberbandTimer();
82
83 // TODO(erikchen): Use the commented out line once Chromium uses the ret urn value correctly.
84 // crbug.com/375512
85 // return shouldHandleEvent(wheelEvent);
86
87 // This logic is incorrect, since diagonal wheel events are not consumed .
88 if (m_client->pinnedInDirection(gfx::Vector2dF(-wheelEvent.deltaX, 0))) {
89 if (wheelEvent.deltaX > 0 && !wheelEvent.canRubberbandLeft)
90 return false;
91 if (wheelEvent.deltaX < 0 && !wheelEvent.canRubberbandRight)
92 return false;
93 }
94
95 return true;
96 }
97
98 if (wheelEvent.phase == blink::WebMouseWheelEvent::PhaseEnded || wheelEvent. phase == blink::WebMouseWheelEvent::PhaseCancelled) {
99 snapRubberBand();
100 return m_hasScrolled;
101 }
102
103 bool isMomentumScrollEvent = (wheelEvent.momentumPhase != blink::WebMouseWhe elEvent::PhaseNone);
104 if (m_ignoreMomentumScrolls && (isMomentumScrollEvent || m_snapRubberbandTim erIsActive)) {
105 if (wheelEvent.momentumPhase == blink::WebMouseWheelEvent::PhaseEnded) {
106 m_ignoreMomentumScrolls = false;
107 return true;
108 }
109 return false;
110 }
111
112 if (!shouldHandleEvent(wheelEvent))
113 return false;
114
115 float deltaX = m_overflowScrollDelta.x() - wheelEvent.deltaX;
116 float deltaY = m_overflowScrollDelta.y() - wheelEvent.deltaY;
117 float eventCoalescedDeltaX = -wheelEvent.deltaX;
118 float eventCoalescedDeltaY = -wheelEvent.deltaY;
119
120 // Reset overflow values because we may decide to remove delta at various po ints and put it into overflow.
121 m_overflowScrollDelta = gfx::Vector2dF();
122
123 gfx::Vector2dF stretchAmount = m_client->stretchAmount();
124 bool isVerticallyStretched = stretchAmount.y();
125 bool isHorizontallyStretched = stretchAmount.x();
126
127 // Slightly prefer scrolling vertically by applying the = case to deltaY
128 if (fabsf(deltaY) >= fabsf(deltaX))
129 deltaX = 0;
130 else
131 deltaY = 0;
132
133 bool shouldStretch = false;
134
135 blink::WebMouseWheelEvent::Phase momentumPhase = wheelEvent.momentumPhase;
136
137 // If we are starting momentum scrolling then do some setup.
138 if (!m_momentumScrollInProgress && (momentumPhase == blink::WebMouseWheelEve nt::PhaseBegan || momentumPhase == blink::WebMouseWheelEvent::PhaseChanged)) {
139 m_momentumScrollInProgress = true;
140 // Start the snap rubber band timer if it's not running. This is needed to
141 // snap back from the over scroll caused by momentum events.
142 if (!m_snapRubberbandTimerIsActive && m_startTime == base::Time())
143 snapRubberBand();
144 }
145
146 // XXX
147 base::Time wheelEventTimestamp = base::Time::Now();
148 float timeDelta = (wheelEventTimestamp - m_lastMomentumScrollTimestamp).InSe condsF();
149 if (m_inScrollGesture || m_momentumScrollInProgress) {
150 if (m_lastMomentumScrollTimestamp != base::Time() && timeDelta > 0 && ti meDelta < scrollVelocityZeroingTimeout) {
151 m_momentumVelocity.set_x(eventCoalescedDeltaX / (float)timeDelta);
152 m_momentumVelocity.set_y(eventCoalescedDeltaY / (float)timeDelta);
153 m_lastMomentumScrollTimestamp = wheelEventTimestamp;
154 } else {
155 m_lastMomentumScrollTimestamp = wheelEventTimestamp;
156 m_momentumVelocity = gfx::Vector2dF();
157 }
158
159 if (isVerticallyStretched) {
160 if (!isHorizontallyStretched && m_client->pinnedInDirection(gfx::Vec tor2dF(deltaX, 0))) {
161 // Stretching only in the vertical.
162 if (deltaY != 0 && (fabsf(deltaX / deltaY) < rubberbandDirection LockStretchRatio))
163 deltaX = 0;
164 else if (fabsf(deltaX) < rubberbandMinimumRequiredDeltaBeforeStr etch) {
165 m_overflowScrollDelta.set_x(m_overflowScrollDelta.x() + delt aX);
166 deltaX = 0;
167 } else
168 m_overflowScrollDelta.set_x(m_overflowScrollDelta.x() + delt aX);
169 }
170 } else if (isHorizontallyStretched) {
171 // Stretching only in the horizontal.
172 if (m_client->pinnedInDirection(gfx::Vector2dF(0, deltaY))) {
173 if (deltaX != 0 && (fabsf(deltaY / deltaX) < rubberbandDirection LockStretchRatio))
174 deltaY = 0;
175 else if (fabsf(deltaY) < rubberbandMinimumRequiredDeltaBeforeStr etch) {
176 m_overflowScrollDelta.set_y(m_overflowScrollDelta.y() + delt aY);
177 deltaY = 0;
178 } else
179 m_overflowScrollDelta.set_y(m_overflowScrollDelta.y() + delt aY);
180 }
181 } else {
182 // Not stretching at all yet.
183 if (m_client->pinnedInDirection(gfx::Vector2dF(deltaX, deltaY))) {
184 if (fabsf(deltaY) >= fabsf(deltaX)) {
185 if (fabsf(deltaX) < rubberbandMinimumRequiredDeltaBeforeStre tch) {
186 m_overflowScrollDelta.set_x(m_overflowScrollDelta.x() + deltaX);
187 deltaX = 0;
188 } else
189 m_overflowScrollDelta.set_x(m_overflowScrollDelta.x() + deltaX);
190 }
191 shouldStretch = true;
192 }
193 }
194 }
195
196 if (deltaX != 0 || deltaY != 0) {
197 m_hasScrolled = true;
198 if (!(shouldStretch || isVerticallyStretched || isHorizontallyStretched) ) {
199 if (deltaY != 0) {
200 deltaY *= scrollWheelMultiplier();
201 m_client->immediateScrollBy(gfx::Vector2dF(0, deltaY));
202 }
203 if (deltaX != 0) {
204 deltaX *= scrollWheelMultiplier();
205 m_client->immediateScrollBy(gfx::Vector2dF(deltaX, 0));
206 }
207 } else {
208 if (!m_client->allowsHorizontalStretching()) {
209 deltaX = 0;
210 eventCoalescedDeltaX = 0;
211 } else if ((deltaX != 0) && !isHorizontallyStretched && !m_client->p innedInDirection(gfx::Vector2dF(deltaX, 0))) {
212 deltaX *= scrollWheelMultiplier();
213
214 m_client->immediateScrollByWithoutContentEdgeConstraints(gfx::Ve ctor2dF(deltaX, 0));
215 deltaX = 0;
216 }
217
218 if (!m_client->allowsVerticalStretching()) {
219 deltaY = 0;
220 eventCoalescedDeltaY = 0;
221 } else if ((deltaY != 0) && !isVerticallyStretched && !m_client->pin nedInDirection(gfx::Vector2dF(0, deltaY))) {
222 deltaY *= scrollWheelMultiplier();
223
224 m_client->immediateScrollByWithoutContentEdgeConstraints(gfx::Ve ctor2dF(0, deltaY));
225 deltaY = 0;
226 }
227
228 gfx::Vector2dF stretchAmount = m_client->stretchAmount();
229
230 if (m_momentumScrollInProgress) {
231 if ((m_client->pinnedInDirection(gfx::Vector2dF(eventCoalescedDe ltaX, eventCoalescedDeltaY)) || (fabsf(eventCoalescedDeltaX) + fabsf(eventCoales cedDeltaY) <= 0)) && m_lastMomentumScrollTimestamp != base::Time()) {
232 m_ignoreMomentumScrolls = true;
233 m_momentumScrollInProgress = false;
234 snapRubberBand();
235 }
236 }
237
238 m_stretchScrollForce.set_x(m_stretchScrollForce.x() + deltaX);
239 m_stretchScrollForce.set_y(m_stretchScrollForce.y() + deltaY);
240
241 gfx::Vector2dF dampedDelta(ceilf(elasticDeltaForReboundDelta(m_stret chScrollForce.x())), ceilf(elasticDeltaForReboundDelta(m_stretchScrollForce.y()) ));
242
243 m_client->immediateScrollByWithoutContentEdgeConstraints(dampedDelta - stretchAmount);
244 }
245 }
246
247 if (m_momentumScrollInProgress && momentumPhase == blink::WebMouseWheelEvent ::PhaseEnded) {
248 m_momentumScrollInProgress = false;
249 m_ignoreMomentumScrolls = false;
250 m_lastMomentumScrollTimestamp = base::Time();
251 }
252
253 return true;
254 }
255
256 static inline float roundTowardZero(float num)
257 {
258 return num > 0 ? ceilf(num - 0.5f) : floorf(num + 0.5f);
259 }
260
261 static inline float roundToDevicePixelTowardZero(float num)
262 {
263 float roundedNum = roundf(num);
264 if (fabs(num - roundedNum) < 0.125)
265 num = roundedNum;
266
267 return roundTowardZero(num);
268 }
269
270 void InputScrollElasticityController::snapRubberBandTimerFired()
271 {
272 if (!m_momentumScrollInProgress || m_ignoreMomentumScrolls) {
273 float timeDelta = (base::Time::Now() - m_startTime).InSecondsF();
274
275 if (m_startStretch == gfx::Vector2dF()) {
276 m_startStretch = m_client->stretchAmount();
277 if (m_startStretch == gfx::Vector2dF()) {
278 stopSnapRubberbandTimer();
279
280 m_stretchScrollForce = gfx::Vector2dF();
281 m_startTime = base::Time();
282 m_origOrigin = gfx::Vector2dF();
283 m_origVelocity = gfx::Vector2dF();
284 return;
285 }
286
287 m_origOrigin = m_client->absoluteScrollPosition() - m_startStretch;
288 m_origVelocity = m_momentumVelocity;
289
290 // Just like normal scrolling, prefer vertical rubberbanding
291 if (fabsf(m_origVelocity.y()) >= fabsf(m_origVelocity.x()))
292 m_origVelocity.set_x(0);
293
294 // Don't rubber-band horizontally if it's not possible to scroll hor izontally
295 if (!m_client->canScrollHorizontally())
296 m_origVelocity.set_x(0);
297
298 // Don't rubber-band vertically if it's not possible to scroll verti cally
299 if (!m_client->canScrollVertically())
300 m_origVelocity.set_y(0);
301 }
302
303 gfx::Vector2dF delta(roundToDevicePixelTowardZero(elasticDeltaForTimeDel ta(m_startStretch.x(), -m_origVelocity.x(), (float)timeDelta)),
304 roundToDevicePixelTowardZero(elasticDeltaForTimeDelta(m _startStretch.y(), -m_origVelocity.y(), (float)timeDelta)));
305
306 if (fabs(delta.x()) >= 1 || fabs(delta.y()) >= 1) {
307 m_client->immediateScrollByWithoutContentEdgeConstraints(gfx::Vector 2dF(delta.x(), delta.y()) - m_client->stretchAmount());
308
309 gfx::Vector2dF newStretch = m_client->stretchAmount();
310
311 m_stretchScrollForce.set_x(reboundDeltaForElasticDelta(newStretch.x( )));
312 m_stretchScrollForce.set_y(reboundDeltaForElasticDelta(newStretch.y( )));
313 } else {
314 m_client->adjustScrollPositionToBoundsIfNecessary();
315
316 stopSnapRubberbandTimer();
317 m_stretchScrollForce = gfx::Vector2dF();
318 m_startTime = base::Time();
319 m_startStretch = gfx::Vector2dF();
320 m_origOrigin = gfx::Vector2dF();
321 m_origVelocity = gfx::Vector2dF();
322 }
323 } else {
324 m_startTime = base::Time::Now();
325 m_startStretch = gfx::Vector2dF();
326 }
327 }
328
329 bool InputScrollElasticityController::isRubberBandInProgress() const
330 {
331 if (!m_inScrollGesture && !m_momentumScrollInProgress && !m_snapRubberbandTi merIsActive)
332 return false;
333
334 return !m_client->stretchAmount().IsZero();
335 }
336
337 void InputScrollElasticityController::stopSnapRubberbandTimer()
338 {
339 m_client->stopSnapRubberbandTimer();
340 m_snapRubberbandTimerIsActive = false;
341 }
342
343 void InputScrollElasticityController::snapRubberBand()
344 {
345 float timeDelta = (base::Time::Now() - m_lastMomentumScrollTimestamp).InSeco ndsF();
346 if (m_lastMomentumScrollTimestamp != base::Time() && timeDelta >= scrollVelo cityZeroingTimeout)
347 m_momentumVelocity = gfx::Vector2dF();
348
349 m_inScrollGesture = false;
350
351 if (m_snapRubberbandTimerIsActive)
352 return;
353
354 m_startStretch = gfx::Vector2dF();
355 m_origOrigin = gfx::Vector2dF();
356 m_origVelocity = gfx::Vector2dF();
357
358 // If there's no momentum scroll or stretch amount, no need to start the tim er.
359 if (!m_momentumScrollInProgress && m_client->stretchAmount() == gfx::Vector2 dF()) {
360 m_startTime = base::Time();
361 m_stretchScrollForce = gfx::Vector2dF();
362 return;
363 }
364
365 m_startTime = base::Time::Now();
366 m_client->startSnapRubberbandTimer();
367 m_snapRubberbandTimerIsActive = true;
368 }
369
370 bool InputScrollElasticityController::shouldHandleEvent(const blink::WebMouseWhe elEvent& wheelEvent)
371 {
372 // Once any scrolling has happened, all future events should be handled.
373 if (m_hasScrolled)
374 return true;
375
376 // The event can't cause scrolling to start if its delta is 0.
377 if (wheelEvent.deltaX == 0 && wheelEvent.deltaY == 0)
378 return false;
379
380 // If the client isn't pinned, then the event is guaranteed to cause scrolli ng.
381 if (!m_client->pinnedInDirection(gfx::Vector2dF(-wheelEvent.deltaX, 0)))
382 return true;
383
384 // If the event is pinned, then the client can't scroll, but it might rubber band.
385 // Check if the event allows rubber banding.
386 if (wheelEvent.deltaY == 0) {
387 if (wheelEvent.deltaX > 0 && !wheelEvent.canRubberbandLeft)
388 return false;
389 if (wheelEvent.deltaX < 0 && !wheelEvent.canRubberbandRight)
390 return false;
391 }
392
393 // The event is going to either cause scrolling or rubber banding.
394 return true;
395 }
396
397 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/input/input_scroll_elasticity_controller.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698