diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /gfx/layers/Layers.h | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/layers/Layers.h')
-rw-r--r-- | gfx/layers/Layers.h | 2063 |
1 files changed, 2063 insertions, 0 deletions
diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h new file mode 100644 index 0000000000..f24af7a5ec --- /dev/null +++ b/gfx/layers/Layers.h @@ -0,0 +1,2063 @@ +/* -*- 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_LAYERS_H +#define GFX_LAYERS_H + +#include <cstdint> // for uint32_t, uint64_t, int32_t, uint8_t +#include <cstring> // for memcpy, size_t +#include <iosfwd> // for stringstream +#include <new> // for operator new +#include <unordered_set> // for unordered_set +#include <utility> // for forward, move +#include "FrameMetrics.h" // for ScrollMetadata, FrameMetrics::ViewID, FrameMetrics +#include "Units.h" // for LayerIntRegion, ParentLayerIntRect, LayerIntSize, Lay... +#include "gfxPoint.h" // for gfxPoint +#include "gfxRect.h" // for gfxRect +#include "mozilla/Maybe.h" // for Maybe, Nothing (ptr only) +#include "mozilla/Poison.h" // for CorruptionCanary +#include "mozilla/RefPtr.h" // for RefPtr, operator!= +#include "mozilla/TimeStamp.h" // for TimeStamp +#include "mozilla/UniquePtr.h" // for UniquePtr, MakeUnique +#include "mozilla/gfx/BasePoint.h" // for BasePoint<>::(anonymous union)::(anonymous), BasePoin... +#include "mozilla/gfx/BaseSize.h" // for BaseSize +#include "mozilla/gfx/Matrix.h" // for Matrix4x4, Matrix, Matrix4x4Typed +#include "mozilla/gfx/Point.h" // for Point, PointTyped +#include "mozilla/gfx/Polygon.h" // for Polygon +#include "mozilla/gfx/Rect.h" // for IntRectTyped, IntRect +#include "mozilla/gfx/TiledRegion.h" // for TiledIntRegion +#include "mozilla/gfx/Types.h" // for CompositionOp, DeviceColor, SamplingFilter, SideBits +#include "mozilla/gfx/UserData.h" // for UserData, UserDataKey (ptr only) +#include "mozilla/layers/AnimationInfo.h" // for AnimationInfo +#include "mozilla/layers/LayerAttributes.h" // for SimpleLayerAttributes, ScrollbarData (ptr only) +#include "mozilla/layers/LayerManager.h" // for LayerManager, LayerManager::PaintedLayerCreationHint +#include "mozilla/layers/ScrollableLayerGuid.h" // for ScrollableLayerGuid, ScrollableLayerGuid::ViewID +#include "nsISupports.h" // for NS_INLINE_DECL_REFCOUNTING +#include "nsPoint.h" // for nsIntPoint +#include "nsRect.h" // for nsIntRect +#include "nsRegion.h" // for nsIntRegion +#include "nsStringFlags.h" // for operator& +#include "nsStringFwd.h" // for nsCString, nsACString +#include "nsTArray.h" // for nsTArray, nsTArray_Impl, nsTArray_Impl<>::elem_type + +// XXX These includes could be avoided by moving function implementations to the +// cpp file +#include "gfx2DGlue.h" // for ThebesPoint +#include "mozilla/Assertions.h" // for AssertionConditionType, MOZ_ASSERT, MOZ_A... +#include "mozilla/DebugOnly.h" // for DebugOnly +#include "mozilla/layers/CanvasRenderer.h" // for CanvasRenderer +#include "mozilla/layers/LayersTypes.h" // for MOZ_LAYERS_LOG_IF_SHADOWABLE, LayersId, EventRegionsO... +#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING + +namespace mozilla { + +namespace gfx { +class DataSourceSurface; +class DrawTarget; +class Path; +} // namespace gfx + +namespace layers { + +class Animation; +class AsyncPanZoomController; +class HostLayerManager; +class PaintedLayer; +class ContainerLayer; +class ImageLayer; +class ColorLayer; +class CompositorAnimations; +class CanvasLayer; +class RefLayer; +class HostLayer; +class ShadowableLayer; +class SpecificLayerAttributes; +class Compositor; +class TransformData; +struct LayerPolygon; +struct PropertyAnimationGroup; + +namespace layerscope { +class LayersPacket; +} // namespace layerscope + +#define MOZ_LAYER_DECL_NAME(n, e) \ + const char* Name() const override { return n; } \ + LayerType GetType() const override { return e; } \ + static LayerType Type() { return e; } + +/* + * Motivation: For truly smooth animation and video playback, we need to + * be able to compose frames and render them on a dedicated thread (i.e. + * off the main thread where DOM manipulation, script execution and layout + * induce difficult-to-bound latency). This requires Gecko to construct + * some kind of persistent scene structure (graph or tree) that can be + * safely transmitted across threads. We have other scenarios (e.g. mobile + * browsing) where retaining some rendered data between paints is desired + * for performance, so again we need a retained scene structure. + * + * Our retained scene structure is a layer tree. Each layer represents + * content which can be composited onto a destination surface; the root + * layer is usually composited into a window, and non-root layers are + * composited into their parent layers. Layers have attributes (e.g. + * opacity and clipping) that influence their compositing. + * + * We want to support a variety of layer implementations, including + * a simple "immediate mode" implementation that doesn't retain any + * rendered data between paints (i.e. uses cairo in just the way that + * Gecko used it before layers were introduced). But we also don't want + * to have bifurcated "layers"/"non-layers" rendering paths in Gecko. + * Therefore the layers API is carefully designed to permit maximally + * efficient implementation in an "immediate mode" style. See the + * BasicLayerManager for such an implementation. + */ + +/** + * A Layer represents anything that can be rendered onto a destination + * surface. + */ +class Layer { + NS_INLINE_DECL_REFCOUNTING(Layer) + + using AnimationArray = nsTArray<layers::Animation>; + + public: + // Keep these in alphabetical order + enum LayerType { + TYPE_CANVAS, + TYPE_COLOR, + TYPE_CONTAINER, + TYPE_DISPLAYITEM, + TYPE_IMAGE, + TYPE_READBACK, + TYPE_REF, + TYPE_SHADOW, + TYPE_PAINTED + }; + + /** + * Returns the LayerManager this Layer belongs to. Note that the layer + * manager might be in a destroyed state, at which point it's only + * valid to set/get user data from it. + */ + LayerManager* Manager() { return mManager; } + + /** + * This should only be called when changing layer managers from HostLayers. + */ + void SetManager(LayerManager* aManager, HostLayer* aSelf); + + enum { + /** + * If this is set, the caller is promising that by the end of this + * transaction the entire visible region (as specified by + * SetVisibleRegion) will be filled with opaque content. + */ + CONTENT_OPAQUE = 0x01, + /** + * If this is set, the caller is notifying that the contents of this layer + * require per-component alpha for optimal fidelity. However, there is no + * guarantee that component alpha will be supported for this layer at + * paint time. + * This should never be set at the same time as CONTENT_OPAQUE. + */ + CONTENT_COMPONENT_ALPHA = 0x02, + + /** + * If this is set then one of the descendant layers of this one has + * CONTENT_COMPONENT_ALPHA set. + */ + CONTENT_COMPONENT_ALPHA_DESCENDANT = 0x04, + + /** + * If this is set then this layer is part of a preserve-3d group, and should + * be sorted with sibling layers that are also part of the same group. + */ + CONTENT_EXTEND_3D_CONTEXT = 0x08, + /** + * This indicates that the transform may be changed on during an empty + * transaction where there is no possibility of redrawing the content, so + * the implementation should be ready for that. + */ + CONTENT_MAY_CHANGE_TRANSFORM = 0x10, + + /** + * Disable subpixel AA for this layer. This is used if the display isn't + * suited for subpixel AA like hidpi or rotated content. + */ + CONTENT_DISABLE_SUBPIXEL_AA = 0x20, + + /** + * If this is set then the layer contains content that may look + * objectionable if not handled as an active layer (such as text with an + * animated transform). This is for internal layout/FrameLayerBuilder usage + * only until flattening code is obsoleted. See bug 633097 + */ + CONTENT_DISABLE_FLATTENING = 0x40, + + /** + * This layer is hidden if the backface of the layer is visible + * to user. + */ + CONTENT_BACKFACE_HIDDEN = 0x80, + + /** + * This layer should be snapped to the pixel grid. + */ + CONTENT_SNAP_TO_GRID = 0x100 + }; + /** + * CONSTRUCTION PHASE ONLY + * This lets layout make some promises about what will be drawn into the + * visible region of the PaintedLayer. This enables internal quality + * and performance optimizations. + */ + void SetContentFlags(uint32_t aFlags) { + NS_ASSERTION((aFlags & (CONTENT_OPAQUE | CONTENT_COMPONENT_ALPHA)) != + (CONTENT_OPAQUE | CONTENT_COMPONENT_ALPHA), + "Can't be opaque and require component alpha"); + if (mSimpleAttrs.SetContentFlags(aFlags)) { + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, + ("Layer::Mutated(%p) ContentFlags", this)); + MutatedSimple(); + } + } + + /** + * CONSTRUCTION PHASE ONLY + * Tell this layer which region will be visible. The visible region + * is a region which contains all the contents of the layer that can + * actually affect the rendering of the window. It can exclude areas + * that are covered by opaque contents of other layers, and it can + * exclude areas where this layer simply contains no content at all. + * (This can be an overapproximation to the "true" visible region.) + * + * There is no general guarantee that drawing outside the bounds of the + * visible region will be ignored. So if a layer draws outside the bounds + * of its visible region, it needs to ensure that what it draws is valid. + */ + virtual void SetVisibleRegion(const LayerIntRegion& aRegion) { + // IsEmpty is required otherwise we get invalidation glitches. + // See bug 1288464 for investigating why. + if (!mVisibleRegion.IsEqual(aRegion) || aRegion.IsEmpty()) { + MOZ_LAYERS_LOG_IF_SHADOWABLE( + this, ("Layer::Mutated(%p) VisibleRegion was %s is %s", this, + mVisibleRegion.ToString().get(), aRegion.ToString().get())); + mVisibleRegion = aRegion; + Mutated(); + } + } + + /** + * CONSTRUCTION PHASE ONLY + * Set the (sub)document metrics used to render the Layer subtree + * rooted at this. Note that a layer may have multiple FrameMetrics + * objects; calling this function will remove all of them and replace + * them with the provided FrameMetrics. See the documentation for + * SetFrameMetrics(const nsTArray<FrameMetrics>&) for more details. + */ + void SetScrollMetadata(const ScrollMetadata& aScrollMetadata) { + Manager()->ClearPendingScrollInfoUpdate(); + if (mScrollMetadata.Length() != 1 || + mScrollMetadata[0] != aScrollMetadata) { + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, + ("Layer::Mutated(%p) ScrollMetadata", this)); + mScrollMetadata.ReplaceElementsAt(0, mScrollMetadata.Length(), + aScrollMetadata); + ScrollMetadataChanged(); + Mutated(); + } + } + + /** + * CONSTRUCTION PHASE ONLY + * Set the (sub)document metrics used to render the Layer subtree + * rooted at this. There might be multiple metrics on this layer + * because the layer may, for example, be contained inside multiple + * nested scrolling subdocuments. In general a Layer having multiple + * ScrollMetadata objects is conceptually equivalent to having a stack + * of ContainerLayers that have been flattened into this Layer. + * See the documentation in LayerMetricsWrapper.h for a more detailed + * explanation of this conceptual equivalence. + * + * Note also that there is actually a many-to-many relationship between + * Layers and ScrollMetadata, because multiple Layers may have identical + * ScrollMetadata objects. This happens when those layers belong to the + * same scrolling subdocument and therefore end up with the same async + * transform when they are scrolled by the APZ code. + */ + void SetScrollMetadata(const nsTArray<ScrollMetadata>& aMetadataArray) { + Manager()->ClearPendingScrollInfoUpdate(); + if (mScrollMetadata != aMetadataArray) { + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, + ("Layer::Mutated(%p) ScrollMetadata", this)); + mScrollMetadata = aMetadataArray.Clone(); + ScrollMetadataChanged(); + Mutated(); + } + } + + /* + * Compositor event handling + * ========================= + * When a touch-start event (or similar) is sent to the + * AsyncPanZoomController, it needs to decide whether the event should be sent + * to the main thread. Each layer has a list of event handling regions. When + * the compositor needs to determine how to handle a touch event, it scans the + * layer tree from top to bottom in z-order (traversing children before their + * parents). Points outside the clip region for a layer cause that layer (and + * its subtree) to be ignored. If a layer has a mask layer, and that mask + * layer's alpha value is zero at the event point, then the layer and its + * subtree should be ignored. For each layer, if the point is outside its hit + * region, we ignore the layer and move onto the next. If the point is inside + * its hit region but outside the dispatch-to-content region, we can initiate + * a gesture without consulting the content thread. Otherwise we must dispatch + * the event to content. Note that if a layer or any ancestor layer has a + * ForceEmptyHitRegion override in GetEventRegionsOverride() then the + * hit-region must be treated as empty. Similarly, if there is a + * ForceDispatchToContent override then the dispatch-to-content region must be + * treated as encompassing the entire hit region, and therefore we must + * consult the content thread before initiating a gesture. (If both flags are + * set, ForceEmptyHitRegion takes priority.) + */ + /** + * CONSTRUCTION PHASE ONLY + * Set the event handling region. + */ + void SetEventRegions(const EventRegions& aRegions); + + /** + * CONSTRUCTION PHASE ONLY + * Set the opacity which will be applied to this layer as it + * is composited to the destination. + */ + void SetOpacity(float aOpacity) { + if (mSimpleAttrs.SetOpacity(aOpacity)) { + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) Opacity", this)); + MutatedSimple(); + } + } + + void SetMixBlendMode(gfx::CompositionOp aMixBlendMode) { + if (mSimpleAttrs.SetMixBlendMode(aMixBlendMode)) { + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, + ("Layer::Mutated(%p) MixBlendMode", this)); + MutatedSimple(); + } + } + + void SetForceIsolatedGroup(bool aForceIsolatedGroup) { + if (mSimpleAttrs.SetForceIsolatedGroup(aForceIsolatedGroup)) { + MOZ_LAYERS_LOG_IF_SHADOWABLE( + this, ("Layer::Mutated(%p) ForceIsolatedGroup", this)); + MutatedSimple(); + } + } + + bool GetForceIsolatedGroup() const { + return mSimpleAttrs.GetForceIsolatedGroup(); + } + + /** + * CONSTRUCTION PHASE ONLY + * Set a clip rect which will be applied to this layer as it is + * composited to the destination. The coordinates are relative to + * the parent layer (i.e. the contents of this layer + * are transformed before this clip rect is applied). + * For the root layer, the coordinates are relative to the widget, + * in device pixels. + * If aRect is null no clipping will be performed. + */ + void SetClipRect(const Maybe<ParentLayerIntRect>& aRect) { + if (mClipRect) { + if (!aRect) { + MOZ_LAYERS_LOG_IF_SHADOWABLE( + this, ("Layer::Mutated(%p) ClipRect was %d,%d,%d,%d is <none>", + this, mClipRect->X(), mClipRect->Y(), mClipRect->Width(), + mClipRect->Height())); + mClipRect.reset(); + Mutated(); + } else { + if (!aRect->IsEqualEdges(*mClipRect)) { + MOZ_LAYERS_LOG_IF_SHADOWABLE( + this, + ("Layer::Mutated(%p) ClipRect was %d,%d,%d,%d is %d,%d,%d,%d", + this, mClipRect->X(), mClipRect->Y(), mClipRect->Width(), + mClipRect->Height(), aRect->X(), aRect->Y(), aRect->Width(), + aRect->Height())); + mClipRect = aRect; + Mutated(); + } + } + } else { + if (aRect) { + MOZ_LAYERS_LOG_IF_SHADOWABLE( + this, + ("Layer::Mutated(%p) ClipRect was <none> is %d,%d,%d,%d", this, + aRect->X(), aRect->Y(), aRect->Width(), aRect->Height())); + mClipRect = aRect; + Mutated(); + } + } + } + + /** + * CONSTRUCTION PHASE ONLY + * Set an optional scrolled clip on the layer. + * The scrolled clip, if present, consists of a clip rect and an optional + * mask. This scrolled clip is always scrolled by all scroll frames associated + * with this layer. (By contrast, the scroll clips stored in ScrollMetadata + * are only scrolled by scroll frames above that ScrollMetadata, and the + * layer's mClipRect is always fixed to the layer contents (which may or may + * not be scrolled by some of the scroll frames associated with the layer, + * depending on whether the layer is fixed).) + */ + void SetScrolledClip(const Maybe<LayerClip>& aScrolledClip) { + if (mSimpleAttrs.SetScrolledClip(aScrolledClip)) { + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, + ("Layer::Mutated(%p) ScrolledClip", this)); + MutatedSimple(); + } + } + + /** + * CONSTRUCTION PHASE ONLY + * Set a layer to mask this layer. + * + * The mask layer should be applied using its effective transform (after it + * is calculated by ComputeEffectiveTransformForMaskLayer), this should use + * this layer's parent's transform and the mask layer's transform, but not + * this layer's. That is, the mask layer is specified relative to this layer's + * position in it's parent layer's coord space. + * Currently, only 2D translations are supported for the mask layer transform. + * + * Ownership of aMaskLayer passes to this. + * Typical use would be an ImageLayer with an alpha image used for masking. + * See also ContainerState::BuildMaskLayer in FrameLayerBuilder.cpp. + */ + void SetMaskLayer(Layer* aMaskLayer) { +#ifdef DEBUG + if (aMaskLayer) { + bool maskIs2D = aMaskLayer->GetTransform().CanDraw2D(); + NS_ASSERTION(maskIs2D, "Mask layer has invalid transform."); + } +#endif + + if (mMaskLayer != aMaskLayer) { + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, + ("Layer::Mutated(%p) MaskLayer", this)); + mMaskLayer = aMaskLayer; + Mutated(); + } + } + + /** + * CONSTRUCTION PHASE ONLY + * Add mask layers associated with LayerClips. + */ + void SetAncestorMaskLayers(const nsTArray<RefPtr<Layer>>& aLayers) { + if (aLayers != mAncestorMaskLayers) { + MOZ_LAYERS_LOG_IF_SHADOWABLE( + this, ("Layer::Mutated(%p) AncestorMaskLayers", this)); + mAncestorMaskLayers = aLayers.Clone(); + Mutated(); + } + } + + /** + * CONSTRUCTION PHASE ONLY + * Add a mask layer associated with a LayerClip. + */ + void AddAncestorMaskLayer(const RefPtr<Layer>& aLayer) { + mAncestorMaskLayers.AppendElement(aLayer); + Mutated(); + } + + /** + * CONSTRUCTION PHASE ONLY + * Tell this layer what its transform should be. The transformation + * is applied when compositing the layer into its parent container. + */ + void SetBaseTransform(const gfx::Matrix4x4& aMatrix) { + NS_ASSERTION(!aMatrix.IsSingular(), + "Shouldn't be trying to draw with a singular matrix!"); + mPendingTransform = nullptr; + if (!mSimpleAttrs.SetTransform(aMatrix)) { + return; + } + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, + ("Layer::Mutated(%p) BaseTransform", this)); + MutatedSimple(); + } + + /** + * Can be called at any time. + * + * Like SetBaseTransform(), but can be called before the next + * transform (i.e. outside an open transaction). Semantically, this + * method enqueues a new transform value to be set immediately after + * the next transaction is opened. + */ + void SetBaseTransformForNextTransaction(const gfx::Matrix4x4& aMatrix) { + mPendingTransform = mozilla::MakeUnique<gfx::Matrix4x4>(aMatrix); + } + + void SetPostScale(float aXScale, float aYScale) { + if (!mSimpleAttrs.SetPostScale(aXScale, aYScale)) { + return; + } + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PostScale", this)); + MutatedSimple(); + } + + /** + * CONSTRUCTION PHASE ONLY + * A layer is "fixed position" when it draws content from a content + * (not chrome) document, the topmost content document has a root scrollframe + * with a displayport, but the layer does not move when that displayport + * scrolls. + */ + void SetIsFixedPosition(bool aFixedPosition) { + if (mSimpleAttrs.SetIsFixedPosition(aFixedPosition)) { + MOZ_LAYERS_LOG_IF_SHADOWABLE( + this, ("Layer::Mutated(%p) IsFixedPosition", this)); + MutatedSimple(); + } + } + + void SetIsAsyncZoomContainer(const Maybe<FrameMetrics::ViewID>& aViewId) { + if (mSimpleAttrs.SetIsAsyncZoomContainer(aViewId)) { + MOZ_LAYERS_LOG_IF_SHADOWABLE( + this, ("Layer::Mutated(%p) IsAsyncZoomContainer", this)); + MutatedSimple(); + } + } + + /** + * CONSTRUCTION PHASE ONLY + * This flag is true when the transform on the layer is a perspective + * transform. The compositor treats perspective transforms specially + * for async scrolling purposes. + */ + void SetTransformIsPerspective(bool aTransformIsPerspective) { + if (mSimpleAttrs.SetTransformIsPerspective(aTransformIsPerspective)) { + MOZ_LAYERS_LOG_IF_SHADOWABLE( + this, ("Layer::Mutated(%p) TransformIsPerspective", this)); + MutatedSimple(); + } + } + // This is only called when the layer tree is updated. Do not call this from + // layout code. To add an animation to this layer, use AddAnimation. + void SetCompositorAnimations( + const LayersId& aLayersId, + const CompositorAnimations& aCompositorAnimations); + // Go through all animations in this layer and its children and, for + // any animations with a null start time, update their start time such + // that at |aReadyTime| the animation's current time corresponds to its + // 'initial current time' value. + void StartPendingAnimations(const TimeStamp& aReadyTime); + + void ClearCompositorAnimations(); + + /** + * CONSTRUCTION PHASE ONLY + * If a layer represents a fixed position element, this data is stored on the + * layer for use by the compositor. + * + * - |aScrollId| identifies the scroll frame that this element is fixed + * with respect to. + * + * - |aAnchor| is the point on the layer that is considered the "anchor" + * point, that is, the point which remains in the same position when + * compositing the layer tree with a transformation (such as when + * asynchronously scrolling and zooming). + * + * - |aSides| is the set of sides to which the element is fixed relative to. + * This is used if the viewport size is changed in the compositor and + * fixed position items need to shift accordingly. This value is made up + * combining appropriate values from mozilla::SideBits. + */ + void SetFixedPositionData(ScrollableLayerGuid::ViewID aScrollId, + const LayerPoint& aAnchor, SideBits aSides) { + if (mSimpleAttrs.SetFixedPositionData(aScrollId, aAnchor, aSides)) { + MOZ_LAYERS_LOG_IF_SHADOWABLE( + this, ("Layer::Mutated(%p) FixedPositionData", this)); + MutatedSimple(); + } + } + + /** + * CONSTRUCTION PHASE ONLY + * If a layer is "sticky position", |aScrollId| holds the scroll identifier + * of the scrollable content that contains it. The difference between the two + * rectangles |aOuter| and |aInner| is treated as two intervals in each + * dimension, with the current scroll position at the origin. For each + * dimension, while that component of the scroll position lies within either + * interval, the layer should not move relative to its scrolling container. + */ + void SetStickyPositionData(ScrollableLayerGuid::ViewID aScrollId, + LayerRectAbsolute aOuter, + LayerRectAbsolute aInner) { + if (mSimpleAttrs.SetStickyPositionData(aScrollId, aOuter, aInner)) { + MOZ_LAYERS_LOG_IF_SHADOWABLE( + this, ("Layer::Mutated(%p) StickyPositionData", this)); + MutatedSimple(); + } + } + + /** + * CONSTRUCTION PHASE ONLY + * If a layer is a scroll thumb container layer or a scrollbar container + * layer, set the scroll identifier of the scroll frame scrolled by + * the scrollbar, and other data related to the scrollbar. + */ + void SetScrollbarData(const ScrollbarData& aThumbData) { + if (mSimpleAttrs.SetScrollbarData(aThumbData)) { + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, + ("Layer::Mutated(%p) ScrollbarData", this)); + MutatedSimple(); + } + } + + // Used when forwarding transactions. Do not use at any other time. + void SetSimpleAttributes(const SimpleLayerAttributes& aAttrs) { + mSimpleAttrs = aAttrs; + } + const SimpleLayerAttributes& GetSimpleAttributes() const { + return mSimpleAttrs; + } + + // These getters can be used anytime. + float GetOpacity() { return mSimpleAttrs.GetOpacity(); } + gfx::CompositionOp GetMixBlendMode() const { + return mSimpleAttrs.GetMixBlendMode(); + } + const Maybe<ParentLayerIntRect>& GetClipRect() const { return mClipRect; } + const Maybe<LayerClip>& GetScrolledClip() const { + return mSimpleAttrs.GetScrolledClip(); + } + Maybe<ParentLayerIntRect> GetScrolledClipRect() const; + uint32_t GetContentFlags() { return mSimpleAttrs.GetContentFlags(); } + const LayerIntRegion& GetVisibleRegion() const { return mVisibleRegion; } + const ScrollMetadata& GetScrollMetadata(uint32_t aIndex) const; + const FrameMetrics& GetFrameMetrics(uint32_t aIndex) const; + uint32_t GetScrollMetadataCount() const { return mScrollMetadata.Length(); } + const nsTArray<ScrollMetadata>& GetAllScrollMetadata() { + return mScrollMetadata; + } + bool HasScrollableFrameMetrics() const; + bool IsScrollableWithoutContent() const; + const EventRegions& GetEventRegions() const { return mEventRegions; } + ContainerLayer* GetParent() const { return mParent; } + Layer* GetNextSibling() { + if (mNextSibling) { + mNextSibling->CheckCanary(); + } + return mNextSibling; + } + const Layer* GetNextSibling() const { + if (mNextSibling) { + mNextSibling->CheckCanary(); + } + return mNextSibling; + } + Layer* GetPrevSibling() { return mPrevSibling; } + const Layer* GetPrevSibling() const { return mPrevSibling; } + virtual Layer* GetFirstChild() const { return nullptr; } + virtual Layer* GetLastChild() const { return nullptr; } + gfx::Matrix4x4 GetTransform() const; + // Same as GetTransform(), but returns the transform as a strongly-typed + // matrix. Eventually this will replace GetTransform(). + const CSSTransformMatrix GetTransformTyped() const; + const gfx::Matrix4x4& GetBaseTransform() const { + return mSimpleAttrs.GetTransform(); + } + // Note: these are virtual because ContainerLayerComposite overrides them. + virtual float GetPostXScale() const { return mSimpleAttrs.GetPostXScale(); } + virtual float GetPostYScale() const { return mSimpleAttrs.GetPostYScale(); } + bool GetIsFixedPosition() { return mSimpleAttrs.IsFixedPosition(); } + Maybe<FrameMetrics::ViewID> IsAsyncZoomContainer() { + return mSimpleAttrs.IsAsyncZoomContainer(); + } + bool GetTransformIsPerspective() const { + return mSimpleAttrs.GetTransformIsPerspective(); + } + bool GetIsStickyPosition() { return mSimpleAttrs.IsStickyPosition(); } + ScrollableLayerGuid::ViewID GetFixedPositionScrollContainerId() { + return mSimpleAttrs.GetFixedPositionScrollContainerId(); + } + LayerPoint GetFixedPositionAnchor() { + return mSimpleAttrs.GetFixedPositionAnchor(); + } + SideBits GetFixedPositionSides() { + return mSimpleAttrs.GetFixedPositionSides(); + } + ScrollableLayerGuid::ViewID GetStickyScrollContainerId() { + return mSimpleAttrs.GetStickyScrollContainerId(); + } + const LayerRectAbsolute& GetStickyScrollRangeOuter() { + return mSimpleAttrs.GetStickyScrollRangeOuter(); + } + const LayerRectAbsolute& GetStickyScrollRangeInner() { + return mSimpleAttrs.GetStickyScrollRangeInner(); + } + const ScrollbarData& GetScrollbarData() const { + return mSimpleAttrs.GetScrollbarData(); + } + bool IsScrollbarContainer() const; + Layer* GetMaskLayer() const { return mMaskLayer; } + bool HasPendingTransform() const { return !!mPendingTransform; } + + void CheckCanary() const { mCanary.Check(); } + + // Ancestor mask layers are associated with FrameMetrics, but for simplicity + // in maintaining the layer tree structure we attach them to the layer. + size_t GetAncestorMaskLayerCount() const { + return mAncestorMaskLayers.Length(); + } + Layer* GetAncestorMaskLayerAt(size_t aIndex) const { + return mAncestorMaskLayers.ElementAt(aIndex); + } + const nsTArray<RefPtr<Layer>>& GetAllAncestorMaskLayers() const { + return mAncestorMaskLayers; + } + + bool HasMaskLayers() const { + return GetMaskLayer() || mAncestorMaskLayers.Length() > 0; + } + + /* + * Get the combined clip rect of the Layer clip and all clips on FrameMetrics. + * This is intended for use in Layout. The compositor needs to apply async + * transforms to find the combined clip. + */ + Maybe<ParentLayerIntRect> GetCombinedClipRect() const; + + /** + * Retrieve the root level visible region for |this| taking into account + * clipping applied to parent layers of |this| as well as subtracting + * visible regions of higher siblings of this layer and each ancestor. + * + * Note translation values for offsets of visible regions and accumulated + * aLayerOffset are integer rounded using IntPoint::Round. + * + * @param aResult - the resulting visible region of this layer. + * @param aLayerOffset - this layer's total offset from the root layer. + * @return - false if during layer tree traversal a parent or sibling + * transform is found to be non-translational. This method returns early + * in this case, results will not be valid. Returns true on successful + * traversal. + */ + bool GetVisibleRegionRelativeToRootLayer(nsIntRegion& aResult, + nsIntPoint* aLayerOffset); + + // Note that all lengths in animation data are either in CSS pixels or app + // units and must be converted to device pixels by the compositor. + // Besides, this should only be called on the compositor thread. + AnimationArray& GetAnimations() { return mAnimationInfo.GetAnimations(); } + uint64_t GetCompositorAnimationsId() { + return mAnimationInfo.GetCompositorAnimationsId(); + } + nsTArray<PropertyAnimationGroup>& GetPropertyAnimationGroups() { + return mAnimationInfo.GetPropertyAnimationGroups(); + } + const Maybe<TransformData>& GetTransformData() const { + return mAnimationInfo.GetTransformData(); + } + const LayersId& GetAnimationLayersId() const { + return mAnimationInfo.GetLayersId(); + } + + Maybe<uint64_t> GetAnimationGeneration() const { + return mAnimationInfo.GetAnimationGeneration(); + } + + gfx::Path* CachedMotionPath() { return mAnimationInfo.CachedMotionPath(); } + + bool HasTransformAnimation() const; + + /** + * Returns the local transform for this layer: either mTransform or, + * for shadow layers, GetShadowBaseTransform(), in either case with the + * pre- and post-scales applied. + */ + gfx::Matrix4x4 GetLocalTransform(); + + /** + * Same as GetLocalTransform(), but returns a strongly-typed matrix. + * Eventually, this will replace GetLocalTransform(). + */ + const LayerToParentLayerMatrix4x4 GetLocalTransformTyped(); + + /** + * Returns the local opacity for this layer: either mOpacity or, + * for shadow layers, GetShadowOpacity() + */ + float GetLocalOpacity(); + + /** + * DRAWING PHASE ONLY + * + * Apply pending changes to layers before drawing them, if those + * pending changes haven't been overridden by later changes. + * + * Returns a list of scroll ids which had pending updates. + */ + std::unordered_set<ScrollableLayerGuid::ViewID> + ApplyPendingUpdatesToSubtree(); + + /** + * DRAWING PHASE ONLY + * + * Write layer-subtype-specific attributes into aAttrs. Used to + * synchronize layer attributes to their shadows'. + */ + virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) {} + + // Returns true if it's OK to save the contents of aLayer in an + // opaque surface (a surface without an alpha channel). + // If we can use a surface without an alpha channel, we should, because + // it will often make painting of antialiased text faster and higher + // quality. + bool CanUseOpaqueSurface(); + + SurfaceMode GetSurfaceMode() { + if (CanUseOpaqueSurface()) return SurfaceMode::SURFACE_OPAQUE; + if (GetContentFlags() & CONTENT_COMPONENT_ALPHA) + return SurfaceMode::SURFACE_COMPONENT_ALPHA; + return SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA; + } + + // Returns true if this layer can be treated as opaque for visibility + // computation. A layer may be non-opaque for visibility even if it + // is not transparent, for example, if it has a mix-blend-mode. + bool IsOpaqueForVisibility(); + + /** + * This setter can be used anytime. The user data for all keys is + * initially null. Ownership pases to the layer manager. + */ + void SetUserData( + void* aKey, LayerUserData* aData, + void (*aDestroy)(void*) = LayerManager::LayerUserDataDestroy) { + mUserData.Add(static_cast<gfx::UserDataKey*>(aKey), aData, aDestroy); + } + /** + * This can be used anytime. Ownership passes to the caller! + */ + UniquePtr<LayerUserData> RemoveUserData(void* aKey); + /** + * This getter can be used anytime. + */ + bool HasUserData(void* aKey) { + return mUserData.Has(static_cast<gfx::UserDataKey*>(aKey)); + } + /** + * This getter can be used anytime. Ownership is retained by the layer + * manager. + */ + LayerUserData* GetUserData(void* aKey) const { + return static_cast<LayerUserData*>( + mUserData.Get(static_cast<gfx::UserDataKey*>(aKey))); + } + + /** + * |Disconnect()| is used by layers hooked up over IPC. It may be + * called at any time, and may not be called at all. Using an + * IPC-enabled layer after Destroy() (drawing etc.) results in a + * safe no-op; no crashy or uaf etc. + * + * XXX: this interface is essentially LayerManager::Destroy, but at + * Layer granularity. It might be beneficial to unify them. + */ + virtual void Disconnect() {} + + /** + * Dynamic downcast to a PaintedLayer. Returns null if this is not + * a PaintedLayer. + */ + virtual PaintedLayer* AsPaintedLayer() { return nullptr; } + + /** + * Dynamic cast to a ContainerLayer. Returns null if this is not + * a ContainerLayer. + */ + virtual ContainerLayer* AsContainerLayer() { return nullptr; } + virtual const ContainerLayer* AsContainerLayer() const { return nullptr; } + + /** + * Dynamic cast to a RefLayer. Returns null if this is not a + * RefLayer. + */ + virtual RefLayer* AsRefLayer() { return nullptr; } + + /** + * Dynamic cast to a Color. Returns null if this is not a + * ColorLayer. + */ + virtual ColorLayer* AsColorLayer() { return nullptr; } + + /** + * Dynamic cast to a Canvas. Returns null if this is not a + * ColorLayer. + */ + virtual CanvasLayer* AsCanvasLayer() { return nullptr; } + + /** + * Dynamic cast to an Image. Returns null if this is not a + * ColorLayer. + */ + virtual ImageLayer* AsImageLayer() { return nullptr; } + + /** + * Dynamic cast to a LayerComposite. Return null if this is not a + * LayerComposite. Can be used anytime. + */ + virtual HostLayer* AsHostLayer() { return nullptr; } + + /** + * Dynamic cast to a ShadowableLayer. Return null if this is not a + * ShadowableLayer. Can be used anytime. + */ + virtual ShadowableLayer* AsShadowableLayer() { return nullptr; } + + // These getters can be used anytime. They return the effective + // values that should be used when drawing this layer to screen, + // accounting for this layer possibly being a shadow. + const Maybe<ParentLayerIntRect>& GetLocalClipRect(); + const LayerIntRegion& GetLocalVisibleRegion(); + + bool Extend3DContext() { + return GetContentFlags() & CONTENT_EXTEND_3D_CONTEXT; + } + bool Combines3DTransformWithAncestors() { + return GetParent() && + reinterpret_cast<Layer*>(GetParent())->Extend3DContext(); + } + bool Is3DContextLeaf() { + return !Extend3DContext() && Combines3DTransformWithAncestors(); + } + /** + * It is true if the user can see the back of the layer and the + * backface is hidden. The compositor should skip the layer if the + * result is true. + */ + bool IsBackfaceHidden(); + bool IsVisible() { + // For containers extending 3D context, visible region + // is meaningless, since they are just intermediate result of + // content. + return !GetLocalVisibleRegion().IsEmpty() || Extend3DContext(); + } + + /** + * Return true if current layer content is opaque. + * It does not guarantee that layer content is always opaque. + */ + virtual bool IsOpaque() { return GetContentFlags() & CONTENT_OPAQUE; } + + /** + * Returns the product of the opacities of this layer and all ancestors up + * to and excluding the nearest ancestor that has UseIntermediateSurface() + * set. + */ + float GetEffectiveOpacity(); + + /** + * Returns the blendmode of this layer. + */ + gfx::CompositionOp GetEffectiveMixBlendMode(); + + /** + * This returns the effective transform computed by + * ComputeEffectiveTransforms. Typically this is a transform that transforms + * this layer all the way to some intermediate surface or destination + * surface. For non-BasicLayers this will be a transform to the nearest + * ancestor with UseIntermediateSurface() (or to the root, if there is no + * such ancestor), but for BasicLayers it's different. + */ + const gfx::Matrix4x4& GetEffectiveTransform() const { + return mEffectiveTransform; + } + + /** + * This returns the effective transform for Layer's buffer computed by + * ComputeEffectiveTransforms. Typically this is a transform that transforms + * this layer's buffer all the way to some intermediate surface or destination + * surface. For non-BasicLayers this will be a transform to the nearest + * ancestor with UseIntermediateSurface() (or to the root, if there is no + * such ancestor), but for BasicLayers it's different. + * + * By default, its value is same to GetEffectiveTransform(). + * When ImageLayer is rendered with ScaleMode::STRETCH, + * it becomes different from GetEffectiveTransform(). + */ + virtual const gfx::Matrix4x4& GetEffectiveTransformForBuffer() const { + return mEffectiveTransform; + } + + /** + * If the current layers participates in a preserve-3d + * context (returns true for Combines3DTransformWithAncestors), + * returns the combined transform up to the preserve-3d (nearest + * ancestor that doesn't Extend3DContext()). Otherwise returns + * the local transform. + */ + gfx::Matrix4x4 ComputeTransformToPreserve3DRoot(); + + /** + * @param aTransformToSurface the composition of the transforms + * from the parent layer (if any) to the destination pixel grid. + * + * Computes mEffectiveTransform for this layer and all its descendants. + * mEffectiveTransform transforms this layer up to the destination + * pixel grid (whatever aTransformToSurface is relative to). + * + * We promise that when this is called on a layer, all ancestor layers + * have already had ComputeEffectiveTransforms called. + */ + virtual void ComputeEffectiveTransforms( + const gfx::Matrix4x4& aTransformToSurface) = 0; + + /** + * Computes the effective transform for mask layers, if this layer has any. + */ + void ComputeEffectiveTransformForMaskLayers( + const gfx::Matrix4x4& aTransformToSurface); + static void ComputeEffectiveTransformForMaskLayer( + Layer* aMaskLayer, const gfx::Matrix4x4& aTransformToSurface); + + /** + * Calculate the scissor rect required when rendering this layer. + * Returns a rectangle relative to the intermediate surface belonging to the + * nearest ancestor that has an intermediate surface, or relative to the root + * viewport if no ancestor has an intermediate surface, corresponding to the + * clip rect for this layer intersected with aCurrentScissorRect. + */ + RenderTargetIntRect CalculateScissorRect( + const RenderTargetIntRect& aCurrentScissorRect); + + virtual const char* Name() const = 0; + virtual LayerType GetType() const = 0; + + /** + * Only the implementation should call this. This is per-implementation + * private data. Normally, all layers with a given layer manager + * use the same type of ImplData. + */ + void* ImplData() { return mImplData; } + + /** + * Only the implementation should use these methods. + */ + void SetParent(ContainerLayer* aParent) { mParent = aParent; } + void SetNextSibling(Layer* aSibling) { mNextSibling = aSibling; } + void SetPrevSibling(Layer* aSibling) { mPrevSibling = aSibling; } + + /** + * Dump information about this layer manager and its managed tree to + * aStream. + */ + void Dump(std::stringstream& aStream, const char* aPrefix = "", + bool aDumpHtml = false, bool aSorted = false, + const Maybe<gfx::Polygon>& aGeometry = Nothing()); + /** + * Dump information about just this layer manager itself to aStream. + */ + void DumpSelf(std::stringstream& aStream, const char* aPrefix = "", + const Maybe<gfx::Polygon>& aGeometry = Nothing()); + + /** + * Dump information about this layer and its child & sibling layers to + * layerscope packet. + */ + void Dump(layerscope::LayersPacket* aPacket, const void* aParent); + + /** + * Log information about this layer manager and its managed tree to + * the NSPR log (if enabled for "Layers"). + */ + void Log(const char* aPrefix = ""); + /** + * Log information about just this layer manager itself to the NSPR + * log (if enabled for "Layers"). + */ + void LogSelf(const char* aPrefix = ""); + + // Print interesting information about this into aStream. Internally + // used to implement Dump*() and Log*(). If subclasses have + // additional interesting properties, they should override this with + // an implementation that first calls the base implementation then + // appends additional info to aTo. + virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix); + + // Just like PrintInfo, but this function dump information into layerscope + // packet, instead of a StringStream. It is also internally used to implement + // Dump(); + virtual void DumpPacket(layerscope::LayersPacket* aPacket, + const void* aParent); + + /** + * Store display list log. + */ + void SetDisplayListLog(const char* log); + + /** + * Return display list log. + */ + void GetDisplayListLog(nsCString& log); + + static bool IsLogEnabled() { return LayerManager::IsLogEnabled(); } + + /** + * Returns the current area of the layer (in layer-space coordinates) + * marked as needed to be recomposited. + */ + const virtual gfx::TiledIntRegion& GetInvalidRegion() { + return mInvalidRegion; + } + void AddInvalidRegion(const nsIntRegion& aRegion) { + mInvalidRegion.Add(aRegion); + } + + /** + * Mark the entirety of the layer's visible region as being invalid. + */ + void SetInvalidRectToVisibleRegion() { + mInvalidRegion.SetEmpty(); + mInvalidRegion.Add(GetVisibleRegion().ToUnknownRegion()); + } + + /** + * Adds to the current invalid rect. + */ + void AddInvalidRect(const gfx::IntRect& aRect) { mInvalidRegion.Add(aRect); } + + /** + * Clear the invalid rect, marking the layer as being identical to what is + * currently composited. + */ + virtual void ClearInvalidRegion() { mInvalidRegion.SetEmpty(); } + + // These functions allow attaching an AsyncPanZoomController to this layer, + // and can be used anytime. + // A layer has an APZC at index aIndex only-if + // GetFrameMetrics(aIndex).IsScrollable(); attempting to get an APZC for a + // non-scrollable metrics will return null. The reverse is also generally true + // (that if GetFrameMetrics(aIndex).IsScrollable() is true, then the layer + // will have an APZC). However, it only holds on the the compositor-side layer + // tree, and only after the APZ code has had a chance to rebuild its internal + // hit-testing tree using the layer tree. Also, it may not hold in certain + // "exceptional" scenarios such as if the layer tree doesn't have a + // GeckoContentController registered for it, or if there is a malicious + // content process trying to trip up the compositor over IPC. The aIndex for + // these functions must be less than GetScrollMetadataCount(). + void SetAsyncPanZoomController(uint32_t aIndex, + AsyncPanZoomController* controller); + AsyncPanZoomController* GetAsyncPanZoomController(uint32_t aIndex) const; + // The ScrollMetadataChanged function is used internally to ensure the APZC + // array length matches the frame metrics array length. + + virtual void ClearCachedResources() {} + + virtual bool SupportsAsyncUpdate() { return false; } + + private: + void ScrollMetadataChanged(); + + public: + void ApplyPendingUpdatesForThisTransaction(); + +#ifdef DEBUG + void SetDebugColorIndex(uint32_t aIndex) { mDebugColorIndex = aIndex; } + uint32_t GetDebugColorIndex() { return mDebugColorIndex; } +#endif + + void Mutated() { mManager->Mutated(this); } + void MutatedSimple() { mManager->MutatedSimple(this); } + + virtual int32_t GetMaxLayerSize() { return Manager()->GetMaxTextureSize(); } + + /** + * Returns true if this layer's effective transform is not just + * a translation by integers, or if this layer or some ancestor layer + * is marked as having a transform that may change without a full layer + * transaction. + * + * Note: This function ignores ancestor layers across layer tree boundaries + * so that it returns a consistent value when compositing and when painting. + */ + bool MayResample(); + + RenderTargetRect TransformRectToRenderTarget(const LayerIntRect& aRect); + + /** + * Add debugging information to the layer dump. + */ + void AddExtraDumpInfo(const nsACString& aStr) { +#ifdef MOZ_DUMP_PAINTING + mExtraDumpInfo.AppendElement(aStr); +#endif + } + + /** + * Clear debugging information. Useful for recycling. + */ + void ClearExtraDumpInfo() { +#ifdef MOZ_DUMP_PAINTING + mExtraDumpInfo.Clear(); +#endif + } + + AnimationInfo& GetAnimationInfo() { return mAnimationInfo; } + + protected: + Layer(LayerManager* aManager, void* aImplData); + + // Protected destructor, to discourage deletion outside of Release(): + virtual ~Layer(); + + /** + * We can snap layer transforms for two reasons: + * 1) To avoid unnecessary resampling when a transform is a translation + * by a non-integer number of pixels. + * Snapping the translation to an integer number of pixels avoids + * blurring the layer and can be faster to composite. + * 2) When a layer is used to render a rectangular object, we need to + * emulate the rendering of rectangular inactive content and snap the + * edges of the rectangle to pixel boundaries. This is both to ensure + * layer rendering is consistent with inactive content rendering, and to + * avoid seams. + * This function implements type 1 snapping. If aTransform is a 2D + * translation, and this layer's layer manager has enabled snapping + * (which is the default), return aTransform with the translation snapped + * to nearest pixels. Otherwise just return aTransform. Call this when the + * layer does not correspond to a single rectangular content object. + * This function does not try to snap if aTransform has a scale, because in + * that case resampling is inevitable and there's no point in trying to + * avoid it. In fact snapping can cause problems because pixel edges in the + * layer's content can be rendered unpredictably (jiggling) as the scale + * interacts with the snapping of the translation, especially with animated + * transforms. + * @param aResidualTransform a transform to apply before the result transform + * in order to get the results to completely match aTransform. + */ + gfx::Matrix4x4 SnapTransformTranslation(const gfx::Matrix4x4& aTransform, + gfx::Matrix* aResidualTransform); + gfx::Matrix4x4 SnapTransformTranslation3D(const gfx::Matrix4x4& aTransform, + gfx::Matrix* aResidualTransform); + /** + * See comment for SnapTransformTranslation. + * This function implements type 2 snapping. If aTransform is a translation + * and/or scale, transform aSnapRect by aTransform, snap to pixel boundaries, + * and return the transform that maps aSnapRect to that rect. Otherwise + * just return aTransform. + * @param aSnapRect a rectangle whose edges should be snapped to pixel + * boundaries in the destination surface. + * @param aResidualTransform a transform to apply before the result transform + * in order to get the results to completely match aTransform. + */ + gfx::Matrix4x4 SnapTransform(const gfx::Matrix4x4& aTransform, + const gfxRect& aSnapRect, + gfx::Matrix* aResidualTransform); + + LayerManager* mManager; + ContainerLayer* mParent; + Layer* mNextSibling; + Layer* mPrevSibling; + void* mImplData; + RefPtr<Layer> mMaskLayer; + nsTArray<RefPtr<Layer>> mAncestorMaskLayers; + // Look for out-of-bound in the middle of the structure + mozilla::CorruptionCanary mCanary; + gfx::UserData mUserData; + SimpleLayerAttributes mSimpleAttrs; + LayerIntRegion mVisibleRegion; + nsTArray<ScrollMetadata> mScrollMetadata; + EventRegions mEventRegions; + // A mutation of |mTransform| that we've queued to be applied at the + // end of the next transaction (if nothing else overrides it in the + // meantime). + UniquePtr<gfx::Matrix4x4> mPendingTransform; + gfx::Matrix4x4 mEffectiveTransform; + AnimationInfo mAnimationInfo; + Maybe<ParentLayerIntRect> mClipRect; + gfx::IntRect mTileSourceRect; + gfx::TiledIntRegion mInvalidRegion; + nsTArray<RefPtr<AsyncPanZoomController>> mApzcs; + bool mUseTileSourceRect; +#ifdef DEBUG + uint32_t mDebugColorIndex; +#endif +#ifdef MOZ_DUMP_PAINTING + nsTArray<nsCString> mExtraDumpInfo; +#endif + // Store display list log. + nsCString mDisplayListLog; +}; + +/** + * A Layer which we can paint into. It is a conceptually + * infinite surface, but each PaintedLayer has an associated "valid region" + * of contents that it is currently storing, which is finite. PaintedLayer + * implementations can store content between paints. + * + * PaintedLayers are rendered into during the drawing phase of a transaction. + * + * Currently the contents of a PaintedLayer are in the device output color + * space. + */ +class PaintedLayer : public Layer { + public: + /** + * CONSTRUCTION PHASE ONLY + * Tell this layer that the content in some region has changed and + * will need to be repainted. This area is removed from the valid + * region. + */ + virtual void InvalidateRegion(const nsIntRegion& aRegion) = 0; + /** + * CONSTRUCTION PHASE ONLY + * Set whether ComputeEffectiveTransforms should compute the + * "residual translation" --- the translation that should be applied *before* + * mEffectiveTransform to get the ideal transform for this PaintedLayer. + * When this is true, ComputeEffectiveTransforms will compute the residual + * and ensure that the layer is invalidated whenever the residual changes. + * When it's false, a change in the residual will not trigger invalidation + * and GetResidualTranslation will return 0,0. + * So when the residual is to be ignored, set this to false for better + * performance. + */ + void SetAllowResidualTranslation(bool aAllow) { + mAllowResidualTranslation = aAllow; + } + + void SetValidRegion(const nsIntRegion& aRegion) { + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, + ("Layer::Mutated(%p) ValidRegion", this)); + mValidRegion = aRegion; + mValidRegionIsCurrent = true; + Mutated(); + } + + /** + * Can be used anytime + */ + const nsIntRegion& GetValidRegion() const { + EnsureValidRegionIsCurrent(); + return mValidRegion; + } + + void InvalidateWholeLayer() { + mInvalidRegion.Add(GetValidRegion().GetBounds()); + ClearValidRegion(); + } + + void ClearValidRegion() { + mValidRegion.SetEmpty(); + mValidRegionIsCurrent = true; + } + void AddToValidRegion(const nsIntRegion& aRegion) { + EnsureValidRegionIsCurrent(); + mValidRegion.OrWith(aRegion); + } + void SubtractFromValidRegion(const nsIntRegion& aRegion) { + EnsureValidRegionIsCurrent(); + mValidRegion.SubOut(aRegion); + } + void UpdateValidRegionAfterInvalidRegionChanged() { + // Changes to mInvalidRegion will be applied to mValidRegion on the next + // call to EnsureValidRegionIsCurrent(). + mValidRegionIsCurrent = false; + } + + void ClearInvalidRegion() override { + // mInvalidRegion is about to be reset. This is the last chance to apply + // any pending changes from it to mValidRegion. Do that by calling + // EnsureValidRegionIsCurrent(). + EnsureValidRegionIsCurrent(); + mInvalidRegion.SetEmpty(); + } + + PaintedLayer* AsPaintedLayer() override { return this; } + + MOZ_LAYER_DECL_NAME("PaintedLayer", TYPE_PAINTED) + + void ComputeEffectiveTransforms( + const gfx::Matrix4x4& aTransformToSurface) override { + gfx::Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface; + gfx::Matrix residual; + mEffectiveTransform = SnapTransformTranslation( + idealTransform, mAllowResidualTranslation ? &residual : nullptr); + // The residual can only be a translation because SnapTransformTranslation + // only changes the transform if it's a translation + NS_ASSERTION(residual.IsTranslation(), + "Residual transform can only be a translation"); + if (!gfx::ThebesPoint(residual.GetTranslation()) + .WithinEpsilonOf(mResidualTranslation, 1e-3f)) { + mResidualTranslation = gfx::ThebesPoint(residual.GetTranslation()); + DebugOnly<mozilla::gfx::Point> transformedOrig = + idealTransform.TransformPoint(mozilla::gfx::Point()); +#ifdef DEBUG + DebugOnly<mozilla::gfx::Point> transformed = + idealTransform.TransformPoint(mozilla::gfx::Point( + mResidualTranslation.x, mResidualTranslation.y)) - + *&transformedOrig; +#endif + NS_ASSERTION(-0.5 <= (&transformed)->x && (&transformed)->x < 0.5 && + -0.5 <= (&transformed)->y && (&transformed)->y < 0.5, + "Residual translation out of range"); + ClearValidRegion(); + } + ComputeEffectiveTransformForMaskLayers(aTransformToSurface); + } + + LayerManager::PaintedLayerCreationHint GetCreationHint() const { + return mCreationHint; + } + + bool UsedForReadback() { return mUsedForReadback; } + void SetUsedForReadback(bool aUsed) { mUsedForReadback = aUsed; } + + /** + * Returns true if aLayer is optimized for the given PaintedLayerCreationHint. + */ + virtual bool IsOptimizedFor( + LayerManager::PaintedLayerCreationHint aCreationHint) { + return true; + } + + /** + * Returns the residual translation. Apply this translation when drawing + * into the PaintedLayer so that when mEffectiveTransform is applied + * afterwards by layer compositing, the results exactly match the "ideal + * transform" (the product of the transform of this layer and its ancestors). + * Returns 0,0 unless SetAllowResidualTranslation(true) has been called. + * The residual translation components are always in the range [-0.5, 0.5). + */ + gfxPoint GetResidualTranslation() const { return mResidualTranslation; } + + protected: + PaintedLayer( + LayerManager* aManager, void* aImplData, + LayerManager::PaintedLayerCreationHint aCreationHint = LayerManager::NONE) + : Layer(aManager, aImplData), + mValidRegion(), + mValidRegionIsCurrent(true), + mCreationHint(aCreationHint), + mUsedForReadback(false), + mAllowResidualTranslation(false) {} + + void PrintInfo(std::stringstream& aStream, const char* aPrefix) override; + + void DumpPacket(layerscope::LayersPacket* aPacket, + const void* aParent) override; + + /** + * ComputeEffectiveTransforms snaps the ideal transform to get + * mEffectiveTransform. mResidualTranslation is the translation that should be + * applied *before* mEffectiveTransform to get the ideal transform. + */ + gfxPoint mResidualTranslation; + + private: + /** + * Needs to be called prior to accessing mValidRegion, unless mValidRegion is + * being completely overwritten. + */ + void EnsureValidRegionIsCurrent() const { + if (!mValidRegionIsCurrent) { + // Apply any pending mInvalidRegion changes to mValidRegion. + if (!mValidRegion.IsEmpty()) { + // Calling mInvalidRegion.GetRegion() is expensive. + // That's why we delay the adjustment of mValidRegion for as long as + // possible, so that multiple modifications to mInvalidRegion can be + // applied to mValidRegion in one go. + mValidRegion.SubOut(mInvalidRegion.GetRegion()); + } + mValidRegionIsCurrent = true; + } + } + + /** + * The layer's valid region. If mValidRegionIsCurrent is false, then + * mValidRegion has not yet been updated for recent changes to + * mInvalidRegion. Those pending changes can be applied by calling + * EnsureValidRegionIsCurrent(). + */ + mutable nsIntRegion mValidRegion; + + mutable bool mValidRegionIsCurrent; + + protected: + /** + * The creation hint that was used when constructing this layer. + */ + const LayerManager::PaintedLayerCreationHint mCreationHint; + /** + * Set when this PaintedLayer is participating in readback, i.e. some + * ReadbackLayer (may) be getting its background from this layer. + */ + bool mUsedForReadback; + /** + * True when + */ + bool mAllowResidualTranslation; +}; + +/** + * A Layer which other layers render into. It holds references to its + * children. + */ +class ContainerLayer : public Layer { + public: + virtual ~ContainerLayer(); + + /** + * CONSTRUCTION PHASE ONLY + * Insert aChild into the child list of this container. aChild must + * not be currently in any child list or the root for the layer manager. + * If aAfter is non-null, it must be a child of this container and + * we insert after that layer. If it's null we insert at the start. + */ + virtual bool InsertAfter(Layer* aChild, Layer* aAfter); + /** + * CONSTRUCTION PHASE ONLY + * Remove aChild from the child list of this container. aChild must + * be a child of this container. + */ + virtual bool RemoveChild(Layer* aChild); + /** + * CONSTRUCTION PHASE ONLY + * Reposition aChild from the child list of this container. aChild must + * be a child of this container. + * If aAfter is non-null, it must be a child of this container and we + * reposition after that layer. If it's null, we reposition at the start. + */ + virtual bool RepositionChild(Layer* aChild, Layer* aAfter); + + void SetPreScale(float aXScale, float aYScale) { + if (mPreXScale == aXScale && mPreYScale == aYScale) { + return; + } + + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PreScale", this)); + mPreXScale = aXScale; + mPreYScale = aYScale; + Mutated(); + } + + void SetInheritedScale(float aXScale, float aYScale) { + if (mInheritedXScale == aXScale && mInheritedYScale == aYScale) { + return; + } + + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, + ("Layer::Mutated(%p) InheritedScale", this)); + mInheritedXScale = aXScale; + mInheritedYScale = aYScale; + Mutated(); + } + + void SetScaleToResolution(float aResolution) { + if (mPresShellResolution == aResolution) { + return; + } + + MOZ_LAYERS_LOG_IF_SHADOWABLE( + this, ("Layer::Mutated(%p) ScaleToResolution", this)); + mPresShellResolution = aResolution; + Mutated(); + } + + void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override; + + enum class SortMode { + WITH_GEOMETRY, + WITHOUT_GEOMETRY, + }; + + nsTArray<LayerPolygon> SortChildrenBy3DZOrder(SortMode aSortMode); + + ContainerLayer* AsContainerLayer() override { return this; } + const ContainerLayer* AsContainerLayer() const override { return this; } + + // These getters can be used anytime. + Layer* GetFirstChild() const override { return mFirstChild; } + Layer* GetLastChild() const override { return mLastChild; } + float GetPreXScale() const { return mPreXScale; } + float GetPreYScale() const { return mPreYScale; } + float GetInheritedXScale() const { return mInheritedXScale; } + float GetInheritedYScale() const { return mInheritedYScale; } + float GetPresShellResolution() const { return mPresShellResolution; } + + MOZ_LAYER_DECL_NAME("ContainerLayer", TYPE_CONTAINER) + + /** + * ContainerLayer backends need to override ComputeEffectiveTransforms + * since the decision about whether to use a temporary surface for the + * container is backend-specific. ComputeEffectiveTransforms must also set + * mUseIntermediateSurface. + */ + void ComputeEffectiveTransforms( + const gfx::Matrix4x4& aTransformToSurface) override = 0; + + /** + * Call this only after ComputeEffectiveTransforms has been invoked + * on this layer. + * Returns true if this will use an intermediate surface. This is largely + * backend-dependent, but it affects the operation of GetEffectiveOpacity(). + */ + bool UseIntermediateSurface() { return mUseIntermediateSurface; } + + /** + * Returns the rectangle covered by the intermediate surface, + * in this layer's coordinate system. + * + * NOTE: Since this layer has an intermediate surface it follows + * that LayerPixel == RenderTargetPixel + */ + RenderTargetIntRect GetIntermediateSurfaceRect(); + + /** + * Returns true if this container has more than one non-empty child + */ + bool HasMultipleChildren(); + + /** + * Returns true if this container supports children with component alpha. + * Should only be called while painting a child of this layer. + */ + bool SupportsComponentAlphaChildren() { + return mSupportsComponentAlphaChildren; + } + + /** + * Returns true if aLayer or any layer in its parent chain has the opaque + * content flag set. + */ + static bool HasOpaqueAncestorLayer(Layer* aLayer); + + void SetChildrenChanged(bool aVal) { mChildrenChanged = aVal; } + + // If |aRect| is null, the entire layer should be considered invalid for + // compositing. + virtual void SetInvalidCompositeRect(const gfx::IntRect* aRect) {} + + protected: + friend class ReadbackProcessor; + + // Note that this is not virtual, and is based on the implementation of + // ContainerLayer::RemoveChild, so it should only be called where you would + // want to explicitly call the base class implementation of RemoveChild; + // e.g., while (mFirstChild) ContainerLayer::RemoveChild(mFirstChild); + void RemoveAllChildren(); + + void DidInsertChild(Layer* aLayer); + void DidRemoveChild(Layer* aLayer); + + bool AnyAncestorOrThisIs3DContextLeaf(); + + void Collect3DContextLeaves(nsTArray<Layer*>& aToSort); + + // Collects child layers that do not extend 3D context. For ContainerLayers + // that do extend 3D context, the 3D context leaves are collected. + nsTArray<Layer*> CollectChildren() { + nsTArray<Layer*> children; + + for (Layer* layer = GetFirstChild(); layer; + layer = layer->GetNextSibling()) { + ContainerLayer* container = layer->AsContainerLayer(); + + if (container && container->Extend3DContext() && + !container->UseIntermediateSurface()) { + container->Collect3DContextLeaves(children); + } else { + children.AppendElement(layer); + } + } + + return children; + } + + ContainerLayer(LayerManager* aManager, void* aImplData); + + /** + * A default implementation of ComputeEffectiveTransforms for use by OpenGL + * and D3D. + */ + void DefaultComputeEffectiveTransforms( + const gfx::Matrix4x4& aTransformToSurface); + + /** + * A default implementation to compute and set the value for + * SupportsComponentAlphaChildren(). + * + * If aNeedsSurfaceCopy is provided, then it is set to true if the caller + * needs to copy the background up into the intermediate surface created, + * false otherwise. + */ + void DefaultComputeSupportsComponentAlphaChildren( + bool* aNeedsSurfaceCopy = nullptr); + + /** + * Loops over the children calling ComputeEffectiveTransforms on them. + */ + void ComputeEffectiveTransformsForChildren( + const gfx::Matrix4x4& aTransformToSurface); + + virtual void PrintInfo(std::stringstream& aStream, + const char* aPrefix) override; + + virtual void DumpPacket(layerscope::LayersPacket* aPacket, + const void* aParent) override; + + /** + * True for if the container start a new 3D context extended by one + * or more children. + */ + bool Creates3DContextWithExtendingChildren(); + + Layer* mFirstChild; + Layer* mLastChild; + float mPreXScale; + float mPreYScale; + // The resolution scale inherited from the parent layer. This will already + // be part of mTransform. + float mInheritedXScale; + float mInheritedYScale; + // For layers corresponding to an nsDisplayAsyncZoom, the resolution of the + // associated pres shell; for other layers, 1.0. + float mPresShellResolution; + bool mUseIntermediateSurface; + bool mSupportsComponentAlphaChildren; + bool mMayHaveReadbackChild; + // This is updated by ComputeDifferences. This will be true if we need to + // invalidate the intermediate surface. + bool mChildrenChanged; +}; + +/** + * A Layer which just renders a solid color in its visible region. It actually + * can fill any area that contains the visible region, so if you need to + * restrict the area filled, set a clip region on this layer. + */ +class ColorLayer : public Layer { + public: + ColorLayer* AsColorLayer() override { return this; } + + /** + * CONSTRUCTION PHASE ONLY + * Set the color of the layer. + */ + virtual void SetColor(const gfx::DeviceColor& aColor) { + if (mColor != aColor) { + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) Color", this)); + mColor = aColor; + Mutated(); + } + } + + void SetBounds(const gfx::IntRect& aBounds) { + if (!mBounds.IsEqualEdges(aBounds)) { + mBounds = aBounds; + Mutated(); + } + } + + const gfx::IntRect& GetBounds() { return mBounds; } + + // This getter can be used anytime. + virtual const gfx::DeviceColor& GetColor() { return mColor; } + + MOZ_LAYER_DECL_NAME("ColorLayer", TYPE_COLOR) + + void ComputeEffectiveTransforms( + const gfx::Matrix4x4& aTransformToSurface) override { + gfx::Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface; + mEffectiveTransform = SnapTransformTranslation(idealTransform, nullptr); + ComputeEffectiveTransformForMaskLayers(aTransformToSurface); + } + + protected: + ColorLayer(LayerManager* aManager, void* aImplData) + : Layer(aManager, aImplData), mColor() {} + + void PrintInfo(std::stringstream& aStream, const char* aPrefix) override; + + void DumpPacket(layerscope::LayersPacket* aPacket, + const void* aParent) override; + + gfx::IntRect mBounds; + gfx::DeviceColor mColor; +}; + +/** + * A Layer for HTML Canvas elements. It's backed by either a + * gfxASurface or a GLContext (for WebGL layers), and has some control + * for intelligent updating from the source if necessary (for example, + * if hardware compositing is not available, for reading from the GL + * buffer into an image surface that we can layer composite.) + * + * After Initialize is called, the underlying canvas Surface/GLContext + * must not be modified during a layer transaction. + */ +class CanvasLayer : public Layer { + public: + void SetBounds(gfx::IntRect aBounds) { mBounds = aBounds; } + + CanvasLayer* AsCanvasLayer() override { return this; } + + /** + * Notify this CanvasLayer that the canvas surface contents have + * changed (or will change) before the next transaction. + */ + void Updated() { + mCanvasRenderer->SetDirty(); + SetInvalidRectToVisibleRegion(); + } + + /** + * Notify this CanvasLayer that the canvas surface contents have + * been painted since the last change. + */ + void Painted() { mCanvasRenderer->ResetDirty(); } + + /** + * Returns true if the canvas surface contents have changed since the + * last paint. + */ + bool IsDirty() { + // We can only tell if we are dirty if we're part of the + // widget's retained layer tree. + if (!mManager || !mManager->IsWidgetLayerManager()) { + return true; + } + return mCanvasRenderer->IsDirty(); + } + + const nsIntRect& GetBounds() const { return mBounds; } + + RefPtr<CanvasRenderer> CreateOrGetCanvasRenderer(); + + public: + /** + * CONSTRUCTION PHASE ONLY + * Set the filter used to resample this image (if necessary). + */ + void SetSamplingFilter(gfx::SamplingFilter aSamplingFilter) { + if (mSamplingFilter != aSamplingFilter) { + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) Filter", this)); + mSamplingFilter = aSamplingFilter; + Mutated(); + } + } + gfx::SamplingFilter GetSamplingFilter() const { return mSamplingFilter; } + + MOZ_LAYER_DECL_NAME("CanvasLayer", TYPE_CANVAS) + + void ComputeEffectiveTransforms( + const gfx::Matrix4x4& aTransformToSurface) override { + // Snap our local transform first, and snap the inherited transform as well. + // This makes our snapping equivalent to what would happen if our content + // was drawn into a PaintedLayer (gfxContext would snap using the local + // transform, then we'd snap again when compositing the PaintedLayer). + mEffectiveTransform = + SnapTransform(GetLocalTransform(), + gfxRect(0, 0, mBounds.Width(), mBounds.Height()), + nullptr) * + SnapTransformTranslation(aTransformToSurface, nullptr); + ComputeEffectiveTransformForMaskLayers(aTransformToSurface); + } + + protected: + CanvasLayer(LayerManager* aManager, void* aImplData); + virtual ~CanvasLayer(); + + void PrintInfo(std::stringstream& aStream, const char* aPrefix) override; + + void DumpPacket(layerscope::LayersPacket* aPacket, + const void* aParent) override; + + virtual RefPtr<CanvasRenderer> CreateCanvasRendererInternal() = 0; + + RefPtr<CanvasRenderer> mCanvasRenderer; + gfx::SamplingFilter mSamplingFilter; + + /** + * 0, 0, canvaswidth, canvasheight + */ + gfx::IntRect mBounds; +}; + +/** + * ContainerLayer that refers to a "foreign" layer tree, through an + * ID. Usage of RefLayer looks like + * + * Construction phase: + * allocate ID for layer subtree + * create RefLayer, SetReferentId(ID) + * + * Composition: + * look up subtree for GetReferentId() + * ConnectReferentLayer(subtree) + * compose + * ClearReferentLayer() + * + * Clients will usually want to Connect/Clear() on each transaction to + * avoid difficulties managing memory across multiple layer subtrees. + */ +class RefLayer : public ContainerLayer { + friend class LayerManager; + + private: + bool InsertAfter(Layer* aChild, Layer* aAfter) override { + MOZ_CRASH("GFX: RefLayer"); + return false; + } + + bool RemoveChild(Layer* aChild) override { + MOZ_CRASH("GFX: RefLayer"); + return false; + } + + bool RepositionChild(Layer* aChild, Layer* aAfter) override { + MOZ_CRASH("GFX: RefLayer"); + return false; + } + + public: + /** + * CONSTRUCTION PHASE ONLY + * Set the ID of the layer's referent. + */ + void SetReferentId(LayersId aId) { + MOZ_ASSERT(aId.IsValid()); + if (mId != aId) { + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, + ("Layer::Mutated(%p) ReferentId", this)); + mId = aId; + Mutated(); + } + } + /** + * CONSTRUCTION PHASE ONLY + * Connect this ref layer to its referent, temporarily. + * ClearReferentLayer() must be called after composition. + */ + void ConnectReferentLayer(Layer* aLayer) { + MOZ_ASSERT(!mFirstChild && !mLastChild); + MOZ_ASSERT(!aLayer->GetParent()); + if (aLayer->Manager() != Manager()) { + // This can happen when e.g. rendering while dragging tabs + // between windows - aLayer's manager may be the manager for the + // old window's tab. In that case, it will be changed before the + // next render (see SetLayerManager). It is simply easier to + // ignore the rendering here than it is to pause it. + NS_WARNING("ConnectReferentLayer failed - Incorrect LayerManager"); + return; + } + + mFirstChild = mLastChild = aLayer; + aLayer->SetParent(this); + } + + /** + * CONSTRUCTION PHASE ONLY + * Set flags that indicate how event regions in the child layer tree need + * to be overridden because of properties of the parent layer tree. + */ + void SetEventRegionsOverride(EventRegionsOverride aVal) { + if (mEventRegionsOverride == aVal) { + return; + } + + MOZ_LAYERS_LOG_IF_SHADOWABLE( + this, ("Layer::Mutated(%p) EventRegionsOverride", this)); + mEventRegionsOverride = aVal; + Mutated(); + } + + EventRegionsOverride GetEventRegionsOverride() const { + return mEventRegionsOverride; + } + + /** + * CONSTRUCTION PHASE ONLY + * Set remote subdocument iframe size. + */ + void SetRemoteDocumentSize(const LayerIntSize& aRemoteDocumentSize) { + if (mRemoteDocumentSize == aRemoteDocumentSize) { + return; + } + mRemoteDocumentSize = aRemoteDocumentSize; + Mutated(); + } + + const LayerIntSize& GetRemoteDocumentSize() const { + return mRemoteDocumentSize; + } + + /** + * DRAWING PHASE ONLY + * |aLayer| is the same as the argument to ConnectReferentLayer(). + */ + void DetachReferentLayer(Layer* aLayer) { + mFirstChild = mLastChild = nullptr; + aLayer->SetParent(nullptr); + } + + // These getters can be used anytime. + RefLayer* AsRefLayer() override { return this; } + + virtual LayersId GetReferentId() { return mId; } + + /** + * DRAWING PHASE ONLY + */ + void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override; + + MOZ_LAYER_DECL_NAME("RefLayer", TYPE_REF) + + protected: + RefLayer(LayerManager* aManager, void* aImplData) + : ContainerLayer(aManager, aImplData), + mId{0}, + mEventRegionsOverride(EventRegionsOverride::NoOverride) {} + + void PrintInfo(std::stringstream& aStream, const char* aPrefix) override; + + void DumpPacket(layerscope::LayersPacket* aPacket, + const void* aParent) override; + + // 0 is a special value that means "no ID". + LayersId mId; + EventRegionsOverride mEventRegionsOverride; + // The remote documents only need their size because their origin is always + // (0, 0). + LayerIntSize mRemoteDocumentSize; +}; + +void SetAntialiasingFlags(Layer* aLayer, gfx::DrawTarget* aTarget); + +#ifdef MOZ_DUMP_PAINTING +void WriteSnapshotToDumpFile(Layer* aLayer, gfx::DataSourceSurface* aSurf); +void WriteSnapshotToDumpFile(LayerManager* aManager, + gfx::DataSourceSurface* aSurf); +void WriteSnapshotToDumpFile(Compositor* aCompositor, gfx::DrawTarget* aTarget); +#endif + +// A utility function used by different LayerManager implementations. +gfx::IntRect ToOutsideIntRect(const gfxRect& aRect); + +void RecordCompositionPayloadsPresented( + const TimeStamp& aCompositionEndTime, + const nsTArray<CompositionPayload>& aPayloads); + +} // namespace layers +} // namespace mozilla + +#endif /* GFX_LAYERS_H */ |