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_WEBRENDERSCROLLDATAWRAPPER_H
8 #define GFX_WEBRENDERSCROLLDATAWRAPPER_H
9 
10 #include "FrameMetrics.h"
11 #include "mozilla/layers/APZUpdater.h"
12 #include "mozilla/layers/CompositorBridgeParent.h"
13 #include "mozilla/layers/WebRenderBridgeParent.h"
14 #include "mozilla/layers/WebRenderScrollData.h"
15 
16 namespace mozilla {
17 namespace layers {
18 
19 /**
20  * A wrapper class around a target WebRenderLayerScrollData (henceforth,
21  * "layer") that allows user code to walk through the ScrollMetadata objects
22  * on the layer the same way it would walk through a layer tree.
23  * Consider the following layer tree:
24  *
25  *                    +---+
26  *                    | A |
27  *                    +---+
28  *                   /  |  \
29  *                  /   |   \
30  *                 /    |    \
31  *            +---+  +-----+  +---+
32  *            | B |  |  C  |  | D |
33  *            +---+  +-----+  +---+
34  *                   | SMn |
35  *                   |  .  |
36  *                   |  .  |
37  *                   |  .  |
38  *                   | SM1 |
39  *                   | SM0 |
40  *                   +-----+
41  *                   /     \
42  *                  /       \
43  *             +---+         +---+
44  *             | E |         | F |
45  *             +---+         +---+
46  *
47  * In this layer tree, there are six layers with A being the root and B,D,E,F
48  * being leaf nodes. Layer C is in the middle and has n+1 ScrollMetadata,
49  * labelled SM0...SMn. SM0 is the ScrollMetadata you get by calling
50  * c->GetScrollMetadata(0) and SMn is the ScrollMetadata you can obtain by
51  * calling c->GetScrollMetadata(c->GetScrollMetadataCount() - 1). This layer
52  * tree is conceptually equivalent to this one below:
53  *
54  *                    +---+
55  *                    | A |
56  *                    +---+
57  *                   /  |  \
58  *                  /   |   \
59  *                 /    |    \
60  *            +---+  +-----+  +---+
61  *            | B |  | Cn  |  | D |
62  *            +---+  +-----+  +---+
63  *                      |
64  *                      .
65  *                      .
66  *                      .
67  *                      |
68  *                   +-----+
69  *                   | C1  |
70  *                   +-----+
71  *                      |
72  *                   +-----+
73  *                   | C0  |
74  *                   +-----+
75  *                   /     \
76  *                  /       \
77  *             +---+         +---+
78  *             | E |         | F |
79  *             +---+         +---+
80  *
81  * In this layer tree, the layer C has been expanded into a stack of layers
82  * C1...Cn, where C1 has ScrollMetadata SM1 and Cn has ScrollMetdata Fn.
83  *
84  * The WebRenderScrollDataWrapper class allows client code to treat the first
85  * layer tree as though it were the second. That is, instead of client code
86  * having to iterate through the ScrollMetadata objects directly, it can use a
87  * WebRenderScrollDataWrapper to encapsulate that aspect of the layer tree and
88  * just walk the tree as if it were a stack of layers.
89  *
90  * The functions on this class do different things depending on which
91  * simulated layer is being wrapped. For example, if the
92  * WebRenderScrollDataWrapper is pretending to be C0, the GetPrevSibling()
93  * function will return null even though the underlying layer C does actually
94  * have a prev sibling. The WebRenderScrollDataWrapper pretending to be Cn will
95  * return B as the prev sibling.
96  *
97  * Implementation notes:
98  *
99  * The AtTopLayer() and AtBottomLayer() functions in this class refer to
100  * Cn and C0 in the second layer tree above; that is, they are predicates
101  * to test if the wrapper is simulating the topmost or bottommost layer, as
102  * those can have special behaviour.
103  *
104  * It is possible to wrap a nullptr in a WebRenderScrollDataWrapper, in which
105  * case the IsValid() function will return false. This is required to allow
106  * WebRenderScrollDataWrapper to be a MOZ_STACK_CLASS (desirable because it is
107  * used in loops and recursion).
108  *
109  * This class purposely does not expose the wrapped layer directly to avoid
110  * user code from accidentally calling functions directly on it. Instead
111  * any necessary functions should be wrapped in this class. It does expose
112  * the wrapped layer as a void* for printf purposes.
113  *
114  * The implementation may look like it special-cases mIndex == 0 and/or
115  * GetScrollMetadataCount() == 0. This is an artifact of the fact that both
116  * mIndex and GetScrollMetadataCount() are uint32_t and GetScrollMetadataCount()
117  * can return 0 but mIndex cannot store -1. This seems better than the
118  * alternative of making mIndex a int32_t that can store -1, but then having
119  * to cast to uint32_t all over the place.
120  *
121  * Note that WebRenderLayerScrollData objects are owned by WebRenderScrollData,
122  * which stores them in a flattened representation. The field mData,
123  * mLayerIndex, and mContainingSubtreeIndex are used to move around the "layers"
124  * given the flattened representation. The mMetadataIndex is used to move around
125  * the ScrollMetadata within a single layer.
126  *
127  * One important note here is that this class holds a pointer to the "owning"
128  * WebRenderScrollData. The caller must ensure that this class does not outlive
129  * the owning WebRenderScrollData, or this may result in use-after-free errors.
130  * This class being declared a MOZ_STACK_CLASS should help with that.
131  */
132 class MOZ_STACK_CLASS WebRenderScrollDataWrapper final {
133  public:
134   // Basic constructor for external callers. Starts the walker at the root of
135   // the tree.
136   explicit WebRenderScrollDataWrapper(
137       const APZUpdater& aUpdater, const WebRenderScrollData* aData = nullptr)
138       : mUpdater(&aUpdater),
139         mData(aData),
140         mLayerIndex(0),
141         mContainingSubtreeLastIndex(0),
142         mLayer(nullptr),
143         mMetadataIndex(0) {
144     if (!mData) {
145       return;
146     }
147     mLayer = mData->GetLayerData(mLayerIndex);
148     if (!mLayer) {
149       return;
150     }
151 
152     // sanity check on the data
153     MOZ_ASSERT(mData->GetLayerCount() ==
154                (size_t)(1 + mLayer->GetDescendantCount()));
155     mContainingSubtreeLastIndex = mData->GetLayerCount();
156 
157     // See documentation in LayerMetricsWrapper.h about this. mMetadataIndex
158     // in this class is equivalent to mIndex in that class.
159     mMetadataIndex = mLayer->GetScrollMetadataCount();
160     if (mMetadataIndex > 0) {
161       mMetadataIndex--;
162     }
163   }
164 
165  private:
166   // Internal constructor for walking from one WebRenderLayerScrollData to
167   // another. In this case we need to recompute the mMetadataIndex to be the
168   // "topmost" scroll metadata on the new layer.
WebRenderScrollDataWrapper(const APZUpdater * aUpdater,const WebRenderScrollData * aData,size_t aLayerIndex,size_t aContainingSubtreeLastIndex)169   WebRenderScrollDataWrapper(const APZUpdater* aUpdater,
170                              const WebRenderScrollData* aData,
171                              size_t aLayerIndex,
172                              size_t aContainingSubtreeLastIndex)
173       : mUpdater(aUpdater),
174         mData(aData),
175         mLayerIndex(aLayerIndex),
176         mContainingSubtreeLastIndex(aContainingSubtreeLastIndex),
177         mLayer(nullptr),
178         mMetadataIndex(0) {
179     MOZ_ASSERT(mData);
180     mLayer = mData->GetLayerData(mLayerIndex);
181     MOZ_ASSERT(mLayer);
182 
183     // See documentation in LayerMetricsWrapper.h about this. mMetadataIndex
184     // in this class is equivalent to mIndex in that class.
185     mMetadataIndex = mLayer->GetScrollMetadataCount();
186     if (mMetadataIndex > 0) {
187       mMetadataIndex--;
188     }
189   }
190 
191   // Internal constructor for walking from one metadata to another metadata on
192   // the same WebRenderLayerScrollData.
WebRenderScrollDataWrapper(const APZUpdater * aUpdater,const WebRenderScrollData * aData,size_t aLayerIndex,size_t aContainingSubtreeLastIndex,const WebRenderLayerScrollData * aLayer,uint32_t aMetadataIndex)193   WebRenderScrollDataWrapper(const APZUpdater* aUpdater,
194                              const WebRenderScrollData* aData,
195                              size_t aLayerIndex,
196                              size_t aContainingSubtreeLastIndex,
197                              const WebRenderLayerScrollData* aLayer,
198                              uint32_t aMetadataIndex)
199       : mUpdater(aUpdater),
200         mData(aData),
201         mLayerIndex(aLayerIndex),
202         mContainingSubtreeLastIndex(aContainingSubtreeLastIndex),
203         mLayer(aLayer),
204         mMetadataIndex(aMetadataIndex) {
205     MOZ_ASSERT(mData);
206     MOZ_ASSERT(mLayer);
207     MOZ_ASSERT(mLayer == mData->GetLayerData(mLayerIndex));
208     MOZ_ASSERT(mMetadataIndex == 0 ||
209                mMetadataIndex < mLayer->GetScrollMetadataCount());
210   }
211 
212  public:
IsValid()213   bool IsValid() const { return mLayer != nullptr; }
214 
215   explicit operator bool() const { return IsValid(); }
216 
GetLastChild()217   WebRenderScrollDataWrapper GetLastChild() const {
218     MOZ_ASSERT(IsValid());
219 
220     if (!AtBottomLayer()) {
221       // If we're still walking around in the virtual container layers created
222       // by the ScrollMetadata array, we just need to update the metadata index
223       // and that's it.
224       return WebRenderScrollDataWrapper(mUpdater, mData, mLayerIndex,
225                                         mContainingSubtreeLastIndex, mLayer,
226                                         mMetadataIndex - 1);
227     }
228 
229     // Otherwise, we need to walk to a different WebRenderLayerScrollData in
230     // mData.
231 
232     // Since mData contains the layer in depth-first, last-to-first order,
233     // the index after mLayerIndex must be mLayerIndex's last child, if it
234     // has any children (indicated by GetDescendantCount() > 0). Furthermore
235     // we compute the first index outside the subtree rooted at this node
236     // (in |subtreeLastIndex|) and pass that in to the child wrapper to use as
237     // its mContainingSubtreeLastIndex.
238     if (mLayer->GetDescendantCount() > 0) {
239       size_t prevSiblingIndex = mLayerIndex + 1 + mLayer->GetDescendantCount();
240       size_t subtreeLastIndex =
241           std::min(mContainingSubtreeLastIndex, prevSiblingIndex);
242       return WebRenderScrollDataWrapper(mUpdater, mData, mLayerIndex + 1,
243                                         subtreeLastIndex);
244     }
245 
246     // We've run out of descendants. But! If the original layer was a RefLayer,
247     // then it connects to another layer tree and we need to traverse that too.
248     // So return a WebRenderScrollDataWrapper for the root of the child layer
249     // tree.
250     if (mLayer->GetReferentId()) {
251       return WebRenderScrollDataWrapper(
252           *mUpdater, mUpdater->GetScrollData(*mLayer->GetReferentId()));
253     }
254 
255     return WebRenderScrollDataWrapper(*mUpdater);
256   }
257 
GetPrevSibling()258   WebRenderScrollDataWrapper GetPrevSibling() const {
259     MOZ_ASSERT(IsValid());
260 
261     if (!AtTopLayer()) {
262       // The virtual container layers don't have siblings
263       return WebRenderScrollDataWrapper(*mUpdater);
264     }
265 
266     // Skip past the descendants to get to the previous sibling. However, we
267     // might be at the last sibling already.
268     size_t prevSiblingIndex = mLayerIndex + 1 + mLayer->GetDescendantCount();
269     if (prevSiblingIndex < mContainingSubtreeLastIndex) {
270       return WebRenderScrollDataWrapper(mUpdater, mData, prevSiblingIndex,
271                                         mContainingSubtreeLastIndex);
272     }
273     return WebRenderScrollDataWrapper(*mUpdater);
274   }
275 
Metadata()276   const ScrollMetadata& Metadata() const {
277     MOZ_ASSERT(IsValid());
278 
279     if (mMetadataIndex >= mLayer->GetScrollMetadataCount()) {
280       return *ScrollMetadata::sNullMetadata;
281     }
282     return mLayer->GetScrollMetadata(*mData, mMetadataIndex);
283   }
284 
Metrics()285   const FrameMetrics& Metrics() const { return Metadata().GetMetrics(); }
286 
GetApzc()287   AsyncPanZoomController* GetApzc() const { return nullptr; }
288 
SetApzc(AsyncPanZoomController * aApzc)289   void SetApzc(AsyncPanZoomController* aApzc) const {}
290 
Name()291   const char* Name() const { return "WebRenderScrollDataWrapper"; }
292 
GetTransform()293   gfx::Matrix4x4 GetTransform() const {
294     MOZ_ASSERT(IsValid());
295 
296     // See WebRenderLayerScrollData::Initialize for more context.
297     //  * The ancestor transform is associated with whichever layer has scroll
298     //    id matching GetAncestorTransformId().
299     //  * The resolution is associated with the "topmost" layer.
300     //  * The transform is associated with the "bottommost" layer.
301     // Multiple transforms may apply to the same layer (e.g. if there is only
302     // one scrollmetadata on the layer, then it is both "topmost" and
303     // "bottommost"), so we may need to combine the transforms.
304 
305     gfx::Matrix4x4 transform;
306     // The ancestor transform is usually emitted at the layer with the
307     // matching scroll id. However, sometimes the transform ends up on
308     // a node with no scroll metadata at all. In such cases we generate
309     // a single layer, and the ancestor transform needs to be on that layer,
310     // otherwise it will be lost.
311     bool emitAncestorTransform =
312         !Metrics().IsScrollable() ||
313         Metrics().GetScrollId() == mLayer->GetAncestorTransformId();
314     if (emitAncestorTransform) {
315       transform = mLayer->GetAncestorTransform();
316     }
317     if (AtTopLayer()) {
318       float resolution = mLayer->GetResolution();
319       transform =
320           transform * gfx::Matrix4x4::Scaling(resolution, resolution, 1.f);
321     }
322     if (AtBottomLayer()) {
323       transform = mLayer->GetTransform() * transform;
324     }
325     return transform;
326   }
327 
GetTransformTyped()328   CSSTransformMatrix GetTransformTyped() const {
329     return ViewAs<CSSTransformMatrix>(GetTransform());
330   }
331 
TransformIsPerspective()332   bool TransformIsPerspective() const {
333     MOZ_ASSERT(IsValid());
334 
335     // mLayer->GetTransformIsPerspective() tells us whether
336     // mLayer->GetTransform() is a perspective transform. Since
337     // mLayer->GetTransform() is only used at the bottom layer, we only
338     // need to check GetTransformIsPerspective() at the bottom layer too.
339     if (AtBottomLayer()) {
340       return mLayer->GetTransformIsPerspective();
341     }
342     return false;
343   }
344 
GetVisibleRegion()345   LayerIntRegion GetVisibleRegion() const {
346     MOZ_ASSERT(IsValid());
347 
348     if (AtBottomLayer()) {
349       return mLayer->GetVisibleRegion();
350     }
351 
352     return ViewAs<LayerPixel>(
353         TransformBy(mLayer->GetTransformTyped(), mLayer->GetVisibleRegion()),
354         PixelCastJustification::MovingDownToChildren);
355   }
356 
GetRemoteDocumentSize()357   LayerIntSize GetRemoteDocumentSize() const {
358     MOZ_ASSERT(IsValid());
359 
360     if (mLayer->GetReferentId().isNothing()) {
361       return LayerIntSize();
362     }
363 
364     if (AtBottomLayer()) {
365       return mLayer->GetRemoteDocumentSize();
366     }
367 
368     return ViewAs<LayerPixel>(mLayer->GetRemoteDocumentSize(),
369                               PixelCastJustification::MovingDownToChildren);
370   }
371 
GetReferentId()372   Maybe<LayersId> GetReferentId() const {
373     MOZ_ASSERT(IsValid());
374 
375     if (AtBottomLayer()) {
376       return mLayer->GetReferentId();
377     }
378     return Nothing();
379   }
380 
GetEventRegionsOverride()381   EventRegionsOverride GetEventRegionsOverride() const {
382     MOZ_ASSERT(IsValid());
383     // Only ref layers can have an event regions override.
384     if (GetReferentId()) {
385       return mLayer->GetEventRegionsOverride();
386     }
387     return EventRegionsOverride::NoOverride;
388   }
389 
GetScrollbarData()390   const ScrollbarData& GetScrollbarData() const {
391     MOZ_ASSERT(IsValid());
392     return mLayer->GetScrollbarData();
393   }
394 
GetScrollbarAnimationId()395   Maybe<uint64_t> GetScrollbarAnimationId() const {
396     MOZ_ASSERT(IsValid());
397     return mLayer->GetScrollbarAnimationId();
398   }
399 
GetFixedPositionAnimationId()400   Maybe<uint64_t> GetFixedPositionAnimationId() const {
401     MOZ_ASSERT(IsValid());
402 
403     if (AtBottomLayer()) {
404       return mLayer->GetFixedPositionAnimationId();
405     }
406     return Nothing();
407   }
408 
GetFixedPositionScrollContainerId()409   ScrollableLayerGuid::ViewID GetFixedPositionScrollContainerId() const {
410     MOZ_ASSERT(IsValid());
411 
412     if (AtBottomLayer()) {
413       return mLayer->GetFixedPositionScrollContainerId();
414     }
415     return ScrollableLayerGuid::NULL_SCROLL_ID;
416   }
417 
GetFixedPositionSides()418   SideBits GetFixedPositionSides() const {
419     MOZ_ASSERT(IsValid());
420 
421     if (AtBottomLayer()) {
422       return mLayer->GetFixedPositionSides();
423     }
424     return SideBits::eNone;
425   }
426 
GetStickyScrollContainerId()427   ScrollableLayerGuid::ViewID GetStickyScrollContainerId() const {
428     MOZ_ASSERT(IsValid());
429 
430     if (AtBottomLayer()) {
431       return mLayer->GetStickyPositionScrollContainerId();
432     }
433     return ScrollableLayerGuid::NULL_SCROLL_ID;
434   }
435 
GetStickyScrollRangeOuter()436   const LayerRectAbsolute& GetStickyScrollRangeOuter() const {
437     MOZ_ASSERT(IsValid());
438 
439     if (AtBottomLayer()) {
440       return mLayer->GetStickyScrollRangeOuter();
441     }
442 
443     static const LayerRectAbsolute empty;
444     return empty;
445   }
446 
GetStickyScrollRangeInner()447   const LayerRectAbsolute& GetStickyScrollRangeInner() const {
448     MOZ_ASSERT(IsValid());
449 
450     if (AtBottomLayer()) {
451       return mLayer->GetStickyScrollRangeInner();
452     }
453 
454     static const LayerRectAbsolute empty;
455     return empty;
456   }
457 
GetStickyPositionAnimationId()458   Maybe<uint64_t> GetStickyPositionAnimationId() const {
459     MOZ_ASSERT(IsValid());
460 
461     if (AtBottomLayer()) {
462       return mLayer->GetStickyPositionAnimationId();
463     }
464     return Nothing();
465   }
466 
GetZoomAnimationId()467   Maybe<uint64_t> GetZoomAnimationId() const {
468     MOZ_ASSERT(IsValid());
469     return mLayer->GetZoomAnimationId();
470   }
471 
GetAsyncZoomContainerId()472   Maybe<ScrollableLayerGuid::ViewID> GetAsyncZoomContainerId() const {
473     MOZ_ASSERT(IsValid());
474     return mLayer->GetAsyncZoomContainerId();
475   }
476 
477   // Expose an opaque pointer to the layer. Mostly used for printf
478   // purposes. This is not intended to be a general-purpose accessor
479   // for the underlying layer.
GetLayer()480   const void* GetLayer() const {
481     MOZ_ASSERT(IsValid());
482     return mLayer;
483   }
484 
485  private:
AtBottomLayer()486   bool AtBottomLayer() const { return mMetadataIndex == 0; }
487 
AtTopLayer()488   bool AtTopLayer() const {
489     return mLayer->GetScrollMetadataCount() == 0 ||
490            mMetadataIndex == mLayer->GetScrollMetadataCount() - 1;
491   }
492 
493  private:
494   const APZUpdater* mUpdater;
495   const WebRenderScrollData* mData;
496   // The index (in mData->mLayerScrollData) of the WebRenderLayerScrollData this
497   // wrapper is pointing to.
498   size_t mLayerIndex;
499   // The upper bound on the set of valid indices inside the subtree rooted at
500   // the parent of this "layer". That is, any layer index |i| in the range
501   // mLayerIndex <= i < mContainingSubtreeLastIndex is guaranteed to point to
502   // a layer that is a descendant of "parent", where "parent" is the parent
503   // layer of the layer at mLayerIndex. This is needed in order to implement
504   // GetPrevSibling() correctly.
505   size_t mContainingSubtreeLastIndex;
506   // The WebRenderLayerScrollData this wrapper is pointing to.
507   const WebRenderLayerScrollData* mLayer;
508   // The index of the scroll metadata within mLayer that this wrapper is
509   // pointing to.
510   uint32_t mMetadataIndex;
511 };
512 
513 }  // namespace layers
514 }  // namespace mozilla
515 
516 #endif /* GFX_WEBRENDERSCROLLDATAWRAPPER_H */
517