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

Side by Side Diff: Source/core/platform/ScrollAnimatorNone.cpp

Issue 99103006: Moving GraphicsContext and dependencies from core to platform. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Final patch - fixes Android Created 7 years 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 | Annotate | Revision Log
« no previous file with comments | « Source/core/platform/ScrollAnimatorNone.h ('k') | Source/core/platform/ScrollView.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2011, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32
33 #include "core/platform/ScrollAnimatorNone.h"
34
35 #include <algorithm>
36 #include "core/platform/ScrollableArea.h"
37 #include "wtf/CurrentTime.h"
38 #include "wtf/PassOwnPtr.h"
39
40 #include "platform/TraceEvent.h"
41
42 using namespace std;
43
44 namespace WebCore {
45
46 const double kFrameRate = 60;
47 const double kTickTime = 1 / kFrameRate;
48 const double kMinimumTimerInterval = .001;
49
50 PassOwnPtr<ScrollAnimator> ScrollAnimator::create(ScrollableArea* scrollableArea )
51 {
52 if (scrollableArea && scrollableArea->scrollAnimatorEnabled())
53 return adoptPtr(new ScrollAnimatorNone(scrollableArea));
54 return adoptPtr(new ScrollAnimator(scrollableArea));
55 }
56
57 ScrollAnimatorNone::Parameters::Parameters()
58 : m_isEnabled(false)
59 {
60 }
61
62 ScrollAnimatorNone::Parameters::Parameters(bool isEnabled, double animationTime, double repeatMinimumSustainTime, Curve attackCurve, double attackTime, Curve re leaseCurve, double releaseTime, Curve coastTimeCurve, double maximumCoastTime)
63 : m_isEnabled(isEnabled)
64 , m_animationTime(animationTime)
65 , m_repeatMinimumSustainTime(repeatMinimumSustainTime)
66 , m_attackCurve(attackCurve)
67 , m_attackTime(attackTime)
68 , m_releaseCurve(releaseCurve)
69 , m_releaseTime(releaseTime)
70 , m_coastTimeCurve(coastTimeCurve)
71 , m_maximumCoastTime(maximumCoastTime)
72 {
73 }
74
75 double ScrollAnimatorNone::PerAxisData::curveAt(Curve curve, double t)
76 {
77 switch (curve) {
78 case Linear:
79 return t;
80 case Quadratic:
81 return t * t;
82 case Cubic:
83 return t * t * t;
84 case Quartic:
85 return t * t * t * t;
86 case Bounce:
87 // Time base is chosen to keep the bounce points simpler:
88 // 1 (half bounce coming in) + 1 + .5 + .25
89 const double kTimeBase = 2.75;
90 const double kTimeBaseSquared = kTimeBase * kTimeBase;
91 if (t < 1 / kTimeBase)
92 return kTimeBaseSquared * t * t;
93 if (t < 2 / kTimeBase) {
94 // Invert a [-.5,.5] quadratic parabola, center it in [1,2].
95 double t1 = t - 1.5 / kTimeBase;
96 const double kParabolaAtEdge = 1 - .5 * .5;
97 return kTimeBaseSquared * t1 * t1 + kParabolaAtEdge;
98 }
99 if (t < 2.5 / kTimeBase) {
100 // Invert a [-.25,.25] quadratic parabola, center it in [2,2.5].
101 double t2 = t - 2.25 / kTimeBase;
102 const double kParabolaAtEdge = 1 - .25 * .25;
103 return kTimeBaseSquared * t2 * t2 + kParabolaAtEdge;
104 }
105 // Invert a [-.125,.125] quadratic parabola, center it in [2.5,2.75] .
106 const double kParabolaAtEdge = 1 - .125 * .125;
107 t -= 2.625 / kTimeBase;
108 return kTimeBaseSquared * t * t + kParabolaAtEdge;
109 }
110 ASSERT_NOT_REACHED();
111 return 0;
112 }
113
114 double ScrollAnimatorNone::PerAxisData::attackCurve(Curve curve, double deltaTim e, double curveT, double startPosition, double attackPosition)
115 {
116 double t = deltaTime / curveT;
117 double positionFactor = curveAt(curve, t);
118 return startPosition + positionFactor * (attackPosition - startPosition);
119 }
120
121 double ScrollAnimatorNone::PerAxisData::releaseCurve(Curve curve, double deltaTi me, double curveT, double releasePosition, double desiredPosition)
122 {
123 double t = deltaTime / curveT;
124 double positionFactor = 1 - curveAt(curve, 1 - t);
125 return releasePosition + (positionFactor * (desiredPosition - releasePositio n));
126 }
127
128 double ScrollAnimatorNone::PerAxisData::coastCurve(Curve curve, double factor)
129 {
130 return 1 - curveAt(curve, 1 - factor);
131 }
132
133 double ScrollAnimatorNone::PerAxisData::curveIntegralAt(Curve curve, double t)
134 {
135 switch (curve) {
136 case Linear:
137 return t * t / 2;
138 case Quadratic:
139 return t * t * t / 3;
140 case Cubic:
141 return t * t * t * t / 4;
142 case Quartic:
143 return t * t * t * t * t / 5;
144 case Bounce:
145 const double kTimeBase = 2.75;
146 const double kTimeBaseSquared = kTimeBase * kTimeBase;
147 const double kTimeBaseSquaredOverThree = kTimeBaseSquared / 3;
148 double area;
149 double t1 = min(t, 1 / kTimeBase);
150 area = kTimeBaseSquaredOverThree * t1 * t1 * t1;
151 if (t < 1 / kTimeBase)
152 return area;
153
154 t1 = min(t - 1 / kTimeBase, 1 / kTimeBase);
155 // The integral of kTimeBaseSquared * (t1 - .5 / kTimeBase) * (t1 - .5 / kTimeBase) + kParabolaAtEdge
156 const double kSecondInnerOffset = kTimeBaseSquared * .5 / kTimeBase;
157 double bounceArea = t1 * (t1 * (kTimeBaseSquaredOverThree * t1 - kSecond InnerOffset) + 1);
158 area += bounceArea;
159 if (t < 2 / kTimeBase)
160 return area;
161
162 t1 = min(t - 2 / kTimeBase, 0.5 / kTimeBase);
163 // The integral of kTimeBaseSquared * (t1 - .25 / kTimeBase) * (t1 - .25 / kTimeBase) + kParabolaAtEdge
164 const double kThirdInnerOffset = kTimeBaseSquared * .25 / kTimeBase;
165 bounceArea = t1 * (t1 * (kTimeBaseSquaredOverThree * t1 - kThirdInnerOf fset) + 1);
166 area += bounceArea;
167 if (t < 2.5 / kTimeBase)
168 return area;
169
170 t1 = t - 2.5 / kTimeBase;
171 // The integral of kTimeBaseSquared * (t1 - .125 / kTimeBase) * (t1 - .1 25 / kTimeBase) + kParabolaAtEdge
172 const double kFourthInnerOffset = kTimeBaseSquared * .125 / kTimeBase;
173 bounceArea = t1 * (t1 * (kTimeBaseSquaredOverThree * t1 - kFourthInnerOf fset) + 1);
174 area += bounceArea;
175 return area;
176 }
177 ASSERT_NOT_REACHED();
178 return 0;
179 }
180
181 double ScrollAnimatorNone::PerAxisData::attackArea(Curve curve, double startT, d ouble endT)
182 {
183 double startValue = curveIntegralAt(curve, startT);
184 double endValue = curveIntegralAt(curve, endT);
185 return endValue - startValue;
186 }
187
188 double ScrollAnimatorNone::PerAxisData::releaseArea(Curve curve, double startT, double endT)
189 {
190 double startValue = curveIntegralAt(curve, 1 - endT);
191 double endValue = curveIntegralAt(curve, 1 - startT);
192 return endValue - startValue;
193 }
194
195 ScrollAnimatorNone::PerAxisData::PerAxisData(ScrollAnimatorNone* parent, float* currentPosition, int visibleLength)
196 : m_currentPosition(currentPosition)
197 , m_visibleLength(visibleLength)
198 {
199 reset();
200 }
201
202 void ScrollAnimatorNone::PerAxisData::reset()
203 {
204 m_currentVelocity = 0;
205
206 m_desiredPosition = 0;
207 m_desiredVelocity = 0;
208
209 m_startPosition = 0;
210 m_startTime = 0;
211 m_startVelocity = 0;
212
213 m_animationTime = 0;
214 m_lastAnimationTime = 0;
215
216 m_attackPosition = 0;
217 m_attackTime = 0;
218 m_attackCurve = Quadratic;
219
220 m_releasePosition = 0;
221 m_releaseTime = 0;
222 m_releaseCurve = Quadratic;
223 }
224
225
226 bool ScrollAnimatorNone::PerAxisData::updateDataFromParameters(float step, float multiplier, float scrollableSize, double currentTime, Parameters* parameters)
227 {
228 float delta = step * multiplier;
229 if (!m_startTime || !delta || (delta < 0) != (m_desiredPosition - *m_current Position < 0)) {
230 m_desiredPosition = *m_currentPosition;
231 m_startTime = 0;
232 }
233 float newPosition = m_desiredPosition + delta;
234
235 if (newPosition < 0 || newPosition > scrollableSize)
236 newPosition = max(min(newPosition, scrollableSize), 0.0f);
237
238 if (newPosition == m_desiredPosition)
239 return false;
240
241 m_desiredPosition = newPosition;
242
243 if (!m_startTime) {
244 m_attackTime = parameters->m_attackTime;
245 m_attackCurve = parameters->m_attackCurve;
246 }
247 m_animationTime = parameters->m_animationTime;
248 m_releaseTime = parameters->m_releaseTime;
249 m_releaseCurve = parameters->m_releaseCurve;
250
251 // Prioritize our way out of over constraint.
252 if (m_attackTime + m_releaseTime > m_animationTime) {
253 if (m_releaseTime > m_animationTime)
254 m_releaseTime = m_animationTime;
255 m_attackTime = m_animationTime - m_releaseTime;
256 }
257
258 if (!m_startTime) {
259 // FIXME: This should be the time from the event that got us here.
260 m_startTime = currentTime - kTickTime / 2;
261 m_startPosition = *m_currentPosition;
262 m_lastAnimationTime = m_startTime;
263 }
264 m_startVelocity = m_currentVelocity;
265
266 double remainingDelta = m_desiredPosition - *m_currentPosition;
267
268 double attackAreaLeft = 0;
269
270 double deltaTime = m_lastAnimationTime - m_startTime;
271 double attackTimeLeft = max(0., m_attackTime - deltaTime);
272 double timeLeft = m_animationTime - deltaTime;
273 double minTimeLeft = m_releaseTime + min(parameters->m_repeatMinimumSustainT ime, m_animationTime - m_releaseTime - attackTimeLeft);
274 if (timeLeft < minTimeLeft) {
275 m_animationTime = deltaTime + minTimeLeft;
276 timeLeft = minTimeLeft;
277 }
278
279 if (parameters->m_maximumCoastTime > (parameters->m_repeatMinimumSustainTime + parameters->m_releaseTime)) {
280 double targetMaxCoastVelocity = m_visibleLength * .25 * kFrameRate;
281 // This needs to be as minimal as possible while not being intrusive to page up/down.
282 double minCoastDelta = m_visibleLength;
283
284 if (fabs(remainingDelta) > minCoastDelta) {
285 double maxCoastDelta = parameters->m_maximumCoastTime * targetMaxCoa stVelocity;
286 double coastFactor = min(1., (fabs(remainingDelta) - minCoastDelta) / (maxCoastDelta - minCoastDelta));
287
288 // We could play with the curve here - linear seems a little soft. I nitial testing makes me want to feed into the sustain time more aggressively.
289 double coastMinTimeLeft = min(parameters->m_maximumCoastTime, minTim eLeft + coastCurve(parameters->m_coastTimeCurve, coastFactor) * (parameters->m_m aximumCoastTime - minTimeLeft));
290
291 double additionalTime = max(0., coastMinTimeLeft - minTimeLeft);
292 if (additionalTime) {
293 double additionalReleaseTime = min(additionalTime, parameters->m _releaseTime / (parameters->m_releaseTime + parameters->m_repeatMinimumSustainTi me) * additionalTime);
294 m_releaseTime = parameters->m_releaseTime + additionalReleaseTim e;
295 m_animationTime = deltaTime + coastMinTimeLeft;
296 timeLeft = coastMinTimeLeft;
297 }
298 }
299 }
300
301 double releaseTimeLeft = min(timeLeft, m_releaseTime);
302 double sustainTimeLeft = max(0., timeLeft - releaseTimeLeft - attackTimeLeft );
303
304 if (attackTimeLeft) {
305 double attackSpot = deltaTime / m_attackTime;
306 attackAreaLeft = attackArea(m_attackCurve, attackSpot, 1) * m_attackTime ;
307 }
308
309 double releaseSpot = (m_releaseTime - releaseTimeLeft) / m_releaseTime;
310 double releaseAreaLeft = releaseArea(m_releaseCurve, releaseSpot, 1) * m_re leaseTime;
311
312 m_desiredVelocity = remainingDelta / (attackAreaLeft + sustainTimeLeft + rel easeAreaLeft);
313 m_releasePosition = m_desiredPosition - m_desiredVelocity * releaseAreaLeft;
314 if (attackAreaLeft)
315 m_attackPosition = m_startPosition + m_desiredVelocity * attackAreaLeft;
316 else
317 m_attackPosition = m_releasePosition - (m_animationTime - m_releaseTime - m_attackTime) * m_desiredVelocity;
318
319 if (sustainTimeLeft) {
320 double roundOff = m_releasePosition - ((attackAreaLeft ? m_attackPositio n : *m_currentPosition) + m_desiredVelocity * sustainTimeLeft);
321 m_desiredVelocity += roundOff / sustainTimeLeft;
322 }
323
324 return true;
325 }
326
327 // FIXME: Add in jank detection trace events into this function.
328 bool ScrollAnimatorNone::PerAxisData::animateScroll(double currentTime)
329 {
330 double lastScrollInterval = currentTime - m_lastAnimationTime;
331 if (lastScrollInterval < kMinimumTimerInterval)
332 return true;
333
334 m_lastAnimationTime = currentTime;
335
336 double deltaTime = currentTime - m_startTime;
337 double newPosition = *m_currentPosition;
338
339 if (deltaTime > m_animationTime) {
340 *m_currentPosition = m_desiredPosition;
341 reset();
342 return false;
343 }
344 if (deltaTime < m_attackTime)
345 newPosition = attackCurve(m_attackCurve, deltaTime, m_attackTime, m_star tPosition, m_attackPosition);
346 else if (deltaTime < (m_animationTime - m_releaseTime))
347 newPosition = m_attackPosition + (deltaTime - m_attackTime) * m_desiredV elocity;
348 else {
349 // release is based on targeting the exact final position.
350 double releaseDeltaT = deltaTime - (m_animationTime - m_releaseTime);
351 newPosition = releaseCurve(m_releaseCurve, releaseDeltaT, m_releaseTime, m_releasePosition, m_desiredPosition);
352 }
353
354 // Normalize velocity to a per second amount. Could be used to check for jan k.
355 if (lastScrollInterval > 0)
356 m_currentVelocity = (newPosition - *m_currentPosition) / lastScrollInter val;
357 *m_currentPosition = newPosition;
358
359 return true;
360 }
361
362 void ScrollAnimatorNone::PerAxisData::updateVisibleLength(int visibleLength)
363 {
364 m_visibleLength = visibleLength;
365 }
366
367 ScrollAnimatorNone::ScrollAnimatorNone(ScrollableArea* scrollableArea)
368 : ScrollAnimator(scrollableArea)
369 , m_horizontalData(this, &m_currentPosX, scrollableArea->visibleWidth())
370 , m_verticalData(this, &m_currentPosY, scrollableArea->visibleHeight())
371 , m_startTime(0)
372 , m_animationActive(false)
373 {
374 }
375
376 ScrollAnimatorNone::~ScrollAnimatorNone()
377 {
378 stopAnimationTimerIfNeeded();
379 }
380
381 ScrollAnimatorNone::Parameters ScrollAnimatorNone::parametersForScrollGranularit y(ScrollGranularity granularity) const
382 {
383 switch (granularity) {
384 case ScrollByDocument:
385 return Parameters(true, 20 * kTickTime, 10 * kTickTime, Cubic, 10 * kTic kTime, Cubic, 10 * kTickTime, Linear, 1);
386 case ScrollByLine:
387 return Parameters(true, 10 * kTickTime, 7 * kTickTime, Cubic, 3 * kTickT ime, Cubic, 3 * kTickTime, Linear, 1);
388 case ScrollByPage:
389 return Parameters(true, 15 * kTickTime, 10 * kTickTime, Cubic, 5 * kTick Time, Cubic, 5 * kTickTime, Linear, 1);
390 case ScrollByPixel:
391 return Parameters(true, 11 * kTickTime, 2 * kTickTime, Cubic, 3 * kTickT ime, Cubic, 3 * kTickTime, Quadratic, 1.25);
392 default:
393 ASSERT_NOT_REACHED();
394 }
395 return Parameters();
396 }
397
398 bool ScrollAnimatorNone::scroll(ScrollbarOrientation orientation, ScrollGranular ity granularity, float step, float multiplier)
399 {
400 if (!m_scrollableArea->scrollAnimatorEnabled())
401 return ScrollAnimator::scroll(orientation, granularity, step, multiplier );
402
403 TRACE_EVENT0("webkit", "ScrollAnimatorNone::scroll");
404
405 // FIXME: get the type passed in. MouseWheel could also be by line, but shou ld still have different
406 // animation parameters than the keyboard.
407 Parameters parameters;
408 switch (granularity) {
409 case ScrollByDocument:
410 case ScrollByLine:
411 case ScrollByPage:
412 case ScrollByPixel:
413 parameters = parametersForScrollGranularity(granularity);
414 break;
415 case ScrollByPrecisePixel:
416 return ScrollAnimator::scroll(orientation, granularity, step, multiplier );
417 }
418
419 // If the individual input setting is disabled, bail.
420 if (!parameters.m_isEnabled)
421 return ScrollAnimator::scroll(orientation, granularity, step, multiplier );
422
423 // This is an animatable scroll. Set the animation in motion using the appro priate parameters.
424 float scrollableSize = static_cast<float>(m_scrollableArea->scrollSize(orien tation));
425
426 PerAxisData& data = (orientation == VerticalScrollbar) ? m_verticalData : m_ horizontalData;
427 bool needToScroll = data.updateDataFromParameters(step, multiplier, scrollab leSize, WTF::monotonicallyIncreasingTime(), &parameters);
428 if (needToScroll && !animationTimerActive()) {
429 m_startTime = data.m_startTime;
430 animationWillStart();
431 animationTimerFired();
432 }
433 return needToScroll;
434 }
435
436 void ScrollAnimatorNone::scrollToOffsetWithoutAnimation(const FloatPoint& offset )
437 {
438 stopAnimationTimerIfNeeded();
439
440 FloatSize delta = FloatSize(offset.x() - *m_horizontalData.m_currentPosition , offset.y() - *m_verticalData.m_currentPosition);
441
442 m_horizontalData.reset();
443 *m_horizontalData.m_currentPosition = offset.x();
444 m_horizontalData.m_desiredPosition = offset.x();
445
446 m_verticalData.reset();
447 *m_verticalData.m_currentPosition = offset.y();
448 m_verticalData.m_desiredPosition = offset.y();
449
450 notifyPositionChanged(delta);
451 }
452
453 void ScrollAnimatorNone::cancelAnimations()
454 {
455 m_animationActive = false;
456 }
457
458 void ScrollAnimatorNone::serviceScrollAnimations()
459 {
460 if (m_animationActive)
461 animationTimerFired();
462 }
463
464 void ScrollAnimatorNone::willEndLiveResize()
465 {
466 updateVisibleLengths();
467 }
468
469 void ScrollAnimatorNone::didAddVerticalScrollbar(Scrollbar*)
470 {
471 updateVisibleLengths();
472 }
473
474 void ScrollAnimatorNone::didAddHorizontalScrollbar(Scrollbar*)
475 {
476 updateVisibleLengths();
477 }
478
479 void ScrollAnimatorNone::updateVisibleLengths()
480 {
481 m_horizontalData.updateVisibleLength(scrollableArea()->visibleWidth());
482 m_verticalData.updateVisibleLength(scrollableArea()->visibleHeight());
483 }
484
485 void ScrollAnimatorNone::animationTimerFired()
486 {
487 TRACE_EVENT0("webkit", "ScrollAnimatorNone::animationTimerFired");
488
489 double currentTime = WTF::monotonicallyIncreasingTime();
490
491 bool continueAnimation = false;
492 if (m_horizontalData.m_startTime && m_horizontalData.animateScroll(currentTi me))
493 continueAnimation = true;
494 if (m_verticalData.m_startTime && m_verticalData.animateScroll(currentTime))
495 continueAnimation = true;
496
497 if (continueAnimation)
498 startNextTimer();
499 else
500 m_animationActive = false;
501
502 TRACE_EVENT0("webkit", "ScrollAnimatorNone::notifyPositionChanged");
503 notifyPositionChanged(FloatSize());
504
505 if (!continueAnimation)
506 animationDidFinish();
507 }
508
509 void ScrollAnimatorNone::startNextTimer()
510 {
511 if (scrollableArea()->scheduleAnimation())
512 m_animationActive = true;
513 }
514
515 bool ScrollAnimatorNone::animationTimerActive()
516 {
517 return m_animationActive;
518 }
519
520 void ScrollAnimatorNone::stopAnimationTimerIfNeeded()
521 {
522 if (animationTimerActive())
523 m_animationActive = false;
524 }
525
526 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/core/platform/ScrollAnimatorNone.h ('k') | Source/core/platform/ScrollView.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698