Source code

Revision control

Other Tools

/* -*- 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_WEBRENDERSCROLLDATAWRAPPER_H
#define GFX_WEBRENDERSCROLLDATAWRAPPER_H
#include "FrameMetrics.h"
#include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/WebRenderBridgeParent.h"
#include "mozilla/layers/WebRenderScrollData.h"
namespace mozilla {
namespace layers {
/*
* This class is a wrapper to walk through a WebRenderScrollData object, with
* an exposed API that is template-compatible to LayerMetricsWrapper. This
* allows APZ to walk through both layer trees and WebRender scroll metadata
* structures without a lot of code duplication. (Note that not all functions
* from LayerMetricsWrapper are implemented here, only the ones we've needed in
* APZ code so far.)
*
* A WebRenderScrollData object is basically a flattened layer tree, with a
* number of WebRenderLayerScrollData objects that have a 1:1 correspondence
* to layers in a layer tree. Therefore the mLayer pointer in this class can
* be considered equivalent to the mLayer pointer in the LayerMetricsWrapper.
* There are some extra fields (mData, mLayerIndex, mContainingSubtreeLastIndex)
* to move around between these "layers" given the flattened representation.
* The mMetadataIndex field in this class corresponds to the mIndex field in
* LayerMetricsWrapper, as both classes also need to manage walking through
* "virtual" container layers implied by the list of ScrollMetadata objects.
*
* One important note here is that this class holds a pointer to the "owning"
* WebRenderScrollData. The caller must ensure that this class does not outlive
* the owning WebRenderScrollData, or this may result in use-after-free errors.
* This class being declared a MOZ_STACK_CLASS should help with that.
*
* Refer to LayerMetricsWrapper.h for actual documentation on the exposed API.
*/
class MOZ_STACK_CLASS WebRenderScrollDataWrapper final {
public:
// Basic constructor for external callers. Starts the walker at the root of
// the tree.
explicit WebRenderScrollDataWrapper(
const APZUpdater& aUpdater, const WebRenderScrollData* aData = nullptr)
: mUpdater(&aUpdater),
mData(aData),
mLayerIndex(0),
mContainingSubtreeLastIndex(0),
mLayer(nullptr),
mMetadataIndex(0) {
if (!mData) {
return;
}
mLayer = mData->GetLayerData(mLayerIndex);
if (!mLayer) {
return;
}
// sanity check on the data
MOZ_ASSERT(mData->GetLayerCount() ==
(size_t)(1 + mLayer->GetDescendantCount()));
mContainingSubtreeLastIndex = mData->GetLayerCount();
// See documentation in LayerMetricsWrapper.h about this. mMetadataIndex
// in this class is equivalent to mIndex in that class.
mMetadataIndex = mLayer->GetScrollMetadataCount();
if (mMetadataIndex > 0) {
mMetadataIndex--;
}
}
private:
// Internal constructor for walking from one WebRenderLayerScrollData to
// another. In this case we need to recompute the mMetadataIndex to be the
// "topmost" scroll metadata on the new layer.
WebRenderScrollDataWrapper(const APZUpdater* aUpdater,
const WebRenderScrollData* aData,
size_t aLayerIndex,
size_t aContainingSubtreeLastIndex)
: mUpdater(aUpdater),
mData(aData),
mLayerIndex(aLayerIndex),
mContainingSubtreeLastIndex(aContainingSubtreeLastIndex),
mLayer(nullptr),
mMetadataIndex(0) {
MOZ_ASSERT(mData);
mLayer = mData->GetLayerData(mLayerIndex);
MOZ_ASSERT(mLayer);
// See documentation in LayerMetricsWrapper.h about this. mMetadataIndex
// in this class is equivalent to mIndex in that class.
mMetadataIndex = mLayer->GetScrollMetadataCount();
if (mMetadataIndex > 0) {
mMetadataIndex--;
}
}
// Internal constructor for walking from one metadata to another metadata on
// the same WebRenderLayerScrollData.
WebRenderScrollDataWrapper(const APZUpdater* aUpdater,
const WebRenderScrollData* aData,
size_t aLayerIndex,
size_t aContainingSubtreeLastIndex,
const WebRenderLayerScrollData* aLayer,
uint32_t aMetadataIndex)
: mUpdater(aUpdater),
mData(aData),
mLayerIndex(aLayerIndex),
mContainingSubtreeLastIndex(aContainingSubtreeLastIndex),
mLayer(aLayer),
mMetadataIndex(aMetadataIndex) {
MOZ_ASSERT(mData);
MOZ_ASSERT(mLayer);
MOZ_ASSERT(mLayer == mData->GetLayerData(mLayerIndex));
MOZ_ASSERT(mMetadataIndex == 0 ||
mMetadataIndex < mLayer->GetScrollMetadataCount());
}
public:
bool IsValid() const { return mLayer != nullptr; }
explicit operator bool() const { return IsValid(); }
WebRenderScrollDataWrapper GetLastChild() const {
MOZ_ASSERT(IsValid());
if (!AtBottomLayer()) {
// If we're still walking around in the virtual container layers created
// by the ScrollMetadata array, we just need to update the metadata index
// and that's it.
return WebRenderScrollDataWrapper(mUpdater, mData, mLayerIndex,
mContainingSubtreeLastIndex, mLayer,
mMetadataIndex - 1);
}
// Otherwise, we need to walk to a different WebRenderLayerScrollData in
// mData.
// Since mData contains the layer in depth-first, last-to-first order,
// the index after mLayerIndex must be mLayerIndex's last child, if it
// has any children (indicated by GetDescendantCount() > 0). Furthermore
// we compute the first index outside the subtree rooted at this node
// (in |subtreeLastIndex|) and pass that in to the child wrapper to use as
// its mContainingSubtreeLastIndex.
if (mLayer->GetDescendantCount() > 0) {
size_t prevSiblingIndex = mLayerIndex + 1 + mLayer->GetDescendantCount();
size_t subtreeLastIndex =
std::min(mContainingSubtreeLastIndex, prevSiblingIndex);
return WebRenderScrollDataWrapper(mUpdater, mData, mLayerIndex + 1,
subtreeLastIndex);
}
// We've run out of descendants. But! If the original layer was a RefLayer,
// then it connects to another layer tree and we need to traverse that too.
// So return a WebRenderScrollDataWrapper for the root of the child layer
// tree.
if (mLayer->GetReferentId()) {
return WebRenderScrollDataWrapper(
*mUpdater, mUpdater->GetScrollData(*mLayer->GetReferentId()));
}
return WebRenderScrollDataWrapper(*mUpdater);
}
WebRenderScrollDataWrapper GetPrevSibling() const {
MOZ_ASSERT(IsValid());
if (!AtTopLayer()) {
// The virtual container layers don't have siblings
return WebRenderScrollDataWrapper(*mUpdater);
}
// Skip past the descendants to get to the previous sibling. However, we
// might be at the last sibling already.
size_t prevSiblingIndex = mLayerIndex + 1 + mLayer->GetDescendantCount();
if (prevSiblingIndex < mContainingSubtreeLastIndex) {
return WebRenderScrollDataWrapper(mUpdater, mData, prevSiblingIndex,
mContainingSubtreeLastIndex);
}
return WebRenderScrollDataWrapper(*mUpdater);
}
const ScrollMetadata& Metadata() const {
MOZ_ASSERT(IsValid());
if (mMetadataIndex >= mLayer->GetScrollMetadataCount()) {
return *ScrollMetadata::sNullMetadata;
}
return mLayer->GetScrollMetadata(*mData, mMetadataIndex);
}
const FrameMetrics& Metrics() const { return Metadata().GetMetrics(); }
AsyncPanZoomController* GetApzc() const { return nullptr; }
void SetApzc(AsyncPanZoomController* aApzc) const {}
const char* Name() const { return "WebRenderScrollDataWrapper"; }
gfx::Matrix4x4 GetTransform() const {
MOZ_ASSERT(IsValid());
// See WebRenderLayerScrollData::Initialize for more context. The ancestor
// transform is associated with the "topmost" layer, and the transform is
// associated with the "bottommost" layer. If there is only one
// scrollmetadata on the layer, then it is both "topmost" and "bottommost"
// and we combine the two transforms.
gfx::Matrix4x4 transform;
if (AtTopLayer()) {
float resolution = mLayer->GetResolution();
transform = mLayer->GetAncestorTransform() *
gfx::Matrix4x4::Scaling(resolution, resolution, 1.f);
}
if (AtBottomLayer()) {
transform = mLayer->GetTransform() * transform;
}
return transform;
}
CSSTransformMatrix GetTransformTyped() const {
return ViewAs<CSSTransformMatrix>(GetTransform());
}
bool TransformIsPerspective() const {
MOZ_ASSERT(IsValid());
if (AtBottomLayer()) {
return mLayer->GetTransformIsPerspective();
}
return false;
}
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());
if (mLayer->GetReferentId().isNothing()) {
return LayerIntSize();
}
if (AtBottomLayer()) {
return mLayer->GetRemoteDocumentSize();
}
return ViewAs<LayerPixel>(mLayer->GetRemoteDocumentSize(),
PixelCastJustification::MovingDownToChildren);
}
Maybe<LayersId> GetReferentId() const {
MOZ_ASSERT(IsValid());
if (AtBottomLayer()) {
return mLayer->GetReferentId();
}
return Nothing();
}
Maybe<ParentLayerIntRect> GetClipRect() const {
// TODO
return Nothing();
}
EventRegionsOverride GetEventRegionsOverride() const {
MOZ_ASSERT(IsValid());
// Only ref layers can have an event regions override.
if (GetReferentId()) {
return mLayer->GetEventRegionsOverride();
}
return EventRegionsOverride::NoOverride;
}
const ScrollbarData& GetScrollbarData() const {
MOZ_ASSERT(IsValid());
return mLayer->GetScrollbarData();
}
Maybe<uint64_t> GetScrollbarAnimationId() const {
MOZ_ASSERT(IsValid());
return mLayer->GetScrollbarAnimationId();
}
Maybe<uint64_t> GetFixedPositionAnimationId() const {
MOZ_ASSERT(IsValid());
if (AtBottomLayer()) {
return mLayer->GetFixedPositionAnimationId();
}
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()) {
return mLayer->GetStickyPositionScrollContainerId();
}
return ScrollableLayerGuid::NULL_SCROLL_ID;
}
const LayerRectAbsolute& GetStickyScrollRangeOuter() const {
MOZ_ASSERT(IsValid());
if (AtBottomLayer()) {
return mLayer->GetStickyScrollRangeOuter();
}
static const LayerRectAbsolute empty;
return empty;
}
const LayerRectAbsolute& GetStickyScrollRangeInner() const {
MOZ_ASSERT(IsValid());
if (AtBottomLayer()) {
return mLayer->GetStickyScrollRangeInner();
}
static const LayerRectAbsolute empty;
return empty;
}
Maybe<uint64_t> GetStickyPositionAnimationId() const {
MOZ_ASSERT(IsValid());
if (AtBottomLayer()) {
return mLayer->GetStickyPositionAnimationId();
}
return Nothing();
}
Maybe<uint64_t> GetZoomAnimationId() const {
MOZ_ASSERT(IsValid());
return mLayer->GetZoomAnimationId();
}
bool IsBackfaceHidden() const {
// This is only used by APZCTM hit testing, and WR does its own
// hit testing, so no need to implement this.
return false;
}
Maybe<ScrollableLayerGuid::ViewID> GetAsyncZoomContainerId() const {
MOZ_ASSERT(IsValid());
return mLayer->GetAsyncZoomContainerId();
}
const void* GetLayer() const {
MOZ_ASSERT(IsValid());
return mLayer;
}
private:
bool AtBottomLayer() const { return mMetadataIndex == 0; }
bool AtTopLayer() const {
return mLayer->GetScrollMetadataCount() == 0 ||
mMetadataIndex == mLayer->GetScrollMetadataCount() - 1;
}
private:
const APZUpdater* mUpdater;
const WebRenderScrollData* mData;
// The index (in mData->mLayerScrollData) of the WebRenderLayerScrollData this
// wrapper is pointing to.
size_t mLayerIndex;
// The upper bound on the set of valid indices inside the subtree rooted at
// the parent of this "layer". That is, any layer index |i| in the range
// mLayerIndex <= i < mContainingSubtreeLastIndex is guaranteed to point to
// a layer that is a descendant of "parent", where "parent" is the parent
// layer of the layer at mLayerIndex. This is needed in order to implement
// GetPrevSibling() correctly.
size_t mContainingSubtreeLastIndex;
// The WebRenderLayerScrollData this wrapper is pointing to.
const WebRenderLayerScrollData* mLayer;
// The index of the scroll metadata within mLayer that this wrapper is
// pointing to.
uint32_t mMetadataIndex;
};
} // namespace layers
} // namespace mozilla
#endif /* GFX_WEBRENDERSCROLLDATAWRAPPER_H */