summaryrefslogtreecommitdiffstats
path: root/gfx/layers/LayerMetricsWrapper.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--gfx/layers/LayerMetricsWrapper.h519
1 files changed, 519 insertions, 0 deletions
diff --git a/gfx/layers/LayerMetricsWrapper.h b/gfx/layers/LayerMetricsWrapper.h
new file mode 100644
index 0000000000..9bf45a6a55
--- /dev/null
+++ b/gfx/layers/LayerMetricsWrapper.h
@@ -0,0 +1,519 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_LAYERMETRICSWRAPPER_H
+#define GFX_LAYERMETRICSWRAPPER_H
+
+#include "Layers.h"
+#include "UnitTransforms.h"
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * A wrapper class around a target Layer with that allows user code to
+ * walk through the FrameMetrics objects on the layer the same way it
+ * would walk through a ContainerLayer hierarchy. Consider the following
+ * layer tree:
+ *
+ * +---+
+ * | A |
+ * +---+
+ * / | \
+ * / | \
+ * / | \
+ * +---+ +-----+ +---+
+ * | B | | C | | D |
+ * +---+ +-----+ +---+
+ * | FMn |
+ * | . |
+ * | . |
+ * | . |
+ * | FM1 |
+ * | FM0 |
+ * +-----+
+ * / \
+ * / \
+ * +---+ +---+
+ * | E | | F |
+ * +---+ +---+
+ *
+ * In this layer tree, there are six layers with A being the root and B,D,E,F
+ * being leaf nodes. Layer C is in the middle and has n+1 FrameMetrics, labelled
+ * FM0...FMn. FM0 is the FrameMetrics you get by calling c->GetFrameMetrics(0)
+ * and FMn is the FrameMetrics you can obtain by calling
+ * c->GetFrameMetrics(c->GetScrollMetadataCount() - 1). This layer tree is
+ * conceptually equivalent to this one below:
+ *
+ * +---+
+ * | A |
+ * +---+
+ * / | \
+ * / | \
+ * / | \
+ * +---+ +-----+ +---+
+ * | B | | Cn | | D |
+ * +---+ +-----+ +---+
+ * |
+ * .
+ * .
+ * .
+ * |
+ * +-----+
+ * | C1 |
+ * +-----+
+ * |
+ * +-----+
+ * | C0 |
+ * +-----+
+ * / \
+ * / \
+ * +---+ +---+
+ * | E | | F |
+ * +---+ +---+
+ *
+ * In this layer tree, the layer C has been expanded into a stack of container
+ * layers C1...Cn, where C1 has FrameMetrics FM1 and Cn has FrameMetrics Fn.
+ * Although in this example C (in the first layer tree) and C0 (in the second
+ * layer tree) are both ContainerLayers (because they have children), they
+ * do not have to be. They may just be PaintedLayers or ColorLayers, for
+ * example, which do not have any children. However, the type of C will always
+ * be the same as the type of C0.
+ *
+ * The LayerMetricsWrapper class allows client code to treat the first layer
+ * tree as though it were the second. That is, instead of client code having
+ * to iterate through the FrameMetrics objects directly, it can use a
+ * LayerMetricsWrapper to encapsulate that aspect of the layer tree and just
+ * walk the tree as if it were a stack of ContainerLayers.
+ *
+ * The functions on this class do different things depending on which
+ * simulated ContainerLayer is being wrapped. For example, if the
+ * LayerMetricsWrapper is pretending to be C0, the GetNextSibling() function
+ * will return null even though the underlying layer C does actually have
+ * a next sibling. The LayerMetricsWrapper pretending to be Cn will return
+ * D as the next sibling.
+ *
+ * Implementation notes:
+ *
+ * The AtTopLayer() and AtBottomLayer() functions in this class refer to
+ * Cn and C0 in the second layer tree above; that is, they are predicates
+ * to test if the LayerMetricsWrapper is simulating the topmost or bottommost
+ * layer, as those will have special behaviour.
+ *
+ * It is possible to wrap a nullptr in a LayerMetricsWrapper, in which case
+ * the IsValid() function will return false. This is required to allow
+ * LayerMetricsWrapper to be a MOZ_STACK_CLASS (desirable because it is used
+ * in loops and recursion).
+ *
+ * This class purposely does not expose the wrapped layer directly to avoid
+ * user code from accidentally calling functions directly on it. Instead
+ * any necessary functions should be wrapped in this class. It does expose
+ * the wrapped layer as a void* for printf purposes.
+ *
+ * The implementation may look like it special-cases mIndex == 0 and/or
+ * GetScrollMetadataCount() == 0. This is an artifact of the fact that both
+ * mIndex and GetScrollMetadataCount() are uint32_t and GetScrollMetadataCount()
+ * can return 0 but mIndex cannot store -1. This seems better than the
+ * alternative of making mIndex a int32_t that can store -1, but then having
+ * to cast to uint32_t all over the place.
+ */
+class MOZ_STACK_CLASS LayerMetricsWrapper final {
+ public:
+ enum StartAt {
+ TOP,
+ BOTTOM,
+ };
+
+ LayerMetricsWrapper() : mLayer(nullptr), mIndex(0) {}
+
+ explicit LayerMetricsWrapper(Layer* aRoot, StartAt aStart = StartAt::TOP)
+ : mLayer(aRoot), mIndex(0) {
+ if (!mLayer) {
+ return;
+ }
+
+ switch (aStart) {
+ case StartAt::TOP:
+ mIndex = mLayer->GetScrollMetadataCount();
+ if (mIndex > 0) {
+ mIndex--;
+ }
+ break;
+ case StartAt::BOTTOM:
+ mIndex = 0;
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unknown startAt value");
+ break;
+ }
+ }
+
+ explicit LayerMetricsWrapper(Layer* aLayer, uint32_t aMetricsIndex)
+ : mLayer(aLayer), mIndex(aMetricsIndex) {
+ MOZ_ASSERT(mLayer);
+ MOZ_ASSERT(mIndex == 0 || mIndex < mLayer->GetScrollMetadataCount());
+ }
+
+ bool IsValid() const { return mLayer != nullptr; }
+
+ explicit operator bool() const { return IsValid(); }
+
+ LayerMetricsWrapper GetParent() const {
+ MOZ_ASSERT(IsValid());
+
+ if (!AtTopLayer()) {
+ return LayerMetricsWrapper(mLayer, mIndex + 1);
+ }
+ if (mLayer->GetParent()) {
+ return LayerMetricsWrapper(mLayer->GetParent(), StartAt::BOTTOM);
+ }
+ return LayerMetricsWrapper(nullptr);
+ }
+
+ LayerMetricsWrapper GetFirstChild() const {
+ MOZ_ASSERT(IsValid());
+
+ if (!AtBottomLayer()) {
+ return LayerMetricsWrapper(mLayer, mIndex - 1);
+ }
+ return LayerMetricsWrapper(mLayer->GetFirstChild());
+ }
+
+ LayerMetricsWrapper GetLastChild() const {
+ MOZ_ASSERT(IsValid());
+
+ if (!AtBottomLayer()) {
+ return LayerMetricsWrapper(mLayer, mIndex - 1);
+ }
+ return LayerMetricsWrapper(mLayer->GetLastChild());
+ }
+
+ LayerMetricsWrapper GetPrevSibling() const {
+ MOZ_ASSERT(IsValid());
+
+ if (AtTopLayer()) {
+ return LayerMetricsWrapper(mLayer->GetPrevSibling());
+ }
+ return LayerMetricsWrapper(nullptr);
+ }
+
+ LayerMetricsWrapper GetNextSibling() const {
+ MOZ_ASSERT(IsValid());
+
+ if (AtTopLayer()) {
+ return LayerMetricsWrapper(mLayer->GetNextSibling());
+ }
+ return LayerMetricsWrapper(nullptr);
+ }
+
+ const ScrollMetadata& Metadata() const {
+ MOZ_ASSERT(IsValid());
+
+ if (mIndex >= mLayer->GetScrollMetadataCount()) {
+ return *ScrollMetadata::sNullMetadata;
+ }
+ return mLayer->GetScrollMetadata(mIndex);
+ }
+
+ const FrameMetrics& Metrics() const { return Metadata().GetMetrics(); }
+
+ AsyncPanZoomController* GetApzc() const {
+ MOZ_ASSERT(IsValid());
+
+ if (mIndex >= mLayer->GetScrollMetadataCount()) {
+ return nullptr;
+ }
+ return mLayer->GetAsyncPanZoomController(mIndex);
+ }
+
+ void SetApzc(AsyncPanZoomController* aApzc) const {
+ MOZ_ASSERT(IsValid());
+
+ if (mLayer->GetScrollMetadataCount() == 0) {
+ MOZ_ASSERT(mIndex == 0);
+ MOZ_ASSERT(aApzc == nullptr);
+ return;
+ }
+ MOZ_ASSERT(mIndex < mLayer->GetScrollMetadataCount());
+ mLayer->SetAsyncPanZoomController(mIndex, aApzc);
+ }
+
+ const char* Name() const {
+ MOZ_ASSERT(IsValid());
+
+ if (AtBottomLayer()) {
+ return mLayer->Name();
+ }
+ return "DummyContainerLayer";
+ }
+
+ LayerManager* Manager() const {
+ MOZ_ASSERT(IsValid());
+
+ return mLayer->Manager();
+ }
+
+ gfx::Matrix4x4 GetTransform() const {
+ MOZ_ASSERT(IsValid());
+
+ if (AtBottomLayer()) {
+ return mLayer->GetTransform();
+ }
+ return gfx::Matrix4x4();
+ }
+
+ CSSTransformMatrix GetTransformTyped() const {
+ return ViewAs<CSSTransformMatrix>(GetTransform());
+ }
+
+ bool TransformIsPerspective() const {
+ MOZ_ASSERT(IsValid());
+
+ // mLayer->GetTransformIsPerspective() tells us whether
+ // mLayer->GetTransform() is a perspective transform. Since
+ // mLayer->GetTransform() is only used at the bottom layer, we only
+ // need to check GetTransformIsPerspective() at the bottom layer too.
+ if (AtBottomLayer()) {
+ return mLayer->GetTransformIsPerspective();
+ }
+ return false;
+ }
+
+ bool Combines3DTransformWithAncestors() const {
+ MOZ_ASSERT(IsValid());
+
+ return mLayer->Combines3DTransformWithAncestors();
+ }
+
+ EventRegions GetEventRegions() const {
+ MOZ_ASSERT(IsValid());
+
+ if (AtBottomLayer()) {
+ return mLayer->GetEventRegions();
+ }
+ return EventRegions();
+ }
+
+ LayerIntRegion GetVisibleRegion() const {
+ MOZ_ASSERT(IsValid());
+
+ if (AtBottomLayer()) {
+ return mLayer->GetVisibleRegion();
+ }
+
+ return ViewAs<LayerPixel>(
+ TransformBy(mLayer->GetTransformTyped(), mLayer->GetVisibleRegion()),
+ PixelCastJustification::MovingDownToChildren);
+ }
+
+ LayerIntSize GetRemoteDocumentSize() const {
+ MOZ_ASSERT(IsValid());
+
+ return AsRefLayer() ? AsRefLayer()->GetRemoteDocumentSize()
+ : LayerIntSize();
+ }
+
+ bool HasTransformAnimation() const {
+ MOZ_ASSERT(IsValid());
+
+ if (AtBottomLayer()) {
+ return mLayer->HasTransformAnimation();
+ }
+ return false;
+ }
+
+ RefLayer* AsRefLayer() const {
+ MOZ_ASSERT(IsValid());
+
+ if (AtBottomLayer()) {
+ return mLayer->AsRefLayer();
+ }
+ return nullptr;
+ }
+
+ Maybe<LayersId> GetReferentId() const {
+ MOZ_ASSERT(IsValid());
+
+ if (AtBottomLayer()) {
+ return mLayer->AsRefLayer() ? Some(mLayer->AsRefLayer()->GetReferentId())
+ : Nothing();
+ }
+ return Nothing();
+ }
+
+ Maybe<ParentLayerIntRect> GetClipRect() const {
+ MOZ_ASSERT(IsValid());
+
+ Maybe<ParentLayerIntRect> result;
+
+ // The layer can have a clip rect and a scrolled clip, which are considered
+ // to apply only to the bottommost LayerMetricsWrapper.
+ // TODO: These actually apply in a different coordinate space than the
+ // scroll clip of the bottommost metrics, so we shouldn't be intersecting
+ // them with the scroll clip; bug 1269537 tracks fixing this.
+ if (AtBottomLayer()) {
+ result = mLayer->GetClipRect();
+ result = IntersectMaybeRects(result, mLayer->GetScrolledClipRect());
+ }
+
+ // The scroll metadata can have a clip rect as well.
+ result = IntersectMaybeRects(result, Metadata().GetClipRect());
+
+ return result;
+ }
+
+ float GetPresShellResolution() const {
+ MOZ_ASSERT(IsValid());
+
+ if (AtTopLayer() && mLayer->AsContainerLayer()) {
+ return mLayer->AsContainerLayer()->GetPresShellResolution();
+ }
+
+ return 1.0f;
+ }
+
+ EventRegionsOverride GetEventRegionsOverride() const {
+ MOZ_ASSERT(IsValid());
+
+ if (AsRefLayer()) {
+ return AsRefLayer()->GetEventRegionsOverride();
+ }
+ return EventRegionsOverride::NoOverride;
+ }
+
+ const ScrollbarData& GetScrollbarData() const {
+ MOZ_ASSERT(IsValid());
+
+ return mLayer->GetScrollbarData();
+ }
+
+ Maybe<uint64_t> GetScrollbarAnimationId() const {
+ MOZ_ASSERT(IsValid());
+ // This function is only really needed for template-compatibility with
+ // WebRenderScrollDataWrapper. Although it will be called, the return
+ // value is not used.
+ return Nothing();
+ }
+
+ Maybe<uint64_t> GetFixedPositionAnimationId() const {
+ MOZ_ASSERT(IsValid());
+ // This function is only really needed for template-compatibility with
+ // WebRenderScrollDataWrapper. Although it will be called, the return
+ // value is not used.
+ return Nothing();
+ }
+
+ ScrollableLayerGuid::ViewID GetFixedPositionScrollContainerId() const {
+ MOZ_ASSERT(IsValid());
+
+ if (AtBottomLayer()) {
+ return mLayer->GetFixedPositionScrollContainerId();
+ }
+ return ScrollableLayerGuid::NULL_SCROLL_ID;
+ }
+
+ SideBits GetFixedPositionSides() const {
+ MOZ_ASSERT(IsValid());
+
+ if (AtBottomLayer()) {
+ return mLayer->GetFixedPositionSides();
+ }
+ return SideBits::eNone;
+ }
+
+ ScrollableLayerGuid::ViewID GetStickyScrollContainerId() const {
+ MOZ_ASSERT(IsValid());
+
+ if (AtBottomLayer() && mLayer->GetIsStickyPosition()) {
+ return mLayer->GetStickyScrollContainerId();
+ }
+ return ScrollableLayerGuid::NULL_SCROLL_ID;
+ }
+
+ const LayerRectAbsolute& GetStickyScrollRangeOuter() const {
+ MOZ_ASSERT(IsValid());
+
+ if (AtBottomLayer() && mLayer->GetIsStickyPosition()) {
+ return mLayer->GetStickyScrollRangeOuter();
+ }
+
+ static const LayerRectAbsolute empty;
+ return empty;
+ }
+
+ const LayerRectAbsolute& GetStickyScrollRangeInner() const {
+ MOZ_ASSERT(IsValid());
+
+ if (AtBottomLayer() && mLayer->GetIsStickyPosition()) {
+ return mLayer->GetStickyScrollRangeInner();
+ }
+
+ static const LayerRectAbsolute empty;
+ return empty;
+ }
+
+ Maybe<uint64_t> GetStickyPositionAnimationId() const {
+ MOZ_ASSERT(IsValid());
+ // This function is only really needed for template-compatibility with
+ // WebRenderScrollDataWrapper. Although it will be called, the return
+ // value is not used.
+ return Nothing();
+ }
+
+ Maybe<uint64_t> GetZoomAnimationId() const {
+ MOZ_ASSERT(IsValid());
+ // This function is only really needed for template-compatibility with
+ // WebRenderScrollDataWrapper. Although it will be called, the return
+ // value is not used.
+ return Nothing();
+ }
+
+ bool IsBackfaceHidden() const {
+ MOZ_ASSERT(IsValid());
+
+ return mLayer->IsBackfaceHidden();
+ }
+
+ Maybe<ScrollableLayerGuid::ViewID> IsAsyncZoomContainer() const {
+ MOZ_ASSERT(IsValid());
+
+ return mLayer->IsAsyncZoomContainer();
+ }
+
+ // Expose an opaque pointer to the layer. Mostly used for printf
+ // purposes. This is not intended to be a general-purpose accessor
+ // for the underlying layer.
+ const void* GetLayer() const {
+ MOZ_ASSERT(IsValid());
+
+ return (void*)mLayer;
+ }
+
+ bool operator==(const LayerMetricsWrapper& aOther) const {
+ return mLayer == aOther.mLayer && mIndex == aOther.mIndex;
+ }
+
+ bool operator!=(const LayerMetricsWrapper& aOther) const {
+ return !(*this == aOther);
+ }
+
+ private:
+ bool AtBottomLayer() const { return mIndex == 0; }
+
+ bool AtTopLayer() const {
+ return mLayer->GetScrollMetadataCount() == 0 ||
+ mIndex == mLayer->GetScrollMetadataCount() - 1;
+ }
+
+ private:
+ Layer* mLayer;
+ uint32_t mIndex;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif /* GFX_LAYERMETRICSWRAPPER_H */