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