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 #ifndef mozilla_layers_AndroidDynamicToolbarAnimator_h_
8 #define mozilla_layers_AndroidDynamicToolbarAnimator_h_
9 
10 #include "InputData.h"
11 #include "mozilla/Atomics.h"
12 #include "mozilla/EventForwards.h"
13 #include "mozilla/ipc/Shmem.h"
14 #include "mozilla/layers/Effects.h"
15 #include "mozilla/layers/TextureHost.h"
16 #include "mozilla/LinkedList.h"
17 #include "mozilla/Maybe.h"
18 #include "mozilla/TimeStamp.h"
19 #include "nsISupports.h"
20 
21 namespace mozilla {
22 namespace layers {
23 
24 struct FrameMetrics;
25 class APZCTreeManager;
26 class CompositorOGL;
27 
28 /*
29  * The AndroidDynamicToolbarAnimator is responsible for calculating the position
30  * and drawing the static snapshot of the toolbar. The animator lives in both
31  * compositor thread and controller thread. It intercepts input events in the
32  * controller thread and determines if the intercepted touch events will cause
33  * the toolbar to move or be animated. Once the proper conditions have been met,
34  * the animator requests that the UI thread send a static snapshot of the
35  * current state of the toolbar. Once the animator has received the snapshot and
36  * converted it into an OGL texture, the animator notifies the UI thread it is
37  * ready. The UI thread will then hide the real toolbar and notify the animator
38  * that it is unlocked and may begin translating the snapshot. The
39  * animator is responsible for rendering the snapshot until it receives a
40  * message to show the toolbar or touch events cause the snapshot to be
41  * completely visible. When the snapshot is made completely visible the animator
42  * locks the static toolbar and sends a message to the UI thread to show the
43  * real toolbar and the whole process may start again. The toolbar height is in
44  * screen pixels. The toolbar height will be at max height when completely
45  * visible and at 0 when completely hidden. The toolbar is only locked when it
46  * is completely visible. The animator must ask for an update of the toolbar
47  * snapshot and that the real toolbar be hidden in order to unlock the static
48  * snapshot and begin translating it.
49  *
50  * See Bug 1335895 for more details.
51  */
52 
53 class AndroidDynamicToolbarAnimator {
54  public:
55   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AndroidDynamicToolbarAnimator);
56   explicit AndroidDynamicToolbarAnimator(APZCTreeManager* aApz);
57   void Initialize(uint64_t aRootLayerTreeId);
58   void ClearTreeManager();
59   // Used to intercept events to determine if the event affects the toolbar.
60   // May apply translation to touch events if the toolbar is visible.
61   // Returns nsEventStatus_eIgnore when the event is not consumed and
62   // nsEventStatus_eConsumeNoDefault when the event was used to translate the
63   // toolbar.
64   nsEventStatus ReceiveInputEvent(const RefPtr<APZCTreeManager>& aApz,
65                                   InputData& aEvent,
66                                   const ScreenPoint& aScrollOffset);
67   void SetMaxToolbarHeight(ScreenIntCoord aHeight);
68   // When a pinned reason is set to true, the animator will prevent
69   // touch events from altering the height of the toolbar. All pinned
70   // reasons must be cleared before touch events will affect the toolbar.
71   // Animation requests from the UI thread are still honored even if any
72   // pin reason is set. This allows the UI thread to pin the toolbar for
73   // full screen and then request the animator hide the toolbar.
74   void SetPinned(bool aPinned, int32_t aReason);
75   // returns maximum number of Y device pixels the toolbar will cover when fully
76   // visible.
77   ScreenIntCoord GetMaxToolbarHeight() const;
78   // returns the current number of Y screen pixels the toolbar is currently
79   // showing.
80   ScreenIntCoord GetCurrentToolbarHeight() const;
81   // returns the current number of Y screen pixels the content should be offset
82   // from the top of the surface.
83   ScreenIntCoord GetCurrentContentOffset() const;
84   // returns the height in device pixels of the current Android surface used to
85   // display content and the toolbar. This will only change when the surface
86   // provided by the system actually changes size such as when the device is
87   // rotated or the virtual keyboard is made visible.
88   ScreenIntCoord GetCurrentSurfaceHeight() const;
89   // This is the height in device pixels of the root document's content. While
90   // the toolbar is being hidden or shown, the content may extend beyond the
91   // bottom of the surface until the toolbar is completely visible or hidden.
92   ScreenIntCoord GetCompositionHeight() const;
93   // Called to signal that root content is being scrolled. This prevents sub
94   // scroll frames from affecting the toolbar when being scrolled up. The idea
95   // is a scrolling down will always show the toolbar while scrolling up will
96   // only hide the toolbar if it is the root content being scrolled.
97   void SetScrollingRootContent();
98   void ToolbarAnimatorMessageFromUI(int32_t aMessage);
99   // Returns true if the animation will continue and false if it has completed.
100   bool UpdateAnimation(const TimeStamp& aCurrentFrame);
101   // Called to signify the first paint has occurred.
102   void FirstPaint();
103   // Called whenever the root document's FrameMetrics have reached a steady
104   // state.
105   void UpdateRootFrameMetrics(const FrameMetrics& aMetrics);
106   // Only update the frame metrics if the root composition size has changed
107   void MaybeUpdateCompositionSizeAndRootFrameMetrics(
108       const FrameMetrics& aMetrics);
109   // When aEnable is set to true, it informs the animator that the UI thread
110   // expects to be notified when the layer tree  has been updated. Enabled
111   // currently by robocop tests.
112   void EnableLayersUpdateNotifications(bool aEnable);
113   // Called when a layer has been updated so the UI thread may be notified if
114   // necessary.
115   void NotifyLayersUpdated();
116   // Adopts the Shmem containing the toolbar snapshot sent from the UI thread.
117   // The AndroidDynamicToolbarAnimator is responsible for deallocating the Shmem
118   // when it is done being used.
119   void AdoptToolbarPixels(mozilla::ipc::Shmem&& aMem,
120                           const ScreenIntSize& aSize);
121   // Updates the toolbar snapshot texture and notifies the UI thread that the
122   // static toolbar is now ready to be displayed.
123   void UpdateToolbarSnapshotTexture(CompositorOGL* gl);
124   // Returns the Effect object used by the compositor to render the toolbar
125   // snapshot.
126   Effect* GetToolbarEffect();
127   void Shutdown();
128 
129  protected:
130   enum StaticToolbarState {
131     eToolbarVisible,
132     eToolbarUpdated,
133     eToolbarUnlocked,
134     eToolbarAnimating
135   };
136   enum ControllerThreadState {
137     eNothingPending,
138     eShowPending,
139     eUnlockPending,
140     eAnimationStartPending,
141     eAnimationStopPending
142   };
143   enum AnimationStyle { eImmediate, eAnimate };
144 
~AndroidDynamicToolbarAnimator()145   ~AndroidDynamicToolbarAnimator() {}
146   nsEventStatus ProcessTouchDelta(const RefPtr<APZCTreeManager>& aApz,
147                                   StaticToolbarState aCurrentToolbarState,
148                                   ScreenIntCoord aDelta, uint32_t aTimeStamp);
149   // Called when a touch ends
150   void HandleTouchEnd(StaticToolbarState aCurrentToolbarState,
151                       ScreenIntCoord aCurrentTouch);
152   // Sends a message to the UI thread. May be called from any thread
153   void PostMessage(int32_t aMessage);
154   void UpdateCompositorToolbarHeight(ScreenIntCoord aHeight);
155   void UpdateControllerToolbarHeight(ScreenIntCoord aHeight,
156                                      ScreenIntCoord aMaxHeight = -1);
157   void UpdateControllerSurfaceHeight(ScreenIntCoord aHeight);
158   void UpdateControllerCompositionHeight(ScreenIntCoord aHeight);
159   void UpdateFixedLayerMargins();
160   void NotifyControllerPendingAnimation(int32_t aDirection,
161                                         AnimationStyle aStyle);
162   void StartCompositorAnimation(int32_t aDirection, AnimationStyle aStyle,
163                                 ScreenIntCoord aHeight,
164                                 bool aWaitForPageResize);
165   void NotifyControllerAnimationStarted();
166   void StopCompositorAnimation();
167   void NotifyControllerAnimationStopped(ScreenIntCoord aHeight);
168   void RequestComposite();
169   void PostToolbarReady();
170   void UpdateFrameMetrics(ScreenPoint aScrollOffset, CSSToScreenScale aScale,
171                           CSSRect aCssPageRect);
172   // Returns true if the page is too small to animate the toolbar
173   // Also ensures the toolbar is visible.
174   bool PageTooSmallEnsureToolbarVisible();
175   void ShowToolbarIfNotVisible(StaticToolbarState aCurrentToolbarState);
176   void TranslateTouchEvent(MultiTouchInput& aTouchEvent);
177   ScreenIntCoord GetFixedLayerMarginsBottom();
178   void NotifyControllerSnapshotFailed();
179   void CheckForResetOnNextMove(ScreenIntCoord aCurrentTouch);
180   // Returns true if the page scroll offset is near the bottom.
181   bool ScrollOffsetNearBottom() const;
182   // Returns true if toolbar is not completely visible nor completely hidden.
183   bool ToolbarInTransition();
184   void QueueMessage(int32_t aMessage);
185 
186   // Read only Compositor and Controller threads after Initialize()
187   uint64_t mRootLayerTreeId;
188   MOZ_NON_OWNING_REF APZCTreeManager* mApz;
189 
190   // Read/Write Compositor Thread, Read only Controller thread
191   Atomic<StaticToolbarState> mToolbarState;  // Current toolbar state.
192   Atomic<uint32_t> mPinnedFlags;  // The toolbar should not be moved or animated
193                                   // unless no flags are set
194 
195   // Controller thread only
196   bool mControllerScrollingRootContent;  // Set to true when the root content is
197                                          // being scrolled
198   bool mControllerDragThresholdReached;  // Set to true when the drag threshold
199                                          // has been passed in a single drag
200   bool mControllerCancelTouchTracking;   // Set to true when the UI thread
201                                          // requests the toolbar be made visible
202   bool mControllerDragChangedDirection;  // Set to true if the drag ever goes in
203                                          // more than one direction
204   bool mControllerResetOnNextMove;       // Set to true if transitioning from
205                                     // multiple touches to a single touch source
206                                     // Causes mControllerStartTouch,
207                                     // mControllerPreviousTouch,
208                                     // mControllerTotalDistance,
209                                     // mControllerDragThresholdReached, and
210                                     // mControllerLastDragDirection to be reset
211                                     // on next move
212   ScreenIntCoord
213       mControllerStartTouch;  // The Y position where the touch started
214   ScreenIntCoord
215       mControllerPreviousTouch;  // The previous Y position of the touch
216   ScreenIntCoord mControllerTotalDistance;  // Total distance travel during the
217                                             // current touch
218   ScreenIntCoord mControllerMaxToolbarHeight;  // Max height of the toolbar
219   ScreenIntCoord mControllerToolbarHeight;     // Current height of the toolbar
220   ScreenIntCoord
221       mControllerSurfaceHeight;  // Current height of the render surface
222   ScreenIntCoord
223       mControllerCompositionHeight;      // Current height of the visible page
224   ScreenCoord mControllerRootScrollY;    // Current scroll Y value of the root
225                                          // scroll frame
226   int32_t mControllerLastDragDirection;  // Direction of movement of the
227                                          // previous touch move event
228   int32_t mControllerTouchCount;  // Counts the number of current touches.
229   uint32_t mControllerLastEventTimeStamp;  // Time stamp for the previous touch
230                                            // event received
231   ControllerThreadState mControllerState;  // Contains the expected pending
232                                            // state of the mToolbarState
233 
234   // Contains the values from the last steady state root content FrameMetrics
235   struct FrameMetricsState {
236     ScreenPoint mScrollOffset;
237     CSSToScreenScale mScale;
238     CSSRect mCssPageRect;
239     ScreenRect mPageRect;
240 
241     // Returns true if any of the values have changed.
242     bool Update(const ScreenPoint& aScrollOffset,
243                 const CSSToScreenScale& aScale, const CSSRect& aCssPageRect);
244   };
245 
246   // Controller thread only
247   FrameMetricsState mControllerFrameMetrics;  // Updated when frame metrics are
248                                               // in a steady state.
249 
250   class QueuedMessage : public LinkedListElement<QueuedMessage> {
251    public:
QueuedMessage(int32_t aMessage)252     explicit QueuedMessage(int32_t aMessage) : mMessage(aMessage) {}
253     int32_t mMessage;
254 
255    private:
256     QueuedMessage() = delete;
257     QueuedMessage(const QueuedMessage&) = delete;
258     QueuedMessage& operator=(const QueuedMessage&) = delete;
259   };
260 
261   // Compositor thread only
262   bool
263       mCompositorShutdown;  // Set to true when the compositor has been shutdown
264   bool mCompositorAnimationDeferred;    // An animation has been deferred until
265                                         // the toolbar is unlocked
266   bool mCompositorLayersUpdateEnabled;  // Flag set to true when the UI thread
267                                         // is expecting to be notified when a
268                                         // layer has been updated
269   bool mCompositorAnimationStarted;     // Set to true when the compositor has
270                                         // actually started animating the static
271                                         // snapshot.
272   bool mCompositorReceivedFirstPaint;  // Set to true when a first paint occurs.
273                                        // Used by toolbar animator to detect a
274                                        // new page load.
275   bool mCompositorWaitForPageResize;   // Set to true if the bottom of the page
276                                        // has been reached and the toolbar
277                                        // animator should wait for the page to
278                                        // resize before ending animation.
279   bool mCompositorToolbarShowRequested;  // Set to true if the animator has
280                                          // already requested the real toolbar
281                                          // chrome be shown
282   bool mCompositorSendResponseForSnapshotUpdate;  // Set to true when a message
283                                                   // should be sent after a
284                                                   // static toolbar snapshot
285                                                   // update
286   AnimationStyle mCompositorAnimationStyle;  // Set to true when the snapshot
287                                              // should be immediately hidden or
288                                              // shown in the animation update
289   ScreenIntCoord mCompositorMaxToolbarHeight;  // Should contain the same value
290                                                // as mControllerMaxToolbarHeight
291   ScreenIntCoord mCompositorToolbarHeight;  // This value is only updated by the
292                                             // compositor thread when the
293                                             // mToolbarState == ToolbarAnimating
294   ScreenIntCoord
295       mCompositorSurfaceHeight;  // Current height of the render surface
296   ScreenIntSize mCompositorCompositionSize;  // Current size of the visible page
297   int32_t mCompositorAnimationDirection;     // Direction the snapshot should be
298                                              // animated
299   ScreenIntCoord mCompositorAnimationStartHeight;  // The height of the snapshot
300                                                    // at the start of an
301                                                    // animation
302   ScreenIntSize
303       mCompositorToolbarPixelsSize;  // Size of the received toolbar pixels
304   Maybe<mozilla::ipc::Shmem> mCompositorToolbarPixels;  // Shared memory contain
305                                                         // the updated snapshot
306                                                         // pixels used to create
307                                                         // the OGL texture
308   RefPtr<DataTextureSource> mCompositorToolbarTexture;  // The OGL texture used
309                                                         // to render the
310                                                         // snapshot in the
311                                                         // compositor
312   RefPtr<EffectRGB> mCompositorToolbarEffect;    // Effect used to render the
313                                                  // snapshot in the compositor
314   TimeStamp mCompositorAnimationStartTimeStamp;  // Time stamp when the current
315                                                  // animation started
316   AutoCleanLinkedList<QueuedMessage> mCompositorQueuedMessages;  // Queue to
317                                                                  // contain
318                                                                  // messages
319                                                                  // sent before
320                                                                  // Initialize()
321                                                                  // called
322 };
323 
324 }  // namespace layers
325 }  // namespace mozilla
326 #endif  // mozilla_layers_AndroidDynamicToolbarAnimator_h_
327