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 GFX_ASYNCCOMPOSITIONMANAGER_H
8 #define GFX_ASYNCCOMPOSITIONMANAGER_H
9 
10 #include "Units.h"                                  // for ScreenPoint, etc
11 #include "FrameMetrics.h"                           // for FrameMetrics
12 #include "mozilla/layers/APZUtils.h"                // for GeckoViewMetrics
13 #include "mozilla/layers/CompositorBridgeParent.h"  // for TransformsToSkip
14 #include "mozilla/layers/LayerManagerComposite.h"   // for LayerManagerComposite
15 #include "mozilla/Attributes.h"                     // for final, etc
16 #include "mozilla/RefPtr.h"                         // for RefCounted
17 #include "mozilla/TimeStamp.h"                      // for TimeStamp
18 #include "mozilla/gfx/BasePoint.h"                  // for BasePoint
19 #include "mozilla/gfx/Matrix.h"                     // for Matrix4x4
20 #include "mozilla/HalScreenConfiguration.h"         // For ScreenOrientation
21 #include "mozilla/layers/FrameUniformityData.h"     // For FrameUniformityData
22 #include "mozilla/layers/LayersMessages.h"          // for TargetConfig
23 #include "mozilla/RefPtr.h"                         // for nsRefPtr
24 #include "nsISupportsImpl.h"  // for LayerManager::AddRef, etc
25 
26 namespace mozilla {
27 namespace layers {
28 
29 class Layer;
30 class LayerManagerComposite;
31 class AutoResolveRefLayers;
32 class CompositorBridgeParent;
33 class SampleTime;
34 
35 /**
36  * Manage async composition effects. This class is only used with OMTC and only
37  * lives on the compositor thread. It is a layer on top of the layer manager
38  * (LayerManagerComposite) which deals with elements of composition which are
39  * usually dealt with by dom or layout when main thread rendering, but which can
40  * short circuit that stuff to directly affect layers as they are composited,
41  * for example, off-main thread animation, async video, async pan/zoom.
42  */
43 class AsyncCompositionManager final {
44   friend class AutoResolveRefLayers;
45   ~AsyncCompositionManager();
46 
47  public:
48   NS_INLINE_DECL_REFCOUNTING(AsyncCompositionManager)
49 
50   AsyncCompositionManager(CompositorBridgeParent* aParent,
51                           HostLayerManager* aManager);
52 
53   /**
54    * This forces the is-first-paint flag to true. This is intended to
55    * be called by the widget code when it loses its viewport information
56    * (or for whatever reason wants to refresh the viewport information).
57    * The information refresh happens because the compositor will call
58    * AndroidDynamicToolbarAnimator::FirstPaint() on the next frame of
59    * composition.
60    */
ForceIsFirstPaint()61   void ForceIsFirstPaint() { mIsFirstPaint = true; }
62 
63   // Sample transforms for layer trees.  Return true to request
64   // another animation frame.
65   bool TransformShadowTree(
66       const SampleTime& aCurrentFrame, TimeDuration aVsyncRate,
67       CompositorBridgeParentBase::TransformsToSkip aSkip =
68           CompositorBridgeParentBase::TransformsToSkip::NoneOfThem);
69 
70   // Calculates the correct rotation and applies the transform to
71   // our layer manager
72   void ComputeRotation();
73 
74   // Call after updating our layer tree.
Updated(bool isFirstPaint,const TargetConfig & aTargetConfig)75   void Updated(bool isFirstPaint, const TargetConfig& aTargetConfig) {
76     mIsFirstPaint |= isFirstPaint;
77     mLayersUpdated = true;
78     mTargetConfig = aTargetConfig;
79   }
80 
RequiresReorientation(hal::ScreenOrientation aOrientation)81   bool RequiresReorientation(hal::ScreenOrientation aOrientation) const {
82     return mTargetConfig.orientation() != aOrientation;
83   }
84 
85   // True if the underlying layer tree is ready to be composited.
ReadyForCompose()86   bool ReadyForCompose() { return mReadyForCompose; }
87 
88   // Returns true if the next composition will be the first for a
89   // particular document.
IsFirstPaint()90   bool IsFirstPaint() { return mIsFirstPaint; }
91 
92   // GetFrameUniformity will return the frame uniformity for each layer attached
93   // to an APZ from the recorded data in RecordShadowTransform
94   void GetFrameUniformity(FrameUniformityData* aFrameUniformityData);
95 
96   // Stores the clip rect of a layer in two parts: a fixed part and a scrolled
97   // part. When a layer is fixed, the clip needs to be adjusted to account for
98   // async transforms. Only the fixed part needs to be adjusted, so we need
99   // to store the two parts separately.
100   struct ClipParts {
101     Maybe<ParentLayerIntRect> mFixedClip;
102     Maybe<ParentLayerIntRect> mScrolledClip;
103 
IntersectClipParts104     Maybe<ParentLayerIntRect> Intersect() const {
105       return IntersectMaybeRects(mFixedClip, mScrolledClip);
106     }
107   };
108 
109   typedef std::map<Layer*, ClipParts> ClipPartsCache;
110 
111  private:
112   // Return true if an AsyncPanZoomController content transform was
113   // applied for |aLayer|. |*aOutFoundRoot| is set to true on Android only, if
114   // one of the metrics on one of the layers was determined to be the "root"
115   // and its state was synced to the Java front-end. |aOutFoundRoot| must be
116   // non-null.
117   bool ApplyAsyncContentTransformToTree(Layer* aLayer, bool* aOutFoundRoot);
118   /**
119    * Update the shadow transform for aLayer assuming that is a scrollbar,
120    * so that it stays in sync with the content that is being scrolled by APZ.
121    */
122   void ApplyAsyncTransformToScrollbar(Layer* aLayer);
123 
124   /**
125    * Adds a translation to the transform of any fixed position (whose parent
126    * layer is not fixed) or sticky position layer descendant of
127    * |aTransformedSubtreeRoot|. The translation is chosen so that the layer's
128    * anchor point relative to |aTransformedSubtreeRoot|'s parent layer is the
129    * same as it was when |aTransformedSubtreeRoot|'s GetLocalTransform() was
130    * |aPreviousTransformForRoot|. |aCurrentTransformForRoot| is
131    * |aTransformedSubtreeRoot|'s current GetLocalTransform() modulo any
132    * overscroll-related transform, which we don't want to adjust for.
133    * For sticky position layers, the translation is further intersected with
134    * the layer's sticky scroll ranges.
135    * This function will also adjust layers so that the given content document
136    * fixed position margins will be respected during asynchronous panning and
137    * zooming.
138    * |aTransformScrollId| is the scroll id of the scroll frame that scrolls
139    * |aTransformedSubtreeRoot|.
140    * |aClipPartsCache| maps layers to separate fixed and scrolled
141    * clips, so we can only adjust the fixed portion.
142    * This function has a recursive implementation; aStartTraversalAt specifies
143    * where to start the current recursion of the traversal. For the initial
144    * call, it should be the same as aTrasnformedSubtreeRoot.
145    */
146   void AlignFixedAndStickyLayers(
147       Layer* aTransformedSubtreeRoot, Layer* aStartTraversalAt,
148       SideBits aStuckSides, ScrollableLayerGuid::ViewID aTransformScrollId,
149       const LayerToParentLayerMatrix4x4& aPreviousTransformForRoot,
150       const LayerToParentLayerMatrix4x4& aCurrentTransformForRoot,
151       const ScreenMargin& aCompositorFixedLayerMargins,
152       ClipPartsCache& aClipPartsCache,
153       const ScreenMargin& aGeckoFixedLayerMargins);
154 
155   /**
156    * Helper function for AlignFixedAndStickyLayers() to perform a transform
157    * adjustment for a single fixed or sticky layer, rather than all such
158    * layers rooted at a subtree. May also be called directly.
159    */
160   void AdjustFixedOrStickyLayer(
161       Layer* aTransformedSubtreeRoot, Layer* aFixedOrSticky,
162       SideBits aStuckSides, ScrollableLayerGuid::ViewID aTransformScrollId,
163       const LayerToParentLayerMatrix4x4& aPreviousTransformForRoot,
164       const LayerToParentLayerMatrix4x4& aCurrentTransformForRoot,
165       const ScreenMargin& aCompositorFixedLayerMargins,
166       ClipPartsCache& aClipPartsCache,
167       const ScreenMargin& aGeckoFixedLayerMargins);
168 
169   /**
170    * DRAWING PHASE ONLY
171    *
172    * For reach RefLayer in our layer tree, look up its referent and connect it
173    * to the layer tree, if found.
174    * aHasRemoteContent - indicates if the layer tree contains a remote reflayer.
175    *  May be null.
176    */
177   void ResolveRefLayers(CompositorBridgeParent* aCompositor,
178                         bool* aHasRemoteContent);
179 
180   /**
181    * Detaches all referents resolved by ResolveRefLayers.
182    * Assumes that mLayerManager->GetRoot() and mTargetConfig have not changed
183    * since ResolveRefLayers was called.
184    */
185   void DetachRefLayers();
186 
187   // Records the shadow transforms for the tree of layers rooted at the given
188   // layer
189   void RecordShadowTransforms(Layer* aLayer);
190 
191   bool SampleAnimations(Layer* aLayer, TimeStamp aCurrentFrameTime);
192 
193   TargetConfig mTargetConfig;
194   CSSRect mContentRect;
195 
196   RefPtr<HostLayerManager> mLayerManager;
197   // When this flag is set, the next composition will be the first for a
198   // particular document (i.e. the document displayed on the screen will
199   // change). This happens when loading a new page or switching tabs. We notify
200   // the front-end (e.g. Java on Android) about this so that it take the new
201   // page size and zoom into account when providing us with the next view
202   // transform.
203   bool mIsFirstPaint;
204 
205   // This flag is set during a layers update, so that the first composition
206   // after a layers update has it set. It is cleared after that first
207   // composition.
208   bool mLayersUpdated;
209 
210   bool mReadyForCompose;
211 
212   gfx::Matrix mWorldTransform;
213   LayerTransformRecorder mLayerTransformRecorder;
214 
215   TimeStamp mPreviousFrameTimeStamp;
216 
217   MOZ_NON_OWNING_REF CompositorBridgeParent* mCompositorBridge;
218 
219  public:
220   void SetFixedLayerMargins(ScreenIntCoord aTop, ScreenIntCoord aBottom);
221   ScreenMargin GetFixedLayerMargins() const;
222 
223  private:
224   ScreenMargin mFixedLayerMargins;
225 
226 #ifdef MOZ_WIDGET_ANDROID
227  private:
228   // This calculates whether GeckoView metrics should be sent to Java.
229   bool GeckoViewMetricsHaveUpdated(const GeckoViewMetrics& aMetrics);
230   // This holds the most recent GeckoView metrics sent to Java, and is used
231   // to send new updates when it changes.
232   GeckoViewMetrics mLastMetrics;
233   // The following two fields are only needed on Fennec with C++ APZ, because
234   // then we need to reposition the gecko scrollbar to deal with the
235   // dynamic toolbar shifting content around.
236   ScrollableLayerGuid::ViewID mRootScrollableId;
237 #endif
238 };
239 
240 class MOZ_STACK_CLASS AutoResolveRefLayers {
241  public:
242   explicit AutoResolveRefLayers(AsyncCompositionManager* aManager,
243                                 CompositorBridgeParent* aCompositor = nullptr,
244                                 bool* aHasRemoteContent = nullptr)
mManager(aManager)245       : mManager(aManager) {
246     if (mManager) {
247       mManager->ResolveRefLayers(aCompositor, aHasRemoteContent);
248     }
249   }
250 
~AutoResolveRefLayers()251   ~AutoResolveRefLayers() {
252     if (mManager) {
253       mManager->DetachRefLayers();
254     }
255   }
256 
257  private:
258   AsyncCompositionManager* mManager;
259 
260   AutoResolveRefLayers(const AutoResolveRefLayers&) = delete;
261   AutoResolveRefLayers& operator=(const AutoResolveRefLayers&) = delete;
262 };
263 
264 }  // namespace layers
265 }  // namespace mozilla
266 
267 #endif
268