1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "AutoscrollAnimation.h"
8
9 #include <cmath> // for sqrtf()
10
11 #include "AsyncPanZoomController.h"
12 #include "APZCTreeManager.h"
13 #include "FrameMetrics.h"
14 #include "mozilla/Telemetry.h" // for Telemetry
15
16 namespace mozilla {
17 namespace layers {
18
19 // Helper function for AutoscrollAnimation::DoSample().
20 // Basically copied as-is from toolkit/actors/AutoScrollChild.jsm.
Accelerate(ScreenCoord curr,ScreenCoord start)21 static float Accelerate(ScreenCoord curr, ScreenCoord start) {
22 static const int speed = 12;
23 float val = (curr - start) / speed;
24 if (val > 1) {
25 return val * sqrtf(val) - 1;
26 }
27 if (val < -1) {
28 return val * sqrtf(-val) + 1;
29 }
30 return 0;
31 }
32
AutoscrollAnimation(AsyncPanZoomController & aApzc,const ScreenPoint & aAnchorLocation)33 AutoscrollAnimation::AutoscrollAnimation(AsyncPanZoomController& aApzc,
34 const ScreenPoint& aAnchorLocation)
35 : mApzc(aApzc), mAnchorLocation(aAnchorLocation) {}
36
DoSample(FrameMetrics & aFrameMetrics,const TimeDuration & aDelta)37 bool AutoscrollAnimation::DoSample(FrameMetrics& aFrameMetrics,
38 const TimeDuration& aDelta) {
39 APZCTreeManager* treeManager = mApzc.GetApzcTreeManager();
40 if (!treeManager) {
41 return false;
42 }
43
44 ScreenPoint mouseLocation = treeManager->GetCurrentMousePosition();
45
46 // The implementation of this function closely mirrors that of its main-
47 // thread equivalent, the autoscrollLoop() function in
48 // toolkit/actors/AutoScrollChild.jsm.
49
50 // Avoid long jumps when the browser hangs for more than |maxTimeDelta| ms.
51 static const TimeDuration maxTimeDelta = TimeDuration::FromMilliseconds(100);
52 TimeDuration timeDelta = TimeDuration::Min(aDelta, maxTimeDelta);
53
54 float timeCompensation = timeDelta.ToMilliseconds() / 20;
55
56 // Notes:
57 // - The main-thread implementation rounds the scroll delta to an integer,
58 // and keeps track of the fractional part as an "error". It does this
59 // because it uses Window.scrollBy() or Element.scrollBy() to perform
60 // the scrolling, and those functions truncate the fractional part of
61 // the offset. APZ does no such truncation, so there's no need to keep
62 // track of the fractional part separately.
63 // - The Accelerate() function takes Screen coordinates as inputs, but
64 // its output is interpreted as CSS coordinates. This is intentional,
65 // insofar as autoscrollLoop() does the same thing.
66 CSSPoint scrollDelta{
67 Accelerate(mouseLocation.x, mAnchorLocation.x) * timeCompensation,
68 Accelerate(mouseLocation.y, mAnchorLocation.y) * timeCompensation};
69
70 mApzc.ScrollByAndClamp(scrollDelta);
71
72 // An autoscroll animation never ends of its own accord.
73 // It can be stopped in response to various input events, in which case
74 // AsyncPanZoomController::StopAutoscroll() will stop it via
75 // CancelAnimation().
76 return true;
77 }
78
Cancel(CancelAnimationFlags aFlags)79 void AutoscrollAnimation::Cancel(CancelAnimationFlags aFlags) {
80 // The cancellation was initiated by browser.js, so there's no need to
81 // notify it.
82 if (aFlags & TriggeredExternally) {
83 return;
84 }
85
86 if (RefPtr<GeckoContentController> controller =
87 mApzc.GetGeckoContentController()) {
88 controller->CancelAutoscroll(mApzc.GetGuid());
89 }
90 }
91
92 } // namespace layers
93 } // namespace mozilla
94