Bug 1632310 [wpt PR 23186] - Add test for computed versus resolved style., a=testonly
[gecko.git] / gfx / layers / LayerMetricsWrapper.h
blob9bf45a6a55a0c0f0faf02d869c336c9ff42ef8bd
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/. */
7 #ifndef GFX_LAYERMETRICSWRAPPER_H
8 #define GFX_LAYERMETRICSWRAPPER_H
10 #include "Layers.h"
11 #include "UnitTransforms.h"
13 namespace mozilla {
14 namespace layers {
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:
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 * +---+ +---+
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:
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 * +---+ +---+
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.
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.
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.
99 * Implementation notes:
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.
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).
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.
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.
123 class MOZ_STACK_CLASS LayerMetricsWrapper final {
124 public:
125 enum StartAt {
126 TOP,
127 BOTTOM,
130 LayerMetricsWrapper() : mLayer(nullptr), mIndex(0) {}
132 explicit LayerMetricsWrapper(Layer* aRoot, StartAt aStart = StartAt::TOP)
133 : mLayer(aRoot), mIndex(0) {
134 if (!mLayer) {
135 return;
138 switch (aStart) {
139 case StartAt::TOP:
140 mIndex = mLayer->GetScrollMetadataCount();
141 if (mIndex > 0) {
142 mIndex--;
144 break;
145 case StartAt::BOTTOM:
146 mIndex = 0;
147 break;
148 default:
149 MOZ_ASSERT_UNREACHABLE("Unknown startAt value");
150 break;
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());
160 bool IsValid() const { return mLayer != nullptr; }
162 explicit operator bool() const { return IsValid(); }
164 LayerMetricsWrapper GetParent() const {
165 MOZ_ASSERT(IsValid());
167 if (!AtTopLayer()) {
168 return LayerMetricsWrapper(mLayer, mIndex + 1);
170 if (mLayer->GetParent()) {
171 return LayerMetricsWrapper(mLayer->GetParent(), StartAt::BOTTOM);
173 return LayerMetricsWrapper(nullptr);
176 LayerMetricsWrapper GetFirstChild() const {
177 MOZ_ASSERT(IsValid());
179 if (!AtBottomLayer()) {
180 return LayerMetricsWrapper(mLayer, mIndex - 1);
182 return LayerMetricsWrapper(mLayer->GetFirstChild());
185 LayerMetricsWrapper GetLastChild() const {
186 MOZ_ASSERT(IsValid());
188 if (!AtBottomLayer()) {
189 return LayerMetricsWrapper(mLayer, mIndex - 1);
191 return LayerMetricsWrapper(mLayer->GetLastChild());
194 LayerMetricsWrapper GetPrevSibling() const {
195 MOZ_ASSERT(IsValid());
197 if (AtTopLayer()) {
198 return LayerMetricsWrapper(mLayer->GetPrevSibling());
200 return LayerMetricsWrapper(nullptr);
203 LayerMetricsWrapper GetNextSibling() const {
204 MOZ_ASSERT(IsValid());
206 if (AtTopLayer()) {
207 return LayerMetricsWrapper(mLayer->GetNextSibling());
209 return LayerMetricsWrapper(nullptr);
212 const ScrollMetadata& Metadata() const {
213 MOZ_ASSERT(IsValid());
215 if (mIndex >= mLayer->GetScrollMetadataCount()) {
216 return *ScrollMetadata::sNullMetadata;
218 return mLayer->GetScrollMetadata(mIndex);
221 const FrameMetrics& Metrics() const { return Metadata().GetMetrics(); }
223 AsyncPanZoomController* GetApzc() const {
224 MOZ_ASSERT(IsValid());
226 if (mIndex >= mLayer->GetScrollMetadataCount()) {
227 return nullptr;
229 return mLayer->GetAsyncPanZoomController(mIndex);
232 void SetApzc(AsyncPanZoomController* aApzc) const {
233 MOZ_ASSERT(IsValid());
235 if (mLayer->GetScrollMetadataCount() == 0) {
236 MOZ_ASSERT(mIndex == 0);
237 MOZ_ASSERT(aApzc == nullptr);
238 return;
240 MOZ_ASSERT(mIndex < mLayer->GetScrollMetadataCount());
241 mLayer->SetAsyncPanZoomController(mIndex, aApzc);
244 const char* Name() const {
245 MOZ_ASSERT(IsValid());
247 if (AtBottomLayer()) {
248 return mLayer->Name();
250 return "DummyContainerLayer";
253 LayerManager* Manager() const {
254 MOZ_ASSERT(IsValid());
256 return mLayer->Manager();
259 gfx::Matrix4x4 GetTransform() const {
260 MOZ_ASSERT(IsValid());
262 if (AtBottomLayer()) {
263 return mLayer->GetTransform();
265 return gfx::Matrix4x4();
268 CSSTransformMatrix GetTransformTyped() const {
269 return ViewAs<CSSTransformMatrix>(GetTransform());
272 bool TransformIsPerspective() const {
273 MOZ_ASSERT(IsValid());
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();
282 return false;
285 bool Combines3DTransformWithAncestors() const {
286 MOZ_ASSERT(IsValid());
288 return mLayer->Combines3DTransformWithAncestors();
291 EventRegions GetEventRegions() const {
292 MOZ_ASSERT(IsValid());
294 if (AtBottomLayer()) {
295 return mLayer->GetEventRegions();
297 return EventRegions();
300 LayerIntRegion GetVisibleRegion() const {
301 MOZ_ASSERT(IsValid());
303 if (AtBottomLayer()) {
304 return mLayer->GetVisibleRegion();
307 return ViewAs<LayerPixel>(
308 TransformBy(mLayer->GetTransformTyped(), mLayer->GetVisibleRegion()),
309 PixelCastJustification::MovingDownToChildren);
312 LayerIntSize GetRemoteDocumentSize() const {
313 MOZ_ASSERT(IsValid());
315 return AsRefLayer() ? AsRefLayer()->GetRemoteDocumentSize()
316 : LayerIntSize();
319 bool HasTransformAnimation() const {
320 MOZ_ASSERT(IsValid());
322 if (AtBottomLayer()) {
323 return mLayer->HasTransformAnimation();
325 return false;
328 RefLayer* AsRefLayer() const {
329 MOZ_ASSERT(IsValid());
331 if (AtBottomLayer()) {
332 return mLayer->AsRefLayer();
334 return nullptr;
337 Maybe<LayersId> GetReferentId() const {
338 MOZ_ASSERT(IsValid());
340 if (AtBottomLayer()) {
341 return mLayer->AsRefLayer() ? Some(mLayer->AsRefLayer()->GetReferentId())
342 : Nothing();
344 return Nothing();
347 Maybe<ParentLayerIntRect> GetClipRect() const {
348 MOZ_ASSERT(IsValid());
350 Maybe<ParentLayerIntRect> result;
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());
362 // The scroll metadata can have a clip rect as well.
363 result = IntersectMaybeRects(result, Metadata().GetClipRect());
365 return result;
368 float GetPresShellResolution() const {
369 MOZ_ASSERT(IsValid());
371 if (AtTopLayer() && mLayer->AsContainerLayer()) {
372 return mLayer->AsContainerLayer()->GetPresShellResolution();
375 return 1.0f;
378 EventRegionsOverride GetEventRegionsOverride() const {
379 MOZ_ASSERT(IsValid());
381 if (AsRefLayer()) {
382 return AsRefLayer()->GetEventRegionsOverride();
384 return EventRegionsOverride::NoOverride;
387 const ScrollbarData& GetScrollbarData() const {
388 MOZ_ASSERT(IsValid());
390 return mLayer->GetScrollbarData();
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();
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();
409 ScrollableLayerGuid::ViewID GetFixedPositionScrollContainerId() const {
410 MOZ_ASSERT(IsValid());
412 if (AtBottomLayer()) {
413 return mLayer->GetFixedPositionScrollContainerId();
415 return ScrollableLayerGuid::NULL_SCROLL_ID;
418 SideBits GetFixedPositionSides() const {
419 MOZ_ASSERT(IsValid());
421 if (AtBottomLayer()) {
422 return mLayer->GetFixedPositionSides();
424 return SideBits::eNone;
427 ScrollableLayerGuid::ViewID GetStickyScrollContainerId() const {
428 MOZ_ASSERT(IsValid());
430 if (AtBottomLayer() && mLayer->GetIsStickyPosition()) {
431 return mLayer->GetStickyScrollContainerId();
433 return ScrollableLayerGuid::NULL_SCROLL_ID;
436 const LayerRectAbsolute& GetStickyScrollRangeOuter() const {
437 MOZ_ASSERT(IsValid());
439 if (AtBottomLayer() && mLayer->GetIsStickyPosition()) {
440 return mLayer->GetStickyScrollRangeOuter();
443 static const LayerRectAbsolute empty;
444 return empty;
447 const LayerRectAbsolute& GetStickyScrollRangeInner() const {
448 MOZ_ASSERT(IsValid());
450 if (AtBottomLayer() && mLayer->GetIsStickyPosition()) {
451 return mLayer->GetStickyScrollRangeInner();
454 static const LayerRectAbsolute empty;
455 return empty;
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();
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();
474 bool IsBackfaceHidden() const {
475 MOZ_ASSERT(IsValid());
477 return mLayer->IsBackfaceHidden();
480 Maybe<ScrollableLayerGuid::ViewID> IsAsyncZoomContainer() const {
481 MOZ_ASSERT(IsValid());
483 return mLayer->IsAsyncZoomContainer();
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.
489 const void* GetLayer() const {
490 MOZ_ASSERT(IsValid());
492 return (void*)mLayer;
495 bool operator==(const LayerMetricsWrapper& aOther) const {
496 return mLayer == aOther.mLayer && mIndex == aOther.mIndex;
499 bool operator!=(const LayerMetricsWrapper& aOther) const {
500 return !(*this == aOther);
503 private:
504 bool AtBottomLayer() const { return mIndex == 0; }
506 bool AtTopLayer() const {
507 return mLayer->GetScrollMetadataCount() == 0 ||
508 mIndex == mLayer->GetScrollMetadataCount() - 1;
511 private:
512 Layer* mLayer;
513 uint32_t mIndex;
516 } // namespace layers
517 } // namespace mozilla
519 #endif /* GFX_LAYERMETRICSWRAPPER_H */