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