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