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