summaryrefslogtreecommitdiffstats
path: root/gfx/layers/apz/src/GenericScrollAnimation.cpp
blob: 9320482295bd3b513102d561ce5b0f1197e6ef2c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "GenericScrollAnimation.h"

#include "AsyncPanZoomController.h"
#include "FrameMetrics.h"
#include "nsPoint.h"
#include "ScrollAnimationPhysics.h"
#include "ScrollAnimationBezierPhysics.h"
#include "ScrollAnimationMSDPhysics.h"
#include "mozilla/StaticPrefs_general.h"

namespace mozilla {
namespace layers {

GenericScrollAnimation::GenericScrollAnimation(
    AsyncPanZoomController& aApzc, const nsPoint& aInitialPosition,
    const ScrollAnimationBezierPhysicsSettings& aSettings)
    : mApzc(aApzc), mFinalDestination(aInitialPosition) {
  // ScrollAnimationBezierPhysics (despite it's name) handles the case of
  // general.smoothScroll being disabled whereas ScrollAnimationMSDPhysics does
  // not (ie it scrolls smoothly).
  if (StaticPrefs::general_smoothScroll() &&
      StaticPrefs::general_smoothScroll_msdPhysics_enabled()) {
    mAnimationPhysics = MakeUnique<ScrollAnimationMSDPhysics>(aInitialPosition);
  } else {
    mAnimationPhysics =
        MakeUnique<ScrollAnimationBezierPhysics>(aInitialPosition, aSettings);
  }
}

void GenericScrollAnimation::UpdateDelta(TimeStamp aTime, const nsPoint& aDelta,
                                         const nsSize& aCurrentVelocity) {
  mFinalDestination += aDelta;

  Update(aTime, aCurrentVelocity);
}

void GenericScrollAnimation::UpdateDestination(TimeStamp aTime,
                                               const nsPoint& aDestination,
                                               const nsSize& aCurrentVelocity) {
  mFinalDestination = aDestination;

  Update(aTime, aCurrentVelocity);
}

void GenericScrollAnimation::Update(TimeStamp aTime,
                                    const nsSize& aCurrentVelocity) {
  // Clamp the final destination to the scrollable area.
  CSSPoint clamped = CSSPoint::FromAppUnits(mFinalDestination);
  clamped.x = mApzc.mX.ClampOriginToScrollableRect(clamped.x);
  clamped.y = mApzc.mY.ClampOriginToScrollableRect(clamped.y);
  mFinalDestination = CSSPoint::ToAppUnits(clamped);

  mAnimationPhysics->Update(aTime, mFinalDestination, aCurrentVelocity);
}

bool GenericScrollAnimation::DoSample(FrameMetrics& aFrameMetrics,
                                      const TimeDuration& aDelta) {
  TimeStamp now = mApzc.GetFrameTime().Time();
  CSSToParentLayerScale zoom(aFrameMetrics.GetZoom());
  if (zoom == CSSToParentLayerScale(0)) {
    return false;
  }

  // If the animation is finished, make sure the final position is correct by
  // using one last displacement. Otherwise, compute the delta via the timing
  // function as normal.
  bool finished = mAnimationPhysics->IsFinished(now);
  nsPoint sampledDest = mAnimationPhysics->PositionAt(now);
  ParentLayerPoint displacement = (CSSPoint::FromAppUnits(sampledDest) -
                                   aFrameMetrics.GetVisualScrollOffset()) *
                                  zoom;

  if (finished) {
    mApzc.mX.SetVelocity(0);
    mApzc.mY.SetVelocity(0);
  } else if (!IsZero(displacement / zoom)) {
    // Convert velocity from AppUnits/Seconds to ParentLayerCoords/Milliseconds
    nsSize velocity = mAnimationPhysics->VelocityAt(now);
    ParentLayerPoint velocityPL =
        CSSPoint::FromAppUnits(nsPoint(velocity.width, velocity.height)) * zoom;
    mApzc.mX.SetVelocity(velocityPL.x / 1000.0);
    mApzc.mY.SetVelocity(velocityPL.y / 1000.0);
  }
  // Note: we ignore overscroll for generic animations.
  ParentLayerPoint adjustedOffset, overscroll;
  mApzc.mX.AdjustDisplacement(
      displacement.x, adjustedOffset.x, overscroll.x,
      mDirectionForcedToOverscroll == Some(ScrollDirection::eHorizontal));
  mApzc.mY.AdjustDisplacement(
      displacement.y, adjustedOffset.y, overscroll.y,
      mDirectionForcedToOverscroll == Some(ScrollDirection::eVertical));
  // If we expected to scroll, but there's no more scroll range on either axis,
  // then end the animation early. Note that the initial displacement could be 0
  // if the compositor ran very quickly (<1ms) after the animation was created.
  // When that happens we want to make sure the animation continues.
  if (!IsZero(displacement / zoom) && IsZero(adjustedOffset / zoom)) {
    // Nothing more to do - end the animation.
    return false;
  }
  mApzc.ScrollBy(adjustedOffset / zoom);
  return !finished;
}

bool GenericScrollAnimation::HandleScrollOffsetUpdate(
    const Maybe<CSSPoint>& aRelativeDelta) {
  if (aRelativeDelta) {
    mAnimationPhysics->ApplyContentShift(*aRelativeDelta);
    return true;
  }
  return false;
}

}  // namespace layers
}  // namespace mozilla