summaryrefslogtreecommitdiffstats
path: root/gfx/layers/apz/src/Overscroll.h
blob: b74dcdc782ba37b63c134433a55cf24a7586704d (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
133
134
135
136
137
/* -*- 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/. */

#ifndef mozilla_layers_Overscroll_h
#define mozilla_layers_Overscroll_h

#include "AsyncPanZoomAnimation.h"
#include "AsyncPanZoomController.h"
#include "mozilla/TimeStamp.h"
#include "nsThreadUtils.h"

namespace mozilla {
namespace layers {

// Animation used by GenericOverscrollEffect.
class OverscrollAnimation : public AsyncPanZoomAnimation {
 public:
  OverscrollAnimation(AsyncPanZoomController& aApzc,
                      const ParentLayerPoint& aVelocity)
      : mApzc(aApzc) {
    mApzc.mX.StartOverscrollAnimation(aVelocity.x);
    mApzc.mY.StartOverscrollAnimation(aVelocity.y);
  }
  virtual ~OverscrollAnimation() {
    mApzc.mX.EndOverscrollAnimation();
    mApzc.mY.EndOverscrollAnimation();
  }

  virtual bool DoSample(FrameMetrics& aFrameMetrics,
                        const TimeDuration& aDelta) override {
    // Can't inline these variables due to short-circuit evaluation.
    bool continueX = mApzc.mX.SampleOverscrollAnimation(aDelta);
    bool continueY = mApzc.mY.SampleOverscrollAnimation(aDelta);
    if (!continueX && !continueY) {
      // If we got into overscroll from a fling, that fling did not request a
      // fling snap to avoid a resulting scrollTo from cancelling the overscroll
      // animation too early. We do still want to request a fling snap, though,
      // in case the end of the axis at which we're overscrolled is not a valid
      // snap point, so we request one now. If there are no snap points, this
      // will do nothing. If there are snap points, we'll get a scrollTo that
      // snaps us back to the nearest valid snap point. The scroll snapping is
      // done in a deferred task, otherwise the state change to NOTHING caused
      // by the overscroll animation ending would clobber a possible state
      // change to SMOOTH_SCROLL in ScrollSnap().
      mDeferredTasks.AppendElement(
          NewRunnableMethod("layers::AsyncPanZoomController::ScrollSnap",
                            &mApzc, &AsyncPanZoomController::ScrollSnap));
      return false;
    }
    return true;
  }

  virtual bool WantsRepaints() override { return false; }

 private:
  AsyncPanZoomController& mApzc;
};

// Base class for different overscroll effects;
class OverscrollEffectBase {
 public:
  virtual ~OverscrollEffectBase() = default;
  virtual void ConsumeOverscroll(ParentLayerPoint& aOverscroll,
                                 bool aShouldOverscrollX,
                                 bool aShouldOverscrollY) = 0;
  virtual void HandleFlingOverscroll(const ParentLayerPoint& aVelocity) = 0;
};

// A generic overscroll effect, implemented by AsyncPanZoomController itself.
class GenericOverscrollEffect : public OverscrollEffectBase {
 public:
  explicit GenericOverscrollEffect(AsyncPanZoomController& aApzc)
      : mApzc(aApzc) {}

  void ConsumeOverscroll(ParentLayerPoint& aOverscroll, bool aShouldOverscrollX,
                         bool aShouldOverscrollY) override {
    if (aShouldOverscrollX) {
      mApzc.mX.OverscrollBy(aOverscroll.x);
      aOverscroll.x = 0;
    }

    if (aShouldOverscrollY) {
      mApzc.mY.OverscrollBy(aOverscroll.y);
      aOverscroll.y = 0;
    }

    if (aShouldOverscrollX || aShouldOverscrollY) {
      mApzc.ScheduleComposite();
    }
  }

  void HandleFlingOverscroll(const ParentLayerPoint& aVelocity) override {
    mApzc.StartOverscrollAnimation(aVelocity);
  }

 private:
  AsyncPanZoomController& mApzc;
};

// A widget-specific overscroll effect, implemented by the widget via
// GeckoContentController.
class WidgetOverscrollEffect : public OverscrollEffectBase {
 public:
  explicit WidgetOverscrollEffect(AsyncPanZoomController& aApzc)
      : mApzc(aApzc) {}

  void ConsumeOverscroll(ParentLayerPoint& aOverscroll, bool aShouldOverscrollX,
                         bool aShouldOverscrollY) override {
    RefPtr<GeckoContentController> controller =
        mApzc.GetGeckoContentController();
    if (controller && (aShouldOverscrollX || aShouldOverscrollY)) {
      controller->UpdateOverscrollOffset(mApzc.GetGuid(), aOverscroll.x,
                                         aOverscroll.y, mApzc.IsRootContent());
      aOverscroll = ParentLayerPoint();
    }
  }

  void HandleFlingOverscroll(const ParentLayerPoint& aVelocity) override {
    RefPtr<GeckoContentController> controller =
        mApzc.GetGeckoContentController();
    if (controller) {
      controller->UpdateOverscrollVelocity(mApzc.GetGuid(), aVelocity.x,
                                           aVelocity.y, mApzc.IsRootContent());
    }
  }

 private:
  AsyncPanZoomController& mApzc;
};

}  // namespace layers
}  // namespace mozilla

#endif  // mozilla_layers_Overscroll_h