summaryrefslogtreecommitdiffstats
path: root/gfx/layers/apz/src/GenericScrollAnimation.cpp
blob: 62f19fab35e4fc03c2a48365b2b9111de13d94f9 (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
121
122
123
124
125
126
127
128
129
130
131
132
/* -*- 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 "mozilla/layers/APZPublicUtils.h"
#include "nsPoint.h"
#include "ScrollAnimationPhysics.h"
#include "ScrollAnimationBezierPhysics.h"
#include "ScrollAnimationMSDPhysics.h"
#include "mozilla/StaticPrefs_general.h"

static mozilla::LazyLogModule sApzScrollAnimLog("apz.scrollanimation");
#define GSA_LOG(...) MOZ_LOG(sApzScrollAnimLog, LogLevel::Debug, (__VA_ARGS__))

namespace mozilla {
namespace layers {

GenericScrollAnimation::GenericScrollAnimation(AsyncPanZoomController& aApzc,
                                               const nsPoint& aInitialPosition,
                                               ScrollOrigin aOrigin)
    : mApzc(aApzc), mFinalDestination(aInitialPosition) {
  // ScrollAnimationBezierPhysics (despite its 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,
        apz::ComputeBezierAnimationSettingsForOrigin(aOrigin));
  }
}

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.
  GSA_LOG(
      "Sampling GenericScrollAnimation: time %f finished %d sampledDest %s "
      "adjustedOffset %s overscroll %s\n",
      (now - TimeStamp::ProcessCreation()).ToMilliseconds(), finished,
      ToString(CSSPoint::FromAppUnits(sampledDest)).c_str(),
      ToString(adjustedOffset).c_str(), ToString(overscroll).c_str());
  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);
    mFinalDestination += CSSPoint::ToAppUnits(*aRelativeDelta);
    return true;
  }
  return false;
}

}  // namespace layers
}  // namespace mozilla