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_LAYERMETRICSWRAPPER_H
8 #define GFX_LAYERMETRICSWRAPPER_H
9 
10 #include "Layers.h"
11 #include "UnitTransforms.h"
12 
13 namespace mozilla {
14 namespace layers {
15 
16 /**
17  * A wrapper class around a target Layer with that allows user code to
18  * walk through the FrameMetrics objects on the layer the same way it
19  * would walk through a ContainerLayer hierarchy. Consider the following
20  * layer tree:
21  *
22  *                    +---+
23  *                    | A |
24  *                    +---+
25  *                   /  |  \
26  *                  /   |   \
27  *                 /    |    \
28  *            +---+  +-----+  +---+
29  *            | B |  |  C  |  | D |
30  *            +---+  +-----+  +---+
31  *                   | FMn |
32  *                   |  .  |
33  *                   |  .  |
34  *                   |  .  |
35  *                   | FM1 |
36  *                   | FM0 |
37  *                   +-----+
38  *                   /     \
39  *                  /       \
40  *             +---+         +---+
41  *             | E |         | F |
42  *             +---+         +---+
43  *
44  * In this layer tree, there are six layers with A being the root and B,D,E,F
45  * being leaf nodes. Layer C is in the middle and has n+1 FrameMetrics, labelled
46  * FM0...FMn. FM0 is the FrameMetrics you get by calling c->GetFrameMetrics(0)
47  * and FMn is the FrameMetrics you can obtain by calling
48  * c->GetFrameMetrics(c->GetScrollMetadataCount() - 1). This layer tree is
49  * conceptually equivalent to this one below:
50  *
51  *                    +---+
52  *                    | A |
53  *                    +---+
54  *                   /  |  \
55  *                  /   |   \
56  *                 /    |    \
57  *            +---+  +-----+  +---+
58  *            | B |  | Cn  |  | D |
59  *            +---+  +-----+  +---+
60  *                      |
61  *                      .
62  *                      .
63  *                      .
64  *                      |
65  *                   +-----+
66  *                   | C1  |
67  *                   +-----+
68  *                      |
69  *                   +-----+
70  *                   | C0  |
71  *                   +-----+
72  *                   /     \
73  *                  /       \
74  *             +---+         +---+
75  *             | E |         | F |
76  *             +---+         +---+
77  *
78  * In this layer tree, the layer C has been expanded into a stack of container
79  * layers C1...Cn, where C1 has FrameMetrics FM1 and Cn has FrameMetrics Fn.
80  * Although in this example C (in the first layer tree) and C0 (in the second
81  * layer tree) are both ContainerLayers (because they have children), they
82  * do not have to be. They may just be PaintedLayers or ColorLayers, for
83  * example, which do not have any children. However, the type of C will always
84  * be the same as the type of C0.
85  *
86  * The LayerMetricsWrapper class allows client code to treat the first layer
87  * tree as though it were the second. That is, instead of client code having
88  * to iterate through the FrameMetrics objects directly, it can use a
89  * LayerMetricsWrapper to encapsulate that aspect of the layer tree and just
90  * walk the tree as if it were a stack of ContainerLayers.
91  *
92  * The functions on this class do different things depending on which
93  * simulated ContainerLayer is being wrapped. For example, if the
94  * LayerMetricsWrapper is pretending to be C0, the GetNextSibling() function
95  * will return null even though the underlying layer C does actually have
96  * a next sibling. The LayerMetricsWrapper pretending to be Cn will return
97  * D as the next sibling.
98  *
99  * Implementation notes:
100  *
101  * The AtTopLayer() and AtBottomLayer() functions in this class refer to
102  * Cn and C0 in the second layer tree above; that is, they are predicates
103  * to test if the LayerMetricsWrapper is simulating the topmost or bottommost
104  * layer, as those will have special behaviour.
105  *
106  * It is possible to wrap a nullptr in a LayerMetricsWrapper, in which case
107  * the IsValid() function will return false. This is required to allow
108  * LayerMetricsWrapper to be a MOZ_STACK_CLASS (desirable because it is used
109  * in loops and recursion).
110  *
111  * This class purposely does not expose the wrapped layer directly to avoid
112  * user code from accidentally calling functions directly on it. Instead
113  * any necessary functions should be wrapped in this class. It does expose
114  * the wrapped layer as a void* for printf purposes.
115  *
116  * The implementation may look like it special-cases mIndex == 0 and/or
117  * GetScrollMetadataCount() == 0. This is an artifact of the fact that both
118  * mIndex and GetScrollMetadataCount() are uint32_t and GetScrollMetadataCount()
119  * can return 0 but mIndex cannot store -1. This seems better than the
120  * alternative of making mIndex a int32_t that can store -1, but then having
121  * to cast to uint32_t all over the place.
122  */
123 class MOZ_STACK_CLASS LayerMetricsWrapper final {
124  public:
125   enum StartAt {
126     TOP,
127     BOTTOM,
128   };
129 
LayerMetricsWrapper()130   LayerMetricsWrapper() : mLayer(nullptr), mIndex(0) {}
131 
132   explicit LayerMetricsWrapper(Layer* aRoot, StartAt aStart = StartAt::TOP)
mLayer(aRoot)133       : mLayer(aRoot), mIndex(0) {
134     if (!mLayer) {
135       return;
136     }
137 
138     switch (aStart) {
139       case StartAt::TOP:
140         mIndex = mLayer->GetScrollMetadataCount();
141         if (mIndex > 0) {
142           mIndex--;
143         }
144         break;
145       case StartAt::BOTTOM:
146         mIndex = 0;
147         break;
148       default:
149         MOZ_ASSERT_UNREACHABLE("Unknown startAt value");
150         break;
151     }
152   }
153 
LayerMetricsWrapper(Layer * aLayer,uint32_t aMetricsIndex)154   explicit LayerMetricsWrapper(Layer* aLayer, uint32_t aMetricsIndex)
155       : mLayer(aLayer), mIndex(aMetricsIndex) {
156     MOZ_ASSERT(mLayer);
157     MOZ_ASSERT(mIndex == 0 || mIndex < mLayer->GetScrollMetadataCount());
158   }
159 
IsValid()160   bool IsValid() const { return mLayer != nullptr; }
161 
162   explicit operator bool() const { return IsValid(); }
163 
GetParent()164   LayerMetricsWrapper GetParent() const {
165     MOZ_ASSERT(IsValid());
166 
167     if (!AtTopLayer()) {
168       return LayerMetricsWrapper(mLayer, mIndex + 1);
169     }
170     if (mLayer->GetParent()) {
171       return LayerMetricsWrapper(mLayer->GetParent(), StartAt::BOTTOM);
172     }
173     return LayerMetricsWrapper(nullptr);
174   }
175 
GetFirstChild()176   LayerMetricsWrapper GetFirstChild() const {
177     MOZ_ASSERT(IsValid());
178 
179     if (!AtBottomLayer()) {
180       return LayerMetricsWrapper(mLayer, mIndex - 1);
181     }
182     return LayerMetricsWrapper(mLayer->GetFirstChild());
183   }
184 
GetLastChild()185   LayerMetricsWrapper GetLastChild() const {
186     MOZ_ASSERT(IsValid());
187 
188     if (!AtBottomLayer()) {
189       return LayerMetricsWrapper(mLayer, mIndex - 1);
190     }
191     return LayerMetricsWrapper(mLayer->GetLastChild());
192   }
193 
GetPrevSibling()194   LayerMetricsWrapper GetPrevSibling() const {
195     MOZ_ASSERT(IsValid());
196 
197     if (AtTopLayer()) {
198       return LayerMetricsWrapper(mLayer->GetPrevSibling());
199     }
200     return LayerMetricsWrapper(nullptr);
201   }
202 
GetNextSibling()203   LayerMetricsWrapper GetNextSibling() const {
204     MOZ_ASSERT(IsValid());
205 
206     if (AtTopLayer()) {
207       return LayerMetricsWrapper(mLayer->GetNextSibling());
208     }
209     return LayerMetricsWrapper(nullptr);
210   }
211 
Metadata()212   const ScrollMetadata& Metadata() const {
213     MOZ_ASSERT(IsValid());
214 
215     if (mIndex >= mLayer->GetScrollMetadataCount()) {
216       return *ScrollMetadata::sNullMetadata;
217     }
218     return mLayer->GetScrollMetadata(mIndex);
219   }
220 
Metrics()221   const FrameMetrics& Metrics() const { return Metadata().GetMetrics(); }
222 
GetApzc()223   AsyncPanZoomController* GetApzc() const {
224     MOZ_ASSERT(IsValid());
225 
226     if (mIndex >= mLayer->GetScrollMetadataCount()) {
227       return nullptr;
228     }
229     return mLayer->GetAsyncPanZoomController(mIndex);
230   }
231 
SetApzc(AsyncPanZoomController * aApzc)232   void SetApzc(AsyncPanZoomController* aApzc) const {
233     MOZ_ASSERT(IsValid());
234 
235     if (mLayer->GetScrollMetadataCount() == 0) {
236       MOZ_ASSERT(mIndex == 0);
237       MOZ_ASSERT(aApzc == nullptr);
238       return;
239     }
240     MOZ_ASSERT(mIndex < mLayer->GetScrollMetadataCount());
241     mLayer->SetAsyncPanZoomController(mIndex, aApzc);
242   }
243 
Name()244   const char* Name() const {
245     MOZ_ASSERT(IsValid());
246 
247     if (AtBottomLayer()) {
248       return mLayer->Name();
249     }
250     return "DummyContainerLayer";
251   }
252 
Manager()253   LayerManager* Manager() const {
254     MOZ_ASSERT(IsValid());
255 
256     return mLayer->Manager();
257   }
258 
GetTransform()259   gfx::Matrix4x4 GetTransform() const {
260     MOZ_ASSERT(IsValid());
261 
262     if (AtBottomLayer()) {
263       return mLayer->GetTransform();
264     }
265     return gfx::Matrix4x4();
266   }
267 
GetTransformTyped()268   CSSTransformMatrix GetTransformTyped() const {
269     return ViewAs<CSSTransformMatrix>(GetTransform());
270   }
271 
TransformIsPerspective()272   bool TransformIsPerspective() const {
273     MOZ_ASSERT(IsValid());
274 
275     // mLayer->GetTransformIsPerspective() tells us whether
276     // mLayer->GetTransform() is a perspective transform. Since
277     // mLayer->GetTransform() is only used at the bottom layer, we only
278     // need to check GetTransformIsPerspective() at the bottom layer too.
279     if (AtBottomLayer()) {
280       return mLayer->GetTransformIsPerspective();
281     }
282     return false;
283   }
284 
Combines3DTransformWithAncestors()285   bool Combines3DTransformWithAncestors() const {
286     MOZ_ASSERT(IsValid());
287 
288     return mLayer->Combines3DTransformWithAncestors();
289   }
290 
GetEventRegions()291   EventRegions GetEventRegions() const {
292     MOZ_ASSERT(IsValid());
293 
294     if (AtBottomLayer()) {
295       return mLayer->GetEventRegions();
296     }
297     return EventRegions();
298   }
299 
GetVisibleRegion()300   LayerIntRegion GetVisibleRegion() const {
301     MOZ_ASSERT(IsValid());
302 
303     if (AtBottomLayer()) {
304       return mLayer->GetVisibleRegion();
305     }
306 
307     return ViewAs<LayerPixel>(
308         TransformBy(mLayer->GetTransformTyped(), mLayer->GetVisibleRegion()),
309         PixelCastJustification::MovingDownToChildren);
310   }
311 
GetRemoteDocumentSize()312   LayerIntSize GetRemoteDocumentSize() const {
313     MOZ_ASSERT(IsValid());
314 
315     return AsRefLayer() ? AsRefLayer()->GetRemoteDocumentSize()
316                         : LayerIntSize();
317   }
318 
HasTransformAnimation()319   bool HasTransformAnimation() const {
320     MOZ_ASSERT(IsValid());
321 
322     if (AtBottomLayer()) {
323       return mLayer->HasTransformAnimation();
324     }
325     return false;
326   }
327 
AsRefLayer()328   RefLayer* AsRefLayer() const {
329     MOZ_ASSERT(IsValid());
330 
331     if (AtBottomLayer()) {
332       return mLayer->AsRefLayer();
333     }
334     return nullptr;
335   }
336 
GetReferentId()337   Maybe<LayersId> GetReferentId() const {
338     MOZ_ASSERT(IsValid());
339 
340     if (AtBottomLayer()) {
341       return mLayer->AsRefLayer() ? Some(mLayer->AsRefLayer()->GetReferentId())
342                                   : Nothing();
343     }
344     return Nothing();
345   }
346 
GetClipRect()347   Maybe<ParentLayerIntRect> GetClipRect() const {
348     MOZ_ASSERT(IsValid());
349 
350     Maybe<ParentLayerIntRect> result;
351 
352     // The layer can have a clip rect and a scrolled clip, which are considered
353     // to apply only to the bottommost LayerMetricsWrapper.
354     // TODO: These actually apply in a different coordinate space than the
355     // scroll clip of the bottommost metrics, so we shouldn't be intersecting
356     // them with the scroll clip; bug 1269537 tracks fixing this.
357     if (AtBottomLayer()) {
358       result = mLayer->GetClipRect();
359       result = IntersectMaybeRects(result, mLayer->GetScrolledClipRect());
360     }
361 
362     // The scroll metadata can have a clip rect as well.
363     result = IntersectMaybeRects(result, Metadata().GetClipRect());
364 
365     return result;
366   }
367 
GetPresShellResolution()368   float GetPresShellResolution() const {
369     MOZ_ASSERT(IsValid());
370 
371     if (AtTopLayer() && mLayer->AsContainerLayer()) {
372       return mLayer->AsContainerLayer()->GetPresShellResolution();
373     }
374 
375     return 1.0f;
376   }
377 
GetEventRegionsOverride()378   EventRegionsOverride GetEventRegionsOverride() const {
379     MOZ_ASSERT(IsValid());
380 
381     if (AsRefLayer()) {
382       return AsRefLayer()->GetEventRegionsOverride();
383     }
384     return EventRegionsOverride::NoOverride;
385   }
386 
GetScrollbarData()387   const ScrollbarData& GetScrollbarData() const {
388     MOZ_ASSERT(IsValid());
389 
390     return mLayer->GetScrollbarData();
391   }
392 
GetScrollbarAnimationId()393   Maybe<uint64_t> GetScrollbarAnimationId() const {
394     MOZ_ASSERT(IsValid());
395     // This function is only really needed for template-compatibility with
396     // WebRenderScrollDataWrapper. Although it will be called, the return
397     // value is not used.
398     return Nothing();
399   }
400 
GetFixedPositionAnimationId()401   Maybe<uint64_t> GetFixedPositionAnimationId() const {
402     MOZ_ASSERT(IsValid());
403     // This function is only really needed for template-compatibility with
404     // WebRenderScrollDataWrapper. Although it will be called, the return
405     // value is not used.
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() && mLayer->GetIsStickyPosition()) {
431       return mLayer->GetStickyScrollContainerId();
432     }
433     return ScrollableLayerGuid::NULL_SCROLL_ID;
434   }
435 
GetStickyScrollRangeOuter()436   const LayerRectAbsolute& GetStickyScrollRangeOuter() const {
437     MOZ_ASSERT(IsValid());
438 
439     if (AtBottomLayer() && mLayer->GetIsStickyPosition()) {
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() && mLayer->GetIsStickyPosition()) {
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     // This function is only really needed for template-compatibility with
461     // WebRenderScrollDataWrapper. Although it will be called, the return
462     // value is not used.
463     return Nothing();
464   }
465 
GetZoomAnimationId()466   Maybe<uint64_t> GetZoomAnimationId() const {
467     MOZ_ASSERT(IsValid());
468     // This function is only really needed for template-compatibility with
469     // WebRenderScrollDataWrapper. Although it will be called, the return
470     // value is not used.
471     return Nothing();
472   }
473 
IsBackfaceHidden()474   bool IsBackfaceHidden() const {
475     MOZ_ASSERT(IsValid());
476 
477     return mLayer->IsBackfaceHidden();
478   }
479 
GetAsyncZoomContainerId()480   Maybe<ScrollableLayerGuid::ViewID> GetAsyncZoomContainerId() const {
481     MOZ_ASSERT(IsValid());
482 
483     return mLayer->GetAsyncZoomContainerId();
484   }
485 
486   // Expose an opaque pointer to the layer. Mostly used for printf
487   // purposes. This is not intended to be a general-purpose accessor
488   // for the underlying layer.
GetLayer()489   const void* GetLayer() const {
490     MOZ_ASSERT(IsValid());
491 
492     return (void*)mLayer;
493   }
494 
495   bool operator==(const LayerMetricsWrapper& aOther) const {
496     return mLayer == aOther.mLayer && mIndex == aOther.mIndex;
497   }
498 
499   bool operator!=(const LayerMetricsWrapper& aOther) const {
500     return !(*this == aOther);
501   }
502 
503  private:
AtBottomLayer()504   bool AtBottomLayer() const { return mIndex == 0; }
505 
AtTopLayer()506   bool AtTopLayer() const {
507     return mLayer->GetScrollMetadataCount() == 0 ||
508            mIndex == mLayer->GetScrollMetadataCount() - 1;
509   }
510 
511  private:
512   Layer* mLayer;
513   uint32_t mIndex;
514 };
515 
516 }  // namespace layers
517 }  // namespace mozilla
518 
519 #endif /* GFX_LAYERMETRICSWRAPPER_H */
520