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