summaryrefslogtreecommitdiffstats
path: root/layout/painting/nsDisplayList.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--layout/painting/nsDisplayList.h7616
1 files changed, 7616 insertions, 0 deletions
diff --git a/layout/painting/nsDisplayList.h b/layout/painting/nsDisplayList.h
new file mode 100644
index 0000000000..37161e62ce
--- /dev/null
+++ b/layout/painting/nsDisplayList.h
@@ -0,0 +1,7616 @@
+/* -*- 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/.
+ */
+
+/*
+ * structures that represent things to be painted (ordered in z-order),
+ * used during painting and hit testing
+ */
+
+#ifndef NSDISPLAYLIST_H_
+#define NSDISPLAYLIST_H_
+
+#include "mozilla/Attributes.h"
+#include "gfxContext.h"
+#include "mozilla/ArenaAllocator.h"
+#include "mozilla/Array.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/EnumSet.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/TemplateLib.h" // mozilla::tl::Max
+#include "nsCOMPtr.h"
+#include "nsContainerFrame.h"
+#include "nsPoint.h"
+#include "nsRect.h"
+#include "nsRegion.h"
+#include "nsDisplayListInvalidation.h"
+#include "DisplayItemClipChain.h"
+#include "DisplayListClipState.h"
+#include "LayerState.h"
+#include "FrameMetrics.h"
+#include "ImgDrawResult.h"
+#include "mozilla/dom/EffectsInfo.h"
+#include "mozilla/dom/RemoteBrowser.h"
+#include "mozilla/EffectCompositor.h"
+#include "mozilla/EnumeratedArray.h"
+#include "mozilla/MotionPathUtils.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/gfx/UserData.h"
+#include "mozilla/layers/LayerAttributes.h"
+#include "mozilla/layers/ScrollableLayerGuid.h"
+#include "nsCSSRenderingBorders.h"
+#include "nsPresArena.h"
+#include "nsAutoLayoutPhase.h"
+#include "nsDisplayItemTypes.h"
+#include "RetainedDisplayListHelpers.h"
+#include "Units.h"
+
+#include <stdint.h>
+#include "nsClassHashtable.h"
+#include "nsTHashtable.h"
+
+#include <stdlib.h>
+#include <algorithm>
+#include <unordered_set>
+
+// XXX Includes that could be avoided by moving function implementations to the
+// cpp file.
+#include "gfxPlatform.h"
+
+class gfxContext;
+class nsIContent;
+class nsDisplayList;
+class nsDisplayTableItem;
+class nsIScrollableFrame;
+class nsSubDocumentFrame;
+class nsDisplayCompositorHitTestInfo;
+class nsDisplayScrollInfoLayer;
+class nsDisplayTableBackgroundSet;
+class nsCaret;
+enum class nsDisplayOwnLayerFlags;
+struct WrFiltersHolder;
+
+namespace nsStyleTransformMatrix {
+class TransformReferenceBox;
+}
+
+namespace mozilla {
+class FrameLayerBuilder;
+class PresShell;
+class StickyScrollContainer;
+namespace layers {
+struct FrameMetrics;
+class RenderRootStateManager;
+class Layer;
+class ImageLayer;
+class ImageContainer;
+class StackingContextHelper;
+class WebRenderCommand;
+class WebRenderScrollData;
+class WebRenderLayerScrollData;
+} // namespace layers
+namespace wr {
+class DisplayListBuilder;
+} // namespace wr
+namespace dom {
+class Selection;
+} // namespace dom
+
+enum class DisplayListArenaObjectId {
+#define DISPLAY_LIST_ARENA_OBJECT(name_) name_,
+#include "nsDisplayListArenaTypes.h"
+#undef DISPLAY_LIST_ARENA_OBJECT
+ COUNT
+};
+
+} // namespace mozilla
+
+/*
+ * An nsIFrame can have many different visual parts. For example an image frame
+ * can have a background, border, and outline, the image itself, and a
+ * translucent selection overlay. In general these parts can be drawn at
+ * discontiguous z-levels; see CSS2.1 appendix E:
+ * http://www.w3.org/TR/CSS21/zindex.html
+ *
+ * We construct a display list for a frame tree that contains one item
+ * for each visual part. The display list is itself a tree since some items
+ * are containers for other items; however, its structure does not match
+ * the structure of its source frame tree. The display list items are sorted
+ * by z-order. A display list can be used to paint the frames, to determine
+ * which frame is the target of a mouse event, and to determine what areas
+ * need to be repainted when scrolling. The display lists built for each task
+ * may be different for efficiency; in particular some frames need special
+ * display list items only for event handling, and do not create these items
+ * when the display list will be used for painting (the common case). For
+ * example, when painting we avoid creating nsDisplayBackground items for
+ * frames that don't display a visible background, but for event handling
+ * we need those backgrounds because they are not transparent to events.
+ *
+ * We could avoid constructing an explicit display list by traversing the
+ * frame tree multiple times in clever ways. However, reifying the display list
+ * reduces code complexity and reduces the number of times each frame must be
+ * traversed to one, which seems to be good for performance. It also means
+ * we can share code for painting, event handling and scroll analysis.
+ *
+ * Display lists are short-lived; content and frame trees cannot change
+ * between a display list being created and destroyed. Display lists should
+ * not be created during reflow because the frame tree may be in an
+ * inconsistent state (e.g., a frame's stored overflow-area may not include
+ * the bounds of all its children). However, it should be fine to create
+ * a display list while a reflow is pending, before it starts.
+ *
+ * A display list covers the "extended" frame tree; the display list for
+ * a frame tree containing FRAME/IFRAME elements can include frames from
+ * the subdocuments.
+ *
+ * Display item's coordinates are relative to their nearest reference frame
+ * ancestor. Both the display root and any frame with a transform act as a
+ * reference frame for their frame subtrees.
+ */
+
+/**
+ * Represents a frame that is considered to have (or will have) "animated
+ * geometry" for itself and descendant frames.
+ *
+ * For example the scrolled frames of scrollframes which are actively being
+ * scrolled fall into this category. Frames with certain CSS properties that are
+ * being animated (e.g. 'left'/'top' etc) are also placed in this category.
+ * Frames with different active geometry roots are in different PaintedLayers,
+ * so that we can animate the geometry root by changing its transform (either on
+ * the main thread or in the compositor).
+ *
+ * nsDisplayListBuilder constructs a tree of these (for fast traversals) and
+ * assigns one for each display item.
+ *
+ * The animated geometry root for a display item is required to be a descendant
+ * (or equal to) the item's ReferenceFrame(), which means that we will fall back
+ * to returning aItem->ReferenceFrame() when we can't find another animated
+ * geometry root.
+ *
+ * The animated geometry root isn't strongly defined for a frame as transforms
+ * and background-attachment:fixed can cause it to vary between display items
+ * for a given frame.
+ */
+struct AnimatedGeometryRoot {
+ static already_AddRefed<AnimatedGeometryRoot> CreateAGRForFrame(
+ nsIFrame* aFrame, AnimatedGeometryRoot* aParent, bool aIsAsync,
+ bool aIsRetained) {
+ RefPtr<AnimatedGeometryRoot> result;
+ if (aIsRetained) {
+ result = aFrame->GetProperty(AnimatedGeometryRootCache());
+ }
+
+ if (result) {
+ result->mParentAGR = aParent;
+ result->mIsAsync = aIsAsync;
+ } else {
+ result = new AnimatedGeometryRoot(aFrame, aParent, aIsAsync, aIsRetained);
+ }
+ return result.forget();
+ }
+
+ operator nsIFrame*() { return mFrame; }
+
+ nsIFrame* operator->() const { return mFrame; }
+
+ AnimatedGeometryRoot* GetAsyncAGR() {
+ AnimatedGeometryRoot* agr = this;
+ while (!agr->mIsAsync && agr->mParentAGR) {
+ agr = agr->mParentAGR;
+ }
+ return agr;
+ }
+
+ NS_INLINE_DECL_REFCOUNTING(AnimatedGeometryRoot)
+
+ nsIFrame* mFrame;
+ RefPtr<AnimatedGeometryRoot> mParentAGR;
+ bool mIsAsync;
+ bool mIsRetained;
+
+ protected:
+ static void DetachAGR(AnimatedGeometryRoot* aAGR) {
+ aAGR->mFrame = nullptr;
+ aAGR->mParentAGR = nullptr;
+ NS_RELEASE(aAGR);
+ }
+
+ NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(AnimatedGeometryRootCache,
+ AnimatedGeometryRoot, DetachAGR)
+
+ AnimatedGeometryRoot(nsIFrame* aFrame, AnimatedGeometryRoot* aParent,
+ bool aIsAsync, bool aIsRetained)
+ : mFrame(aFrame),
+ mParentAGR(aParent),
+ mIsAsync(aIsAsync),
+ mIsRetained(aIsRetained) {
+ MOZ_ASSERT(mParentAGR || mIsAsync,
+ "The root AGR should always be treated as an async AGR.");
+ if (mIsRetained) {
+ NS_ADDREF(this);
+ aFrame->SetProperty(AnimatedGeometryRootCache(), this);
+ }
+ }
+
+ ~AnimatedGeometryRoot() {
+ if (mFrame && mIsRetained) {
+ mFrame->RemoveProperty(AnimatedGeometryRootCache());
+ }
+ }
+};
+
+namespace mozilla {
+
+/**
+ * An active scrolled root (ASR) is similar to an animated geometry root (AGR).
+ * The differences are:
+ * - ASRs are only created for async-scrollable scroll frames. This is a
+ * (hopefully) temporary restriction. In the future we will want to create
+ * ASRs for all the things that are currently creating AGRs, and then
+ * replace AGRs with ASRs and rename them from "active scrolled root" to
+ * "animated geometry root".
+ * - ASR objects are created during display list construction by the nsIFrames
+ * that induce ASRs. This is done using AutoCurrentActiveScrolledRootSetter.
+ * The current ASR is returned by
+ * nsDisplayListBuilder::CurrentActiveScrolledRoot().
+ * - There is no way to go from an nsIFrame pointer to the ASR of that frame.
+ * If you need to look up an ASR after display list construction, you need
+ * to store it while the AutoCurrentActiveScrolledRootSetter that creates it
+ * is on the stack.
+ */
+struct ActiveScrolledRoot {
+ static already_AddRefed<ActiveScrolledRoot> CreateASRForFrame(
+ const ActiveScrolledRoot* aParent, nsIScrollableFrame* aScrollableFrame,
+ bool aIsRetained);
+
+ static const ActiveScrolledRoot* PickAncestor(
+ const ActiveScrolledRoot* aOne, const ActiveScrolledRoot* aTwo) {
+ MOZ_ASSERT(IsAncestor(aOne, aTwo) || IsAncestor(aTwo, aOne));
+ return Depth(aOne) <= Depth(aTwo) ? aOne : aTwo;
+ }
+
+ static const ActiveScrolledRoot* PickDescendant(
+ const ActiveScrolledRoot* aOne, const ActiveScrolledRoot* aTwo) {
+ MOZ_ASSERT(IsAncestor(aOne, aTwo) || IsAncestor(aTwo, aOne));
+ return Depth(aOne) >= Depth(aTwo) ? aOne : aTwo;
+ }
+
+ static bool IsAncestor(const ActiveScrolledRoot* aAncestor,
+ const ActiveScrolledRoot* aDescendant);
+
+ static nsCString ToString(
+ const mozilla::ActiveScrolledRoot* aActiveScrolledRoot);
+
+ // Call this when inserting an ancestor.
+ void IncrementDepth() { mDepth++; }
+
+ /**
+ * Find the view ID (or generate a new one) for the content element
+ * corresponding to the ASR.
+ */
+ mozilla::layers::ScrollableLayerGuid::ViewID GetViewId() const {
+ if (!mViewId.isSome()) {
+ mViewId = Some(ComputeViewId());
+ }
+ return *mViewId;
+ }
+
+ RefPtr<const ActiveScrolledRoot> mParent;
+ nsIScrollableFrame* mScrollableFrame;
+
+ NS_INLINE_DECL_REFCOUNTING(ActiveScrolledRoot)
+
+ private:
+ ActiveScrolledRoot()
+ : mScrollableFrame(nullptr), mDepth(0), mRetained(false) {}
+
+ ~ActiveScrolledRoot();
+
+ static void DetachASR(ActiveScrolledRoot* aASR) {
+ aASR->mParent = nullptr;
+ aASR->mScrollableFrame = nullptr;
+ NS_RELEASE(aASR);
+ }
+ NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(ActiveScrolledRootCache,
+ ActiveScrolledRoot, DetachASR)
+
+ static uint32_t Depth(const ActiveScrolledRoot* aActiveScrolledRoot) {
+ return aActiveScrolledRoot ? aActiveScrolledRoot->mDepth : 0;
+ }
+
+ mozilla::layers::ScrollableLayerGuid::ViewID ComputeViewId() const;
+
+ // This field is lazily populated in GetViewId(). We don't want to do the
+ // work of populating if webrender is disabled, because it is often not
+ // needed.
+ mutable Maybe<mozilla::layers::ScrollableLayerGuid::ViewID> mViewId;
+
+ uint32_t mDepth;
+ bool mRetained;
+};
+} // namespace mozilla
+
+enum class nsDisplayListBuilderMode : uint8_t {
+ Painting,
+ EventDelivery,
+ PluginGeometry,
+ FrameVisibility,
+ TransformComputation,
+ GenerateGlyph,
+};
+
+class nsDisplayWrapList;
+
+/**
+ * This manages a display list and is passed as a parameter to
+ * nsIFrame::BuildDisplayList.
+ * It contains the parameters that don't change from frame to frame and manages
+ * the display list memory using an arena. It also establishes the reference
+ * coordinate system for all display list items. Some of the parameters are
+ * available from the prescontext/presshell, but we copy them into the builder
+ * for faster/more convenient access.
+ */
+class nsDisplayListBuilder {
+ typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect;
+ typedef mozilla::LayoutDeviceIntSize LayoutDeviceIntSize;
+ typedef mozilla::LayoutDeviceIntRegion LayoutDeviceIntRegion;
+ typedef mozilla::LayoutDeviceRect LayoutDeviceRect;
+
+ /**
+ * This manages status of a 3d context to collect visible rects of
+ * descendants and passing a dirty rect.
+ *
+ * Since some transforms maybe singular, passing visible rects or
+ * the dirty rect level by level from parent to children may get a
+ * wrong result, being different from the result of appling with
+ * effective transform directly.
+ *
+ * nsIFrame::BuildDisplayListForStackingContext() uses
+ * AutoPreserves3DContext to install an instance on the builder.
+ *
+ * \see AutoAccumulateTransform, AutoAccumulateRect,
+ * AutoPreserves3DContext, Accumulate, GetCurrentTransform,
+ * StartRoot.
+ */
+ class Preserves3DContext {
+ public:
+ typedef mozilla::gfx::Matrix4x4 Matrix4x4;
+
+ Preserves3DContext()
+ : mAccumulatedRectLevels(0), mAllowAsyncAnimation(true) {}
+
+ Preserves3DContext(const Preserves3DContext& aOther)
+ : mAccumulatedTransform(),
+ mAccumulatedRect(),
+ mAccumulatedRectLevels(0),
+ mVisibleRect(aOther.mVisibleRect),
+ mAllowAsyncAnimation(aOther.mAllowAsyncAnimation) {}
+
+ // Accmulate transforms of ancestors on the preserves-3d chain.
+ Matrix4x4 mAccumulatedTransform;
+ // Accmulate visible rect of descendants in the preserves-3d context.
+ nsRect mAccumulatedRect;
+ // How far this frame is from the root of the current 3d context.
+ int mAccumulatedRectLevels;
+ nsRect mVisibleRect;
+ // Allow async animation for this 3D context.
+ bool mAllowAsyncAnimation;
+ };
+
+ /**
+ * A frame can be in one of three states of AGR.
+ * AGR_NO means the frame is not an AGR for now.
+ * AGR_YES means the frame is an AGR for now.
+ */
+ enum AGRState { AGR_NO, AGR_YES };
+
+ public:
+ typedef mozilla::FrameLayerBuilder FrameLayerBuilder;
+ typedef mozilla::DisplayItemClip DisplayItemClip;
+ typedef mozilla::DisplayItemClipChain DisplayItemClipChain;
+ typedef mozilla::DisplayItemClipChainHasher DisplayItemClipChainHasher;
+ typedef mozilla::DisplayItemClipChainEqualer DisplayItemClipChainEqualer;
+ typedef mozilla::DisplayListClipState DisplayListClipState;
+ typedef mozilla::ActiveScrolledRoot ActiveScrolledRoot;
+ typedef nsIWidget::ThemeGeometry ThemeGeometry;
+ typedef mozilla::layers::Layer Layer;
+ typedef mozilla::layers::FrameMetrics FrameMetrics;
+ typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
+ typedef mozilla::layers::ScrollableLayerGuid::ViewID ViewID;
+ typedef mozilla::gfx::CompositorHitTestInfo CompositorHitTestInfo;
+ typedef mozilla::gfx::Matrix4x4 Matrix4x4;
+ typedef mozilla::Maybe<mozilla::layers::ScrollDirection> MaybeScrollDirection;
+ typedef mozilla::dom::EffectsInfo EffectsInfo;
+ typedef mozilla::layers::LayersId LayersId;
+ typedef mozilla::dom::RemoteBrowser RemoteBrowser;
+
+ /**
+ * @param aReferenceFrame the frame at the root of the subtree; its origin
+ * is the origin of the reference coordinate system for this display list
+ * @param aMode encodes what the builder is being used for.
+ * @param aBuildCaret whether or not we should include the caret in any
+ * display lists that we make.
+ */
+ nsDisplayListBuilder(nsIFrame* aReferenceFrame,
+ nsDisplayListBuilderMode aMode, bool aBuildCaret,
+ bool aRetainingDisplayList = false);
+ ~nsDisplayListBuilder();
+
+ void BeginFrame();
+ void EndFrame();
+
+ void AddTemporaryItem(nsDisplayItem* aItem) {
+ mTemporaryItems.AppendElement(aItem);
+ }
+
+ void SetWillComputePluginGeometry(bool aWillComputePluginGeometry) {
+ mWillComputePluginGeometry = aWillComputePluginGeometry;
+ }
+
+ void SetForPluginGeometry(bool aForPlugin) {
+ if (aForPlugin) {
+ NS_ASSERTION(mMode == nsDisplayListBuilderMode::Painting,
+ "Can only switch from Painting to PluginGeometry");
+ NS_ASSERTION(mWillComputePluginGeometry,
+ "Should have signalled this in advance");
+ mMode = nsDisplayListBuilderMode::PluginGeometry;
+ } else {
+ NS_ASSERTION(mMode == nsDisplayListBuilderMode::PluginGeometry,
+ "Can only switch from Painting to PluginGeometry");
+ mMode = nsDisplayListBuilderMode::Painting;
+ }
+ }
+
+ mozilla::layers::LayerManager* GetWidgetLayerManager(
+ nsView** aView = nullptr);
+
+ /**
+ * @return true if the display is being built in order to determine which
+ * frame is under the mouse position.
+ */
+ bool IsForEventDelivery() const {
+ return mMode == nsDisplayListBuilderMode::EventDelivery;
+ }
+
+ /**
+ * Be careful with this. The display list will be built in Painting mode
+ * first and then switched to PluginGeometry before a second call to
+ * ComputeVisibility.
+ * @return true if the display list is being built to compute geometry
+ * for plugins.
+ */
+ bool IsForPluginGeometry() const {
+ return mMode == nsDisplayListBuilderMode::PluginGeometry;
+ }
+
+ /**
+ * @return true if the display list is being built for painting.
+ */
+ bool IsForPainting() const {
+ return mMode == nsDisplayListBuilderMode::Painting;
+ }
+
+ /**
+ * @return true if the display list is being built for determining frame
+ * visibility.
+ */
+ bool IsForFrameVisibility() const {
+ return mMode == nsDisplayListBuilderMode::FrameVisibility;
+ }
+
+ /**
+ * @return true if the display list is being built for creating the glyph
+ * mask from text items.
+ */
+ bool IsForGenerateGlyphMask() const {
+ return mMode == nsDisplayListBuilderMode::GenerateGlyph;
+ }
+
+ bool BuildCompositorHitTestInfo() const {
+ return mBuildCompositorHitTestInfo;
+ }
+
+ bool WillComputePluginGeometry() const { return mWillComputePluginGeometry; }
+
+ /**
+ * @return true if "painting is suppressed" during page load and we
+ * should paint only the background of the document.
+ */
+ bool IsBackgroundOnly() {
+ NS_ASSERTION(mPresShellStates.Length() > 0,
+ "don't call this if we're not in a presshell");
+ return CurrentPresShellState()->mIsBackgroundOnly;
+ }
+
+ /**
+ * @return the root of given frame's (sub)tree, whose origin
+ * establishes the coordinate system for the child display items.
+ */
+ const nsIFrame* FindReferenceFrameFor(const nsIFrame* aFrame,
+ nsPoint* aOffset = nullptr) const;
+
+ const mozilla::Maybe<nsPoint>& AdditionalOffset() const {
+ return mAdditionalOffset;
+ }
+
+ /**
+ * @return the root of the display list's frame (sub)tree, whose origin
+ * establishes the coordinate system for the display list
+ */
+ nsIFrame* RootReferenceFrame() const { return mReferenceFrame; }
+
+ /**
+ * @return a point pt such that adding pt to a coordinate relative to aFrame
+ * makes it relative to ReferenceFrame(), i.e., returns
+ * aFrame->GetOffsetToCrossDoc(ReferenceFrame()). The returned point is in
+ * the appunits of aFrame.
+ */
+ const nsPoint ToReferenceFrame(const nsIFrame* aFrame) const {
+ nsPoint result;
+ FindReferenceFrameFor(aFrame, &result);
+ return result;
+ }
+ /**
+ * When building the display list, the scrollframe aFrame will be "ignored"
+ * for the purposes of clipping, and its scrollbars will be hidden. We use
+ * this to allow RenderOffscreen to render a whole document without beign
+ * clipped by the viewport or drawing the viewport scrollbars.
+ */
+ void SetIgnoreScrollFrame(nsIFrame* aFrame) { mIgnoreScrollFrame = aFrame; }
+ /**
+ * Get the scrollframe to ignore, if any.
+ */
+ nsIFrame* GetIgnoreScrollFrame() { return mIgnoreScrollFrame; }
+ void SetIsRelativeToLayoutViewport();
+ bool IsRelativeToLayoutViewport() const {
+ return mIsRelativeToLayoutViewport;
+ }
+ /**
+ * Get the ViewID of the nearest scrolling ancestor frame.
+ */
+ ViewID GetCurrentScrollParentId() const { return mCurrentScrollParentId; }
+ /**
+ * Get and set the flag that indicates if scroll parents should have layers
+ * forcibly created. This flag is set when a deeply nested scrollframe has
+ * a displayport, and for scroll handoff to work properly the ancestor
+ * scrollframes should also get their own scrollable layers.
+ */
+ void ForceLayerForScrollParent() { mForceLayerForScrollParent = true; }
+ /**
+ * Get the ViewID and the scrollbar flags corresponding to the scrollbar for
+ * which we are building display items at the moment.
+ */
+ ViewID GetCurrentScrollbarTarget() const { return mCurrentScrollbarTarget; }
+ MaybeScrollDirection GetCurrentScrollbarDirection() const {
+ return mCurrentScrollbarDirection;
+ }
+ /**
+ * Returns true if building a scrollbar, and the scrollbar will not be
+ * layerized.
+ */
+ bool IsBuildingNonLayerizedScrollbar() const {
+ return mIsBuildingScrollbar && !mCurrentScrollbarWillHaveLayer;
+ }
+ /**
+ * Calling this setter makes us include all out-of-flow descendant
+ * frames in the display list, wherever they may be positioned (even
+ * outside the dirty rects).
+ */
+ void SetIncludeAllOutOfFlows() { mIncludeAllOutOfFlows = true; }
+ bool GetIncludeAllOutOfFlows() const { return mIncludeAllOutOfFlows; }
+ /**
+ * Calling this setter makes us exclude all leaf frames that aren't
+ * selected.
+ */
+ void SetSelectedFramesOnly() { mSelectedFramesOnly = true; }
+ bool GetSelectedFramesOnly() { return mSelectedFramesOnly; }
+ /**
+ * Calling this setter makes us compute accurate visible regions at the cost
+ * of performance if regions get very complex.
+ */
+ bool GetAccurateVisibleRegions() {
+ return mMode == nsDisplayListBuilderMode::PluginGeometry;
+ }
+ /**
+ * @return Returns true if we should include the caret in any display lists
+ * that we make.
+ */
+ bool IsBuildingCaret() const { return mBuildCaret; }
+
+ bool IsRetainingDisplayList() const { return mRetainingDisplayList; }
+
+ bool IsPartialUpdate() const { return mPartialUpdate; }
+ void SetPartialUpdate(bool aPartial) { mPartialUpdate = aPartial; }
+
+ bool IsBuilding() const { return mIsBuilding; }
+ void SetIsBuilding(bool aIsBuilding) { mIsBuilding = aIsBuilding; }
+
+ bool InInvalidSubtree() const { return mInInvalidSubtree; }
+
+ /**
+ * Allows callers to selectively override the regular paint suppression
+ * checks, so that methods like GetFrameForPoint work when painting is
+ * suppressed.
+ */
+ void IgnorePaintSuppression() { mIgnoreSuppression = true; }
+ /**
+ * @return Returns if this builder will ignore paint suppression.
+ */
+ bool IsIgnoringPaintSuppression() { return mIgnoreSuppression; }
+ /**
+ * Call this if we're doing normal painting to the window.
+ */
+ void SetPaintingToWindow(bool aToWindow) { mIsPaintingToWindow = aToWindow; }
+ bool IsPaintingToWindow() const { return mIsPaintingToWindow; }
+ /**
+ * Call this if we're using high quality scaling for image decoding.
+ * It is also implied by IsPaintingToWindow.
+ */
+ void SetUseHighQualityScaling(bool aUseHighQualityScaling) {
+ mUseHighQualityScaling = aUseHighQualityScaling;
+ }
+ bool UseHighQualityScaling() const {
+ return mIsPaintingToWindow || mUseHighQualityScaling;
+ }
+ /**
+ * Call this if we're doing painting for WebRender
+ */
+ void SetPaintingForWebRender(bool aForWebRender) {
+ mIsPaintingForWebRender = true;
+ }
+ bool IsPaintingForWebRender() const { return mIsPaintingForWebRender; }
+ /**
+ * Call this to prevent descending into subdocuments.
+ */
+ void SetDescendIntoSubdocuments(bool aDescend) {
+ mDescendIntoSubdocuments = aDescend;
+ }
+
+ bool GetDescendIntoSubdocuments() { return mDescendIntoSubdocuments; }
+
+ /**
+ * Get dirty rect relative to current frame (the frame that we're calling
+ * BuildDisplayList on right now).
+ */
+ const nsRect& GetVisibleRect() { return mVisibleRect; }
+ const nsRect& GetDirtyRect() { return mDirtyRect; }
+
+ void SetVisibleRect(const nsRect& aVisibleRect) {
+ mVisibleRect = aVisibleRect;
+ }
+
+ void IntersectVisibleRect(const nsRect& aVisibleRect) {
+ mVisibleRect.IntersectRect(mVisibleRect, aVisibleRect);
+ }
+
+ void SetDirtyRect(const nsRect& aDirtyRect) { mDirtyRect = aDirtyRect; }
+
+ void IntersectDirtyRect(const nsRect& aDirtyRect) {
+ mDirtyRect.IntersectRect(mDirtyRect, aDirtyRect);
+ }
+
+ const nsIFrame* GetCurrentFrame() { return mCurrentFrame; }
+ const nsIFrame* GetCurrentReferenceFrame() { return mCurrentReferenceFrame; }
+
+ const nsPoint& GetCurrentFrameOffsetToReferenceFrame() const {
+ return mCurrentOffsetToReferenceFrame;
+ }
+
+ AnimatedGeometryRoot* GetCurrentAnimatedGeometryRoot() { return mCurrentAGR; }
+ AnimatedGeometryRoot* GetRootAnimatedGeometryRoot() { return mRootAGR; }
+
+ void RecomputeCurrentAnimatedGeometryRoot();
+
+ void Check() { mPool.Check(); }
+
+ /**
+ * Returns true if merging and flattening of display lists should be
+ * performed while computing visibility.
+ */
+ bool AllowMergingAndFlattening() { return mAllowMergingAndFlattening; }
+ void SetAllowMergingAndFlattening(bool aAllow) {
+ mAllowMergingAndFlattening = aAllow;
+ }
+
+ /**
+ * Sets the current compositor hit test area and info to |aHitTestArea| and
+ * |aHitTestInfo|.
+ * This is used during display list building to determine if the parent frame
+ * hit test info contains the same information that child frame needs.
+ */
+ void SetCompositorHitTestInfo(const nsRect& aHitTestArea,
+ const CompositorHitTestInfo& aHitTestInfo) {
+ mHitTestArea = aHitTestArea;
+ mHitTestInfo = aHitTestInfo;
+ }
+
+ const nsRect& GetHitTestArea() const { return mHitTestArea; }
+ const CompositorHitTestInfo& GetHitTestInfo() const { return mHitTestInfo; }
+
+ /**
+ * Builds a new nsDisplayCompositorHitTestInfo for the frame |aFrame| if
+ * needed, and adds it to the top of |aList|. If |aBuildNew| is true, the
+ * previous hit test info will not be reused.
+ */
+ void BuildCompositorHitTestInfoIfNeeded(nsIFrame* aFrame,
+ nsDisplayList* aList,
+ const bool aBuildNew);
+
+ bool IsInsidePointerEventsNoneDoc() {
+ return CurrentPresShellState()->mInsidePointerEventsNoneDoc;
+ }
+
+ bool IsTouchEventPrefEnabledDoc() {
+ return CurrentPresShellState()->mTouchEventPrefEnabledDoc;
+ }
+
+ bool GetAncestorHasApzAwareEventHandler() const {
+ return mAncestorHasApzAwareEventHandler;
+ }
+
+ void SetAncestorHasApzAwareEventHandler(bool aValue) {
+ mAncestorHasApzAwareEventHandler = aValue;
+ }
+
+ bool HaveScrollableDisplayPort() const { return mHaveScrollableDisplayPort; }
+ void SetHaveScrollableDisplayPort() { mHaveScrollableDisplayPort = true; }
+ void ClearHaveScrollableDisplayPort() { mHaveScrollableDisplayPort = false; }
+
+ bool SetIsCompositingCheap(bool aCompositingCheap) {
+ bool temp = mIsCompositingCheap;
+ mIsCompositingCheap = aCompositingCheap;
+ return temp;
+ }
+
+ bool IsCompositingCheap() const { return mIsCompositingCheap; }
+ /**
+ * Display the caret if needed.
+ */
+ bool DisplayCaret(nsIFrame* aFrame, nsDisplayList* aList) {
+ nsIFrame* frame = GetCaretFrame();
+ if (aFrame == frame && !IsBackgroundOnly()) {
+ frame->DisplayCaret(this, aList);
+ return true;
+ }
+ return false;
+ }
+ /**
+ * Get the frame that the caret is supposed to draw in.
+ * If the caret is currently invisible, this will be null.
+ */
+ nsIFrame* GetCaretFrame() { return mCaretFrame; }
+ /**
+ * Get the rectangle we're supposed to draw the caret into.
+ */
+ const nsRect& GetCaretRect() { return mCaretRect; }
+ /**
+ * Get the caret associated with the current presshell.
+ */
+ nsCaret* GetCaret();
+
+ /**
+ * Returns the root scroll frame for the current PresShell, if the PresShell
+ * is ignoring viewport scrolling.
+ */
+ nsIFrame* GetPresShellIgnoreScrollFrame() {
+ return CurrentPresShellState()->mPresShellIgnoreScrollFrame;
+ }
+
+ /**
+ * Notify the display list builder that we're entering a presshell.
+ * aReferenceFrame should be a frame in the new presshell.
+ * aPointerEventsNoneDoc should be set to true if the frame generating this
+ * document is pointer-events:none.
+ */
+ void EnterPresShell(const nsIFrame* aReferenceFrame,
+ bool aPointerEventsNoneDoc = false);
+ /**
+ * For print-preview documents, we sometimes need to build display items for
+ * the same frames multiple times in the same presentation, with different
+ * clipping. Between each such batch of items, call
+ * ResetMarkedFramesForDisplayList to make sure that the results of
+ * MarkFramesForDisplayList do not carry over between batches.
+ */
+ void ResetMarkedFramesForDisplayList(const nsIFrame* aReferenceFrame);
+ /**
+ * Notify the display list builder that we're leaving a presshell.
+ */
+ void LeavePresShell(const nsIFrame* aReferenceFrame,
+ nsDisplayList* aPaintedContents);
+
+ void IncrementPresShellPaintCount(mozilla::PresShell* aPresShell);
+
+ /**
+ * Returns true if we're currently building a display list that's
+ * directly or indirectly under an nsDisplayTransform.
+ */
+ bool IsInTransform() const { return mInTransform; }
+
+ bool InEventsAndPluginsOnly() const { return mInEventsAndPluginsOnly; }
+ /**
+ * Indicate whether or not we're directly or indirectly under and
+ * nsDisplayTransform or SVG foreignObject.
+ */
+ void SetInTransform(bool aInTransform) { mInTransform = aInTransform; }
+
+ /**
+ * Returns true if we're currently building a display list that's
+ * under an nsDisplayFilters.
+ */
+ bool IsInFilter() const { return mInFilter; }
+
+ bool IsInPageSequence() const { return mInPageSequence; }
+ void SetInPageSequence(bool aInPage) { mInPageSequence = aInPage; }
+
+ /**
+ * Return true if we're currently building a display list for a
+ * nested presshell.
+ */
+ bool IsInSubdocument() const { return mPresShellStates.Length() > 1; }
+
+ void SetDisablePartialUpdates(bool aDisable) {
+ mDisablePartialUpdates = aDisable;
+ }
+ bool DisablePartialUpdates() const { return mDisablePartialUpdates; }
+
+ void SetPartialBuildFailed(bool aFailed) { mPartialBuildFailed = aFailed; }
+ bool PartialBuildFailed() const { return mPartialBuildFailed; }
+
+ bool IsInActiveDocShell() const { return mIsInActiveDocShell; }
+ void SetInActiveDocShell(bool aActive) { mIsInActiveDocShell = aActive; }
+
+ /**
+ * Return true if we're currently building a display list for the presshell
+ * of a chrome document, or if we're building the display list for a popup.
+ */
+ bool IsInChromeDocumentOrPopup() const {
+ return mIsInChromePresContext || mIsBuildingForPopup;
+ }
+
+ /**
+ * @return true if images have been set to decode synchronously.
+ */
+ bool ShouldSyncDecodeImages() const { return mSyncDecodeImages; }
+
+ /**
+ * Indicates whether we should synchronously decode images. If true, we decode
+ * and draw whatever image data has been loaded. If false, we just draw
+ * whatever has already been decoded.
+ */
+ void SetSyncDecodeImages(bool aSyncDecodeImages) {
+ mSyncDecodeImages = aSyncDecodeImages;
+ }
+
+ nsDisplayTableBackgroundSet* SetTableBackgroundSet(
+ nsDisplayTableBackgroundSet* aTableSet) {
+ nsDisplayTableBackgroundSet* old = mTableBackgroundSet;
+ mTableBackgroundSet = aTableSet;
+ return old;
+ }
+ nsDisplayTableBackgroundSet* GetTableBackgroundSet() const {
+ return mTableBackgroundSet;
+ }
+
+ void FreeClipChains();
+
+ /*
+ * Frees the temporary display items created during merging.
+ */
+ void FreeTemporaryItems();
+
+ /**
+ * Helper method to generate background painting flags based on the
+ * information available in the display list builder. Currently only
+ * accounts for mSyncDecodeImages.
+ */
+ uint32_t GetBackgroundPaintFlags();
+
+ /**
+ * Helper method to generate image decoding flags based on the
+ * information available in the display list builder.
+ */
+ uint32_t GetImageDecodeFlags() const;
+
+ /**
+ * Subtracts aRegion from *aVisibleRegion. We avoid letting
+ * aVisibleRegion become overcomplex by simplifying it if necessary.
+ */
+ void SubtractFromVisibleRegion(nsRegion* aVisibleRegion,
+ const nsRegion& aRegion);
+
+ /**
+ * Mark the frames in aFrames to be displayed if they intersect aDirtyRect
+ * (which is relative to aDirtyFrame). If the frames have placeholders
+ * that might not be displayed, we mark the placeholders and their ancestors
+ * to ensure that display list construction descends into them
+ * anyway. nsDisplayListBuilder will take care of unmarking them when it is
+ * destroyed.
+ */
+ void MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
+ const nsFrameList& aFrames);
+ void MarkFrameForDisplay(nsIFrame* aFrame, const nsIFrame* aStopAtFrame);
+ void MarkFrameForDisplayIfVisible(nsIFrame* aFrame,
+ const nsIFrame* aStopAtFrame);
+ void AddFrameMarkedForDisplayIfVisible(nsIFrame* aFrame);
+
+ void ClearFixedBackgroundDisplayData();
+ /**
+ * Mark all child frames that Preserve3D() as needing display.
+ * Because these frames include transforms set on their parent, dirty rects
+ * for intermediate frames may be empty, yet child frames could still be
+ * visible.
+ */
+ void MarkPreserve3DFramesForDisplayList(nsIFrame* aDirtyFrame);
+
+ /**
+ * Returns true if we need to descend into this frame when building
+ * the display list, even though it doesn't intersect the dirty
+ * rect, because it may have out-of-flows that do so.
+ */
+ bool ShouldDescendIntoFrame(nsIFrame* aFrame, bool aVisible) const {
+ return aFrame->HasAnyStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) ||
+ (aVisible && aFrame->ForceDescendIntoIfVisible()) ||
+ GetIncludeAllOutOfFlows();
+ }
+
+ /**
+ * Returns the list of registered theme geometries.
+ */
+ nsTArray<ThemeGeometry> GetThemeGeometries() const {
+ nsTArray<ThemeGeometry> geometries;
+
+ for (auto iter = mThemeGeometries.ConstIter(); !iter.Done(); iter.Next()) {
+ geometries.AppendElements(*iter.Data());
+ }
+
+ return geometries;
+ }
+
+ /**
+ * Notifies the builder that a particular themed widget exists
+ * at the given rectangle within the currently built display list.
+ * For certain appearance values (currently only StyleAppearance::Toolbar and
+ * StyleAppearance::WindowTitlebar) this gets called during every display list
+ * construction, for every themed widget of the right type within the
+ * display list, except for themed widgets which are transformed or have
+ * effects applied to them (e.g. CSS opacity or filters).
+ *
+ * @param aWidgetType the -moz-appearance value for the themed widget
+ * @param aItem the item associated with the theme geometry
+ * @param aRect the device-pixel rect relative to the widget's displayRoot
+ * for the themed widget
+ */
+ void RegisterThemeGeometry(uint8_t aWidgetType, nsDisplayItem* aItem,
+ const mozilla::LayoutDeviceIntRect& aRect) {
+ if (!mIsPaintingToWindow) {
+ return;
+ }
+
+ nsTArray<ThemeGeometry>* geometries = mThemeGeometries.LookupOrAdd(aItem);
+ geometries->AppendElement(ThemeGeometry(aWidgetType, aRect));
+ }
+
+ /**
+ * Removes theme geometries associated with the given display item |aItem|.
+ */
+ void UnregisterThemeGeometry(nsDisplayItem* aItem) {
+ mThemeGeometries.Remove(aItem);
+ }
+
+ /**
+ * Adjusts mWindowDraggingRegion to take into account aFrame. If aFrame's
+ * -moz-window-dragging value is |drag|, its border box is added to the
+ * collected dragging region; if the value is |no-drag|, the border box is
+ * subtracted from the region; if the value is |default|, that frame does
+ * not influence the window dragging region.
+ */
+ void AdjustWindowDraggingRegion(nsIFrame* aFrame);
+
+ LayoutDeviceIntRegion GetWindowDraggingRegion() const;
+
+ void RemoveModifiedWindowRegions();
+ void ClearRetainedWindowRegions();
+
+ const nsDataHashtable<nsPtrHashKey<RemoteBrowser>, EffectsInfo>&
+ GetEffectUpdates() const {
+ return mEffectsUpdates;
+ }
+
+ void AddEffectUpdate(RemoteBrowser* aBrowser, EffectsInfo aUpdate) {
+ mEffectsUpdates.Put(aBrowser, aUpdate);
+ }
+
+ /**
+ * Allocate memory in our arena. It will only be freed when this display list
+ * builder is destroyed. This memory holds nsDisplayItems and
+ * DisplayItemClipChain objects.
+ *
+ * Destructors are called as soon as the item is no longer used.
+ */
+ void* Allocate(size_t aSize, mozilla::DisplayListArenaObjectId aId) {
+ return mPool.Allocate(aId, aSize);
+ }
+ void* Allocate(size_t aSize, DisplayItemType aType) {
+ static_assert(size_t(DisplayItemType::TYPE_ZERO) ==
+ size_t(mozilla::DisplayListArenaObjectId::CLIPCHAIN),
+ "");
+#define DECLARE_DISPLAY_ITEM_TYPE(name_, ...) \
+ static_assert(size_t(DisplayItemType::TYPE_##name_) == \
+ size_t(mozilla::DisplayListArenaObjectId::name_), \
+ "");
+#include "nsDisplayItemTypesList.h"
+#undef DECLARE_DISPLAY_ITEM_TYPE
+ return Allocate(aSize, mozilla::DisplayListArenaObjectId(size_t(aType)));
+ }
+
+ void Destroy(mozilla::DisplayListArenaObjectId aId, void* aPtr) {
+ return mPool.Free(aId, aPtr);
+ }
+ void Destroy(DisplayItemType aType, void* aPtr) {
+ return Destroy(mozilla::DisplayListArenaObjectId(size_t(aType)), aPtr);
+ }
+
+ /**
+ * Allocate a new ActiveScrolledRoot in the arena. Will be cleaned up
+ * automatically when the arena goes away.
+ */
+ ActiveScrolledRoot* AllocateActiveScrolledRoot(
+ const ActiveScrolledRoot* aParent, nsIScrollableFrame* aScrollableFrame);
+
+ /**
+ * Allocate a new DisplayItemClipChain object in the arena. Will be cleaned
+ * up automatically when the arena goes away.
+ */
+ const DisplayItemClipChain* AllocateDisplayItemClipChain(
+ const DisplayItemClip& aClip, const ActiveScrolledRoot* aASR,
+ const DisplayItemClipChain* aParent);
+
+ /**
+ * Intersect two clip chains, allocating the new clip chain items in this
+ * builder's arena. The result is parented to aAncestor, and no intersections
+ * happen past aAncestor's ASR.
+ * That means aAncestor has to be living in this builder's arena already.
+ * aLeafClip1 and aLeafClip2 only need to outlive the call to this function,
+ * their values are copied into the newly-allocated intersected clip chain
+ * and this function does not hold on to any pointers to them.
+ */
+ const DisplayItemClipChain* CreateClipChainIntersection(
+ const DisplayItemClipChain* aAncestor,
+ const DisplayItemClipChain* aLeafClip1,
+ const DisplayItemClipChain* aLeafClip2);
+
+ /**
+ * Clone the supplied clip chain's chain items into this builder's arena.
+ */
+ const DisplayItemClipChain* CopyWholeChain(
+ const DisplayItemClipChain* aClipChain);
+
+ /**
+ * Returns a new clip chain containing an intersection of all clips of
+ * |aClipChain| up to and including |aASR|.
+ * If there is no clip, returns nullptr.
+ */
+ const DisplayItemClipChain* FuseClipChainUpTo(
+ const DisplayItemClipChain* aClipChain, const ActiveScrolledRoot* aASR);
+
+ const ActiveScrolledRoot* GetFilterASR() const { return mFilterASR; }
+
+ /**
+ * Transfer off main thread animations to the layer. May be called
+ * with aBuilder and aItem both null, but only if the caller has
+ * already checked that off main thread animations should be sent to
+ * the layer. When they are both null, the animations are added to
+ * the layer as pending animations.
+ */
+ static void AddAnimationsAndTransitionsToLayer(Layer* aLayer,
+ nsDisplayListBuilder* aBuilder,
+ nsDisplayItem* aItem,
+ nsIFrame* aFrame,
+ DisplayItemType aType);
+
+ /**
+ * Merges the display items in |aMergedItems| and returns a new temporary
+ * display item.
+ * The display items in |aMergedItems| have to be mergeable with each other.
+ */
+ nsDisplayWrapList* MergeItems(nsTArray<nsDisplayWrapList*>& aItems);
+
+ /**
+ * A helper class used to temporarily set nsDisplayListBuilder properties for
+ * building display items.
+ * aVisibleRect and aDirtyRect are relative to aForChild.
+ */
+ class AutoBuildingDisplayList {
+ public:
+ AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, nsIFrame* aForChild)
+ : AutoBuildingDisplayList(
+ aBuilder, aForChild, aBuilder->GetVisibleRect(),
+ aBuilder->GetDirtyRect(), aForChild->IsTransformed()) {}
+
+ AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, nsIFrame* aForChild,
+ const nsRect& aVisibleRect,
+ const nsRect& aDirtyRect)
+ : AutoBuildingDisplayList(aBuilder, aForChild, aVisibleRect, aDirtyRect,
+ aForChild->IsTransformed()) {}
+
+ AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, nsIFrame* aForChild,
+ const nsRect& aVisibleRect,
+ const nsRect& aDirtyRect,
+ const bool aIsTransformed);
+
+ void SetReferenceFrameAndCurrentOffset(const nsIFrame* aFrame,
+ const nsPoint& aOffset) {
+ mBuilder->mCurrentReferenceFrame = aFrame;
+ mBuilder->mCurrentOffsetToReferenceFrame = aOffset;
+ }
+
+ void SetAdditionalOffset(const nsPoint& aOffset) {
+ MOZ_ASSERT(!mBuilder->mAdditionalOffset);
+ mBuilder->mAdditionalOffset = mozilla::Some(aOffset);
+
+ mBuilder->mCurrentOffsetToReferenceFrame += aOffset;
+ mBuilder->mAdditionalOffsetFrame = mBuilder->mCurrentReferenceFrame;
+ }
+
+ bool IsAnimatedGeometryRoot() const { return mCurrentAGRState == AGR_YES; }
+
+ void RestoreBuildingInvisibleItemsValue() {
+ mBuilder->mBuildingInvisibleItems = mPrevBuildingInvisibleItems;
+ }
+
+ ~AutoBuildingDisplayList() {
+ mBuilder->mCurrentFrame = mPrevFrame;
+ mBuilder->mCurrentReferenceFrame = mPrevReferenceFrame;
+ mBuilder->mHitTestArea = mPrevHitTestArea;
+ mBuilder->mHitTestInfo = mPrevHitTestInfo;
+ mBuilder->mCurrentOffsetToReferenceFrame = mPrevOffset;
+ mBuilder->mVisibleRect = mPrevVisibleRect;
+ mBuilder->mDirtyRect = mPrevDirtyRect;
+ mBuilder->mCurrentAGR = mPrevAGR;
+ mBuilder->mAncestorHasApzAwareEventHandler =
+ mPrevAncestorHasApzAwareEventHandler;
+ mBuilder->mBuildingInvisibleItems = mPrevBuildingInvisibleItems;
+ mBuilder->mInInvalidSubtree = mPrevInInvalidSubtree;
+ mBuilder->mAdditionalOffset = mPrevAdditionalOffset;
+ }
+
+ private:
+ nsDisplayListBuilder* mBuilder;
+ AGRState mCurrentAGRState;
+ const nsIFrame* mPrevFrame;
+ const nsIFrame* mPrevReferenceFrame;
+ nsRect mPrevHitTestArea;
+ CompositorHitTestInfo mPrevHitTestInfo;
+ nsPoint mPrevOffset;
+ mozilla::Maybe<nsPoint> mPrevAdditionalOffset;
+ nsRect mPrevVisibleRect;
+ nsRect mPrevDirtyRect;
+ RefPtr<AnimatedGeometryRoot> mPrevAGR;
+ bool mPrevAncestorHasApzAwareEventHandler;
+ bool mPrevBuildingInvisibleItems;
+ bool mPrevInInvalidSubtree;
+ };
+
+ /**
+ * A helper class to temporarily set the value of mInTransform.
+ */
+ class AutoInTransformSetter {
+ public:
+ AutoInTransformSetter(nsDisplayListBuilder* aBuilder, bool aInTransform)
+ : mBuilder(aBuilder), mOldValue(aBuilder->mInTransform) {
+ aBuilder->mInTransform = aInTransform;
+ }
+
+ ~AutoInTransformSetter() { mBuilder->mInTransform = mOldValue; }
+
+ private:
+ nsDisplayListBuilder* mBuilder;
+ bool mOldValue;
+ };
+
+ class AutoInEventsAndPluginsOnly {
+ public:
+ AutoInEventsAndPluginsOnly(nsDisplayListBuilder* aBuilder,
+ bool aInEventsAndPluginsOnly)
+ : mBuilder(aBuilder), mOldValue(aBuilder->mInEventsAndPluginsOnly) {
+ aBuilder->mInEventsAndPluginsOnly |= aInEventsAndPluginsOnly;
+ }
+
+ ~AutoInEventsAndPluginsOnly() {
+ mBuilder->mInEventsAndPluginsOnly = mOldValue;
+ }
+
+ private:
+ nsDisplayListBuilder* mBuilder;
+ bool mOldValue;
+ };
+
+ /**
+ * A helper class to temporarily set the value of mFilterASR and
+ * mInFilter.
+ */
+ class AutoEnterFilter {
+ public:
+ AutoEnterFilter(nsDisplayListBuilder* aBuilder, bool aUsingFilter)
+ : mBuilder(aBuilder),
+ mOldValue(aBuilder->mFilterASR),
+ mOldInFilter(aBuilder->mInFilter) {
+ if (!aBuilder->mFilterASR && aUsingFilter) {
+ aBuilder->mFilterASR = aBuilder->CurrentActiveScrolledRoot();
+ aBuilder->mInFilter = true;
+ }
+ }
+
+ ~AutoEnterFilter() {
+ mBuilder->mFilterASR = mOldValue;
+ mBuilder->mInFilter = mOldInFilter;
+ }
+
+ private:
+ nsDisplayListBuilder* mBuilder;
+ const ActiveScrolledRoot* mOldValue;
+ bool mOldInFilter;
+ };
+
+ /**
+ * A helper class to temporarily set the value of mCurrentScrollParentId.
+ */
+ class AutoCurrentScrollParentIdSetter {
+ public:
+ AutoCurrentScrollParentIdSetter(nsDisplayListBuilder* aBuilder,
+ ViewID aScrollId)
+ : mBuilder(aBuilder),
+ mOldValue(aBuilder->mCurrentScrollParentId),
+ mOldForceLayer(aBuilder->mForceLayerForScrollParent) {
+ // If this AutoCurrentScrollParentIdSetter has the same scrollId as the
+ // previous one on the stack, then that means the scrollframe that
+ // created this isn't actually scrollable and cannot participate in
+ // scroll handoff. We set mCanBeScrollParent to false to indicate this.
+ mCanBeScrollParent = (mOldValue != aScrollId);
+ aBuilder->mCurrentScrollParentId = aScrollId;
+ aBuilder->mForceLayerForScrollParent = false;
+ }
+
+ bool ShouldForceLayerForScrollParent() const {
+ // Only scrollframes participating in scroll handoff can be forced to
+ // layerize
+ return mCanBeScrollParent && mBuilder->mForceLayerForScrollParent;
+ }
+
+ ~AutoCurrentScrollParentIdSetter() {
+ mBuilder->mCurrentScrollParentId = mOldValue;
+ if (mCanBeScrollParent) {
+ // If this flag is set, caller code is responsible for having dealt
+ // with the current value of mBuilder->mForceLayerForScrollParent, so
+ // we can just restore the old value.
+ mBuilder->mForceLayerForScrollParent = mOldForceLayer;
+ } else {
+ // Otherwise we need to keep propagating the force-layerization flag
+ // upwards to the next ancestor scrollframe that does participate in
+ // scroll handoff.
+ mBuilder->mForceLayerForScrollParent |= mOldForceLayer;
+ }
+ }
+
+ private:
+ nsDisplayListBuilder* mBuilder;
+ ViewID mOldValue;
+ bool mOldForceLayer;
+ bool mCanBeScrollParent;
+ };
+
+ /**
+ * Used to update the current active scrolled root on the display list
+ * builder, and to create new active scrolled roots.
+ */
+ class AutoCurrentActiveScrolledRootSetter {
+ public:
+ explicit AutoCurrentActiveScrolledRootSetter(nsDisplayListBuilder* aBuilder)
+ : mBuilder(aBuilder),
+ mSavedActiveScrolledRoot(aBuilder->mCurrentActiveScrolledRoot),
+ mContentClipASR(aBuilder->ClipState().GetContentClipASR()),
+ mDescendantsStartIndex(aBuilder->mActiveScrolledRoots.Length()),
+ mUsed(false) {}
+
+ ~AutoCurrentActiveScrolledRootSetter() {
+ mBuilder->mCurrentActiveScrolledRoot = mSavedActiveScrolledRoot;
+ }
+
+ void SetCurrentActiveScrolledRoot(
+ const ActiveScrolledRoot* aActiveScrolledRoot);
+
+ void EnterScrollFrame(nsIScrollableFrame* aScrollableFrame) {
+ MOZ_ASSERT(!mUsed);
+ ActiveScrolledRoot* asr = mBuilder->AllocateActiveScrolledRoot(
+ mBuilder->mCurrentActiveScrolledRoot, aScrollableFrame);
+ mBuilder->mCurrentActiveScrolledRoot = asr;
+ mUsed = true;
+ }
+
+ void InsertScrollFrame(nsIScrollableFrame* aScrollableFrame);
+
+ private:
+ nsDisplayListBuilder* mBuilder;
+ /**
+ * The builder's mCurrentActiveScrolledRoot at construction time which
+ * needs to be restored at destruction time.
+ */
+ const ActiveScrolledRoot* mSavedActiveScrolledRoot;
+ /**
+ * If there's a content clip on the builder at construction time, then
+ * mContentClipASR is that content clip's ASR, otherwise null. The
+ * assumption is that the content clip doesn't get relaxed while this
+ * object is on the stack.
+ */
+ const ActiveScrolledRoot* mContentClipASR;
+ /**
+ * InsertScrollFrame needs to mutate existing ASRs (those that were
+ * created while this object was on the stack), and mDescendantsStartIndex
+ * makes it easier to skip ASRs that were created in the past.
+ */
+ size_t mDescendantsStartIndex;
+ /**
+ * Flag to make sure that only one of SetCurrentActiveScrolledRoot /
+ * EnterScrollFrame / InsertScrollFrame is called per instance of this
+ * class.
+ */
+ bool mUsed;
+ };
+
+ /**
+ * Keeps track of the innermost ASR that can be used as the ASR for a
+ * container item that wraps all items that were created while this
+ * object was on the stack.
+ * The rule is: all child items of the container item need to have
+ * clipped bounds with respect to the container ASR.
+ */
+ class AutoContainerASRTracker {
+ public:
+ explicit AutoContainerASRTracker(nsDisplayListBuilder* aBuilder)
+ : mBuilder(aBuilder),
+ mSavedContainerASR(aBuilder->mCurrentContainerASR) {
+ mBuilder->mCurrentContainerASR = ActiveScrolledRoot::PickDescendant(
+ mBuilder->ClipState().GetContentClipASR(),
+ mBuilder->mCurrentActiveScrolledRoot);
+ }
+
+ const ActiveScrolledRoot* GetContainerASR() {
+ return mBuilder->mCurrentContainerASR;
+ }
+
+ ~AutoContainerASRTracker() {
+ mBuilder->mCurrentContainerASR = ActiveScrolledRoot::PickAncestor(
+ mBuilder->mCurrentContainerASR, mSavedContainerASR);
+ }
+
+ private:
+ nsDisplayListBuilder* mBuilder;
+ const ActiveScrolledRoot* mSavedContainerASR;
+ };
+
+ /**
+ * A helper class to temporarily set the value of mCurrentScrollbarTarget
+ * and mCurrentScrollbarFlags.
+ */
+ class AutoCurrentScrollbarInfoSetter {
+ public:
+ AutoCurrentScrollbarInfoSetter(
+ nsDisplayListBuilder* aBuilder, ViewID aScrollTargetID,
+ const MaybeScrollDirection& aScrollbarDirection, bool aWillHaveLayer)
+ : mBuilder(aBuilder) {
+ aBuilder->mIsBuildingScrollbar = true;
+ aBuilder->mCurrentScrollbarTarget = aScrollTargetID;
+ aBuilder->mCurrentScrollbarDirection = aScrollbarDirection;
+ aBuilder->mCurrentScrollbarWillHaveLayer = aWillHaveLayer;
+ }
+
+ ~AutoCurrentScrollbarInfoSetter() {
+ // No need to restore old values because scrollbars cannot be nested.
+ mBuilder->mIsBuildingScrollbar = false;
+ mBuilder->mCurrentScrollbarTarget = ScrollableLayerGuid::NULL_SCROLL_ID;
+ mBuilder->mCurrentScrollbarDirection.reset();
+ mBuilder->mCurrentScrollbarWillHaveLayer = false;
+ }
+
+ private:
+ nsDisplayListBuilder* mBuilder;
+ };
+
+ /**
+ * A helper class to temporarily set mBuildingExtraPagesForPageNum.
+ */
+ class MOZ_RAII AutoPageNumberSetter {
+ public:
+ AutoPageNumberSetter(nsDisplayListBuilder* aBuilder, const uint8_t aPageNum)
+ : mBuilder(aBuilder),
+ mOldPageNum(aBuilder->GetBuildingExtraPagesForPageNum()) {
+ mBuilder->SetBuildingExtraPagesForPageNum(aPageNum);
+ }
+ ~AutoPageNumberSetter() {
+ mBuilder->SetBuildingExtraPagesForPageNum(mOldPageNum);
+ }
+
+ private:
+ nsDisplayListBuilder* mBuilder;
+ uint8_t mOldPageNum;
+ };
+
+ /**
+ * A helper class to track current effective transform for items.
+ *
+ * For frames that is Combines3DTransformWithAncestors(), we need to
+ * apply all transforms of ancestors on the same preserves3D chain
+ * on the bounds of current frame to the coordination of the 3D
+ * context root. The 3D context root computes it's bounds from
+ * these transformed bounds.
+ */
+ class AutoAccumulateTransform {
+ public:
+ typedef mozilla::gfx::Matrix4x4 Matrix4x4;
+
+ explicit AutoAccumulateTransform(nsDisplayListBuilder* aBuilder)
+ : mBuilder(aBuilder),
+ mSavedTransform(aBuilder->mPreserves3DCtx.mAccumulatedTransform) {}
+
+ ~AutoAccumulateTransform() {
+ mBuilder->mPreserves3DCtx.mAccumulatedTransform = mSavedTransform;
+ }
+
+ void Accumulate(const Matrix4x4& aTransform) {
+ mBuilder->mPreserves3DCtx.mAccumulatedTransform =
+ aTransform * mBuilder->mPreserves3DCtx.mAccumulatedTransform;
+ }
+
+ const Matrix4x4& GetCurrentTransform() {
+ return mBuilder->mPreserves3DCtx.mAccumulatedTransform;
+ }
+
+ void StartRoot() {
+ mBuilder->mPreserves3DCtx.mAccumulatedTransform = Matrix4x4();
+ }
+
+ private:
+ nsDisplayListBuilder* mBuilder;
+ Matrix4x4 mSavedTransform;
+ };
+
+ /**
+ * A helper class to collect bounds rects of descendants.
+ *
+ * For a 3D context root, it's bounds is computed from the bounds of
+ * descendants. If we transform bounds frame by frame applying
+ * transforms, the bounds may turn to empty for any singular
+ * transform on the path, but it is not empty for the accumulated
+ * transform.
+ */
+ class AutoAccumulateRect {
+ public:
+ explicit AutoAccumulateRect(nsDisplayListBuilder* aBuilder)
+ : mBuilder(aBuilder),
+ mSavedRect(aBuilder->mPreserves3DCtx.mAccumulatedRect) {
+ aBuilder->mPreserves3DCtx.mAccumulatedRect = nsRect();
+ aBuilder->mPreserves3DCtx.mAccumulatedRectLevels++;
+ }
+
+ ~AutoAccumulateRect() {
+ mBuilder->mPreserves3DCtx.mAccumulatedRect = mSavedRect;
+ mBuilder->mPreserves3DCtx.mAccumulatedRectLevels--;
+ }
+
+ private:
+ nsDisplayListBuilder* mBuilder;
+ nsRect mSavedRect;
+ };
+
+ void AccumulateRect(const nsRect& aRect) {
+ mPreserves3DCtx.mAccumulatedRect.UnionRect(mPreserves3DCtx.mAccumulatedRect,
+ aRect);
+ }
+
+ const nsRect& GetAccumulatedRect() {
+ return mPreserves3DCtx.mAccumulatedRect;
+ }
+
+ /**
+ * The level is increased by one for items establishing 3D rendering
+ * context and starting a new accumulation.
+ */
+ int GetAccumulatedRectLevels() {
+ return mPreserves3DCtx.mAccumulatedRectLevels;
+ }
+
+ struct OutOfFlowDisplayData {
+ OutOfFlowDisplayData(
+ const DisplayItemClipChain* aContainingBlockClipChain,
+ const DisplayItemClipChain* aCombinedClipChain,
+ const ActiveScrolledRoot* aContainingBlockActiveScrolledRoot,
+ const nsRect& aVisibleRect, const nsRect& aDirtyRect)
+ : mContainingBlockClipChain(aContainingBlockClipChain),
+ mCombinedClipChain(aCombinedClipChain),
+ mContainingBlockActiveScrolledRoot(
+ aContainingBlockActiveScrolledRoot),
+ mVisibleRect(aVisibleRect),
+ mDirtyRect(aDirtyRect) {}
+ const DisplayItemClipChain* mContainingBlockClipChain;
+ const DisplayItemClipChain*
+ mCombinedClipChain; // only necessary for the special case of top layer
+ const ActiveScrolledRoot* mContainingBlockActiveScrolledRoot;
+
+ // If this OutOfFlowDisplayData is associated with the ViewportFrame
+ // of a document that has a resolution (creating separate visual and
+ // layout viewports with their own coordinate spaces), these rects
+ // are in layout coordinates. Similarly, GetVisibleRectForFrame() in
+ // such a case returns a quantity in layout coordinates.
+ nsRect mVisibleRect;
+ nsRect mDirtyRect;
+
+ static nsRect ComputeVisibleRectForFrame(nsDisplayListBuilder* aBuilder,
+ nsIFrame* aFrame,
+ const nsRect& aVisibleRect,
+ const nsRect& aDirtyRect,
+ nsRect* aOutDirtyRect);
+
+ nsRect GetVisibleRectForFrame(nsDisplayListBuilder* aBuilder,
+ nsIFrame* aFrame, nsRect* aDirtyRect) {
+ return ComputeVisibleRectForFrame(aBuilder, aFrame, mVisibleRect,
+ mDirtyRect, aDirtyRect);
+ }
+ };
+
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(OutOfFlowDisplayDataProperty,
+ OutOfFlowDisplayData)
+
+ struct DisplayListBuildingData {
+ RefPtr<AnimatedGeometryRoot> mModifiedAGR = nullptr;
+ nsRect mDirtyRect;
+ };
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(DisplayListBuildingRect,
+ DisplayListBuildingData)
+
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(DisplayListBuildingDisplayPortRect,
+ nsRect)
+
+ static OutOfFlowDisplayData* GetOutOfFlowData(nsIFrame* aFrame) {
+ if (!aFrame->GetParent()) {
+ return nullptr;
+ }
+ return aFrame->GetParent()->GetProperty(OutOfFlowDisplayDataProperty());
+ }
+
+ nsPresContext* CurrentPresContext();
+
+ OutOfFlowDisplayData* GetCurrentFixedBackgroundDisplayData() {
+ auto& displayData = CurrentPresShellState()->mFixedBackgroundDisplayData;
+ return displayData ? displayData.ptr() : nullptr;
+ }
+
+ /**
+ * Accumulates the bounds of box frames that have moz-appearance
+ * -moz-win-exclude-glass style. Used in setting glass margins on
+ * Windows.
+ *
+ * We set the window opaque region (from which glass margins are computed)
+ * to the intersection of the glass region specified here and the opaque
+ * region computed during painting. So the excluded glass region actually
+ * *limits* the extent of the opaque area reported to Windows. We limit it
+ * so that changes to the computed opaque region (which can vary based on
+ * region optimizations and the placement of UI elements) outside the
+ * -moz-win-exclude-glass area don't affect the glass margins reported to
+ * Windows; changing those margins willy-nilly can cause the Windows 7 glass
+ * haze effect to jump around disconcertingly.
+ */
+ void AddWindowExcludeGlassRegion(nsIFrame* aFrame, const nsRect& aBounds) {
+ mWindowExcludeGlassRegion.Add(aFrame, aBounds);
+ }
+
+ /**
+ * Returns the window exclude glass region.
+ */
+ nsRegion GetWindowExcludeGlassRegion() const {
+ return mWindowExcludeGlassRegion.ToRegion();
+ }
+
+ /**
+ * Accumulates opaque stuff into the window opaque region.
+ */
+ void AddWindowOpaqueRegion(nsIFrame* aFrame, const nsRect& aBounds) {
+ if (IsRetainingDisplayList()) {
+ mRetainedWindowOpaqueRegion.Add(aFrame, aBounds);
+ return;
+ }
+ mWindowOpaqueRegion.Or(mWindowOpaqueRegion, aBounds);
+ }
+ /**
+ * Returns the window opaque region built so far. This may be incomplete
+ * since the opaque region is built during layer construction.
+ */
+ const nsRegion GetWindowOpaqueRegion() {
+ return IsRetainingDisplayList() ? mRetainedWindowOpaqueRegion.ToRegion()
+ : mWindowOpaqueRegion;
+ }
+
+ void SetGlassDisplayItem(nsDisplayItem* aItem);
+ void ClearGlassDisplayItem() { mGlassDisplayItem = nullptr; }
+ nsDisplayItem* GetGlassDisplayItem() { return mGlassDisplayItem; }
+
+ bool NeedToForceTransparentSurfaceForItem(nsDisplayItem* aItem);
+
+ void SetContainsPluginItem() { mContainsPluginItem = true; }
+ bool ContainsPluginItem() { return mContainsPluginItem; }
+
+ /**
+ * mContainsBlendMode is true if we processed a display item that
+ * has a blend mode attached. We do this so we can insert a
+ * nsDisplayBlendContainer in the parent stacking context.
+ */
+ void SetContainsBlendMode(bool aContainsBlendMode) {
+ mContainsBlendMode = aContainsBlendMode;
+ }
+ bool ContainsBlendMode() const { return mContainsBlendMode; }
+
+ /**
+ * mContainsBackdropFilter is true if we proccessed a display item that
+ * has a backdrop filter set. We track this so we can insert a
+ * nsDisplayBackdropRootContainer in the stacking context of the nearest
+ * ancestor that forms a backdrop root.
+ */
+ void SetContainsBackdropFilter(bool aContainsBackdropFilter) {
+ mContainsBackdropFilter = aContainsBackdropFilter;
+ }
+ bool ContainsBackdropFilter() const { return mContainsBackdropFilter; }
+
+ DisplayListClipState& ClipState() { return mClipState; }
+ const ActiveScrolledRoot* CurrentActiveScrolledRoot() {
+ return mCurrentActiveScrolledRoot;
+ }
+ const ActiveScrolledRoot* CurrentAncestorASRStackingContextContents() {
+ return mCurrentContainerASR;
+ }
+
+ /**
+ * Add the current frame to the will-change budget if possible and
+ * remeber the outcome. Subsequent calls to IsInWillChangeBudget
+ * will return the same value as return here.
+ */
+ bool AddToWillChangeBudget(nsIFrame* aFrame, const nsSize& aSize);
+
+ /**
+ * This will add the current frame to the will-change budget the first
+ * time it is seen. On subsequent calls this will return the same
+ * answer. This effectively implements a first-come, first-served
+ * allocation of the will-change budget.
+ */
+ bool IsInWillChangeBudget(nsIFrame* aFrame, const nsSize& aSize);
+
+ /**
+ * Clears the will-change budget status for the given |aFrame|.
+ * This will also remove the frame from will-change budgets.
+ */
+ void ClearWillChangeBudgetStatus(nsIFrame* aFrame);
+
+ /**
+ * Removes the given |aFrame| from will-change budgets.
+ */
+ void RemoveFromWillChangeBudgets(const nsIFrame* aFrame);
+
+ /**
+ * Clears the will-change budgets.
+ */
+ void ClearWillChangeBudgets();
+
+ void EnterSVGEffectsContents(nsIFrame* aEffectsFrame,
+ nsDisplayList* aHoistedItemsStorage);
+ void ExitSVGEffectsContents();
+
+ bool ShouldBuildScrollInfoItemsForHoisting() const;
+
+ void AppendNewScrollInfoItemForHoisting(
+ nsDisplayScrollInfoLayer* aScrollInfoItem);
+
+ /**
+ * A helper class to install/restore nsDisplayListBuilder::mPreserves3DCtx.
+ *
+ * mPreserves3DCtx is used by class AutoAccumulateTransform &
+ * AutoAccumulateRect to passing data between frames in the 3D
+ * context. If a frame create a new 3D context, it should restore
+ * the value of mPreserves3DCtx before returning back to the parent.
+ * This class do it for the users.
+ */
+ class AutoPreserves3DContext {
+ public:
+ explicit AutoPreserves3DContext(nsDisplayListBuilder* aBuilder)
+ : mBuilder(aBuilder), mSavedCtx(aBuilder->mPreserves3DCtx) {}
+
+ ~AutoPreserves3DContext() { mBuilder->mPreserves3DCtx = mSavedCtx; }
+
+ private:
+ nsDisplayListBuilder* mBuilder;
+ Preserves3DContext mSavedCtx;
+ };
+
+ const nsRect GetPreserves3DRect() const {
+ return mPreserves3DCtx.mVisibleRect;
+ }
+
+ void SavePreserves3DRect() { mPreserves3DCtx.mVisibleRect = mVisibleRect; }
+
+ void SavePreserves3DAllowAsyncAnimation(bool aValue) {
+ mPreserves3DCtx.mAllowAsyncAnimation = aValue;
+ }
+
+ bool GetPreserves3DAllowAsyncAnimation() const {
+ return mPreserves3DCtx.mAllowAsyncAnimation;
+ }
+
+ bool IsBuildingInvisibleItems() const { return mBuildingInvisibleItems; }
+
+ void SetBuildingInvisibleItems(bool aBuildingInvisibleItems) {
+ mBuildingInvisibleItems = aBuildingInvisibleItems;
+ }
+
+ void SetBuildingExtraPagesForPageNum(uint8_t aPageNum) {
+ mBuildingExtraPagesForPageNum = aPageNum;
+ }
+ uint8_t GetBuildingExtraPagesForPageNum() const {
+ return mBuildingExtraPagesForPageNum;
+ }
+
+ /**
+ * This is a convenience function to ease the transition until AGRs and ASRs
+ * are unified.
+ */
+ AnimatedGeometryRoot* AnimatedGeometryRootForASR(
+ const ActiveScrolledRoot* aASR);
+
+ bool HitTestIsForVisibility() const { return mVisibleThreshold.isSome(); }
+
+ float VisibilityThreshold() const {
+ MOZ_DIAGNOSTIC_ASSERT(HitTestIsForVisibility());
+ return mVisibleThreshold.valueOr(1.0f);
+ }
+
+ void SetHitTestIsForVisibility(float aVisibleThreshold) {
+ mVisibleThreshold = mozilla::Some(aVisibleThreshold);
+ }
+
+ bool ShouldBuildAsyncZoomContainer() const {
+ return mBuildAsyncZoomContainer;
+ }
+ void UpdateShouldBuildAsyncZoomContainer();
+
+ void UpdateShouldBuildBackdropRootContainer();
+
+ bool ShouldRebuildDisplayListDueToPrefChange();
+
+ /**
+ * Represents a region composed of frame/rect pairs.
+ * WeakFrames are used to track whether a rect still belongs to the region.
+ * Modified frames and rects are removed and re-added to the region if needed.
+ */
+ struct WeakFrameRegion {
+ /**
+ * A wrapper to store WeakFrame and the pointer to the underlying frame.
+ * This is needed because WeakFrame does not store the frame pointer after
+ * the frame has been deleted.
+ */
+ struct WeakFrameWrapper {
+ explicit WeakFrameWrapper(nsIFrame* aFrame)
+ : mWeakFrame(new WeakFrame(aFrame)), mFrame(aFrame) {}
+
+ mozilla::UniquePtr<WeakFrame> mWeakFrame;
+ void* mFrame;
+ };
+
+ nsTHashtable<nsPtrHashKey<void>> mFrameSet;
+ nsTArray<WeakFrameWrapper> mFrames;
+ nsTArray<pixman_box32_t> mRects;
+
+ template <typename RectType>
+ void Add(nsIFrame* aFrame, const RectType& aRect) {
+ if (mFrameSet.Contains(aFrame)) {
+ return;
+ }
+
+ mFrameSet.PutEntry(aFrame);
+ mFrames.AppendElement(WeakFrameWrapper(aFrame));
+ mRects.AppendElement(nsRegion::RectToBox(aRect));
+ }
+
+ void Clear() {
+ mFrameSet.Clear();
+ mFrames.Clear();
+ mRects.Clear();
+ }
+
+ void RemoveModifiedFramesAndRects();
+
+ size_t SizeOfExcludingThis(mozilla::MallocSizeOf) const;
+
+ typedef mozilla::gfx::ArrayView<pixman_box32_t> BoxArrayView;
+
+ nsRegion ToRegion() const { return nsRegion(BoxArrayView(mRects)); }
+
+ LayoutDeviceIntRegion ToLayoutDeviceIntRegion() const {
+ return LayoutDeviceIntRegion(BoxArrayView(mRects));
+ }
+ };
+
+ void AddScrollFrameToNotify(nsIScrollableFrame* aScrollFrame);
+ void NotifyAndClearScrollFrames();
+
+ private:
+ bool MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame,
+ const nsRect& aVisibleRect,
+ const nsRect& aDirtyRect);
+
+ /**
+ * Returns whether a frame acts as an animated geometry root, optionally
+ * returning the next ancestor to check.
+ */
+ AGRState IsAnimatedGeometryRoot(nsIFrame* aFrame, bool& aIsAsync,
+ nsIFrame** aParent = nullptr);
+
+ /**
+ * Returns the nearest ancestor frame to aFrame that is considered to have
+ * (or will have) animated geometry. This can return aFrame.
+ */
+ nsIFrame* FindAnimatedGeometryRootFrameFor(nsIFrame* aFrame, bool& aIsAsync);
+
+ friend class nsDisplayCanvasBackgroundImage;
+ friend class nsDisplayBackgroundImage;
+ friend class nsDisplayFixedPosition;
+ friend class nsDisplayPerspective;
+ AnimatedGeometryRoot* FindAnimatedGeometryRootFor(nsDisplayItem* aItem);
+
+ friend class nsDisplayItem;
+ friend class nsDisplayOwnLayer;
+ friend struct RetainedDisplayListBuilder;
+ friend struct HitTestInfo;
+ AnimatedGeometryRoot* FindAnimatedGeometryRootFor(nsIFrame* aFrame);
+
+ AnimatedGeometryRoot* WrapAGRForFrame(
+ nsIFrame* aAnimatedGeometryRoot, bool aIsAsync,
+ AnimatedGeometryRoot* aParent = nullptr);
+
+ nsDataHashtable<nsPtrHashKey<nsIFrame>, RefPtr<AnimatedGeometryRoot>>
+ mFrameToAnimatedGeometryRootMap;
+
+ /**
+ * Add the current frame to the AGR budget if possible and remember
+ * the outcome. Subsequent calls will return the same value as
+ * returned here.
+ */
+ bool AddToAGRBudget(nsIFrame* aFrame);
+
+ struct PresShellState {
+ mozilla::PresShell* mPresShell;
+#ifdef DEBUG
+ mozilla::Maybe<nsAutoLayoutPhase> mAutoLayoutPhase;
+#endif
+ mozilla::Maybe<OutOfFlowDisplayData> mFixedBackgroundDisplayData;
+ uint32_t mFirstFrameMarkedForDisplay;
+ uint32_t mFirstFrameWithOOFData;
+ bool mIsBackgroundOnly;
+ // This is a per-document flag turning off event handling for all content
+ // in the document, and is set when we enter a subdocument for a pointer-
+ // events:none frame.
+ bool mInsidePointerEventsNoneDoc;
+ bool mTouchEventPrefEnabledDoc;
+ nsIFrame* mPresShellIgnoreScrollFrame;
+ };
+
+ PresShellState* CurrentPresShellState() {
+ NS_ASSERTION(mPresShellStates.Length() > 0,
+ "Someone forgot to enter a presshell");
+ return &mPresShellStates[mPresShellStates.Length() - 1];
+ }
+
+ void AddSizeOfExcludingThis(nsWindowSizes&) const;
+
+ struct FrameWillChangeBudget {
+ FrameWillChangeBudget() : mPresContext(nullptr), mUsage(0) {}
+
+ FrameWillChangeBudget(const nsPresContext* aPresContext, uint32_t aUsage)
+ : mPresContext(aPresContext), mUsage(aUsage) {}
+
+ const nsPresContext* mPresContext;
+ uint32_t mUsage;
+ };
+
+ nsIFrame* const mReferenceFrame;
+ nsIFrame* mIgnoreScrollFrame;
+
+ using Arena = nsPresArena<32768, mozilla::DisplayListArenaObjectId,
+ size_t(mozilla::DisplayListArenaObjectId::COUNT)>;
+ Arena mPool;
+
+ AutoTArray<PresShellState, 8> mPresShellStates;
+ AutoTArray<nsIFrame*, 400> mFramesMarkedForDisplay;
+ AutoTArray<nsIFrame*, 40> mFramesMarkedForDisplayIfVisible;
+ AutoTArray<nsIFrame*, 20> mFramesWithOOFData;
+ nsClassHashtable<nsPtrHashKey<nsDisplayItem>, nsTArray<ThemeGeometry>>
+ mThemeGeometries;
+ DisplayListClipState mClipState;
+ const ActiveScrolledRoot* mCurrentActiveScrolledRoot;
+ const ActiveScrolledRoot* mCurrentContainerASR;
+ // mCurrentFrame is the frame that we're currently calling (or about to call)
+ // BuildDisplayList on.
+ const nsIFrame* mCurrentFrame;
+ // The reference frame for mCurrentFrame.
+ const nsIFrame* mCurrentReferenceFrame;
+ // The offset from mCurrentFrame to mCurrentReferenceFrame.
+ nsPoint mCurrentOffsetToReferenceFrame;
+
+ const nsIFrame* mAdditionalOffsetFrame;
+ mozilla::Maybe<nsPoint> mAdditionalOffset;
+
+ RefPtr<AnimatedGeometryRoot> mRootAGR;
+ RefPtr<AnimatedGeometryRoot> mCurrentAGR;
+
+ // will-change budget tracker
+ typedef uint32_t DocumentWillChangeBudget;
+ nsDataHashtable<nsPtrHashKey<const nsPresContext>, DocumentWillChangeBudget>
+ mDocumentWillChangeBudgets;
+
+ // Any frame listed in this set is already counted in the budget
+ // and thus is in-budget.
+ nsDataHashtable<nsPtrHashKey<const nsIFrame>, FrameWillChangeBudget>
+ mFrameWillChangeBudgets;
+
+ uint8_t mBuildingExtraPagesForPageNum;
+
+ // Area of animated geometry root budget already allocated
+ uint32_t mUsedAGRBudget;
+ // Set of frames already counted in budget
+ nsTHashtable<nsPtrHashKey<nsIFrame>> mAGRBudgetSet;
+
+ nsDataHashtable<nsPtrHashKey<RemoteBrowser>, EffectsInfo> mEffectsUpdates;
+
+ // Relative to mCurrentFrame.
+ nsRect mVisibleRect;
+ nsRect mDirtyRect;
+
+ // Tracked regions used for retained display list.
+ WeakFrameRegion mWindowExcludeGlassRegion;
+ WeakFrameRegion mRetainedWindowDraggingRegion;
+ WeakFrameRegion mRetainedWindowNoDraggingRegion;
+
+ // Window opaque region is calculated during layer building.
+ WeakFrameRegion mRetainedWindowOpaqueRegion;
+
+ // Optimized versions for non-retained display list.
+ LayoutDeviceIntRegion mWindowDraggingRegion;
+ LayoutDeviceIntRegion mWindowNoDraggingRegion;
+ nsRegion mWindowOpaqueRegion;
+
+ // The display item for the Windows window glass background, if any
+ // Set during full display list builds or during display list merging only,
+ // partial display list builds don't touch this.
+ nsDisplayItem* mGlassDisplayItem;
+ // If we've encountered a glass item yet, only used during partial display
+ // list builds.
+ bool mHasGlassItemDuringPartial;
+
+ nsIFrame* mCaretFrame;
+ nsRect mCaretRect;
+
+ // A temporary list that we append scroll info items to while building
+ // display items for the contents of frames with SVG effects.
+ // Only non-null when ShouldBuildScrollInfoItemsForHoisting() is true.
+ // This is a pointer and not a real nsDisplayList value because the
+ // nsDisplayList class is defined below this class, so we can't use it here.
+ nsDisplayList* mScrollInfoItemsForHoisting;
+ nsTArray<RefPtr<ActiveScrolledRoot>> mActiveScrolledRoots;
+ std::unordered_set<const DisplayItemClipChain*, DisplayItemClipChainHasher,
+ DisplayItemClipChainEqualer>
+ mClipDeduplicator;
+ DisplayItemClipChain* mFirstClipChainToDestroy;
+ nsTArray<nsDisplayItem*> mTemporaryItems;
+ nsDisplayListBuilderMode mMode;
+ nsDisplayTableBackgroundSet* mTableBackgroundSet;
+ ViewID mCurrentScrollParentId;
+ ViewID mCurrentScrollbarTarget;
+ MaybeScrollDirection mCurrentScrollbarDirection;
+ Preserves3DContext mPreserves3DCtx;
+ nsTArray<nsIFrame*> mSVGEffectsFrames;
+ // When we are inside a filter, the current ASR at the time we entered the
+ // filter. Otherwise nullptr.
+ const ActiveScrolledRoot* mFilterASR;
+ std::unordered_set<nsIScrollableFrame*> mScrollFramesToNotify;
+ bool mContainsBlendMode;
+ bool mIsBuildingScrollbar;
+ bool mCurrentScrollbarWillHaveLayer;
+ bool mBuildCaret;
+ bool mRetainingDisplayList;
+ bool mPartialUpdate;
+ bool mIgnoreSuppression;
+ bool mIncludeAllOutOfFlows;
+ bool mDescendIntoSubdocuments;
+ bool mSelectedFramesOnly;
+ bool mAllowMergingAndFlattening;
+ bool mWillComputePluginGeometry;
+ // True when we're building a display list that's directly or indirectly
+ // under an nsDisplayTransform
+ bool mInTransform;
+ bool mInEventsAndPluginsOnly;
+ bool mInFilter;
+ bool mInPageSequence;
+ bool mIsInChromePresContext;
+ bool mSyncDecodeImages;
+ bool mIsPaintingToWindow;
+ bool mUseHighQualityScaling;
+ bool mIsPaintingForWebRender;
+ bool mIsCompositingCheap;
+ bool mContainsPluginItem;
+ bool mAncestorHasApzAwareEventHandler;
+ // True when the first async-scrollable scroll frame for which we build a
+ // display list has a display port. An async-scrollable scroll frame is one
+ // which WantsAsyncScroll().
+ bool mHaveScrollableDisplayPort;
+ bool mWindowDraggingAllowed;
+ bool mIsBuildingForPopup;
+ bool mForceLayerForScrollParent;
+ bool mAsyncPanZoomEnabled;
+ bool mBuildingInvisibleItems;
+ bool mIsBuilding;
+ bool mInInvalidSubtree;
+ bool mBuildCompositorHitTestInfo;
+ bool mDisablePartialUpdates;
+ bool mPartialBuildFailed;
+ bool mIsInActiveDocShell;
+ bool mBuildAsyncZoomContainer;
+ bool mContainsBackdropFilter;
+ bool mIsRelativeToLayoutViewport;
+ bool mUseOverlayScrollbars;
+
+ mozilla::Maybe<float> mVisibleThreshold;
+ nsRect mHitTestArea;
+ CompositorHitTestInfo mHitTestInfo;
+};
+
+class nsDisplayItem;
+class nsDisplayItemBase;
+class nsPaintedDisplayItem;
+class nsDisplayList;
+class RetainedDisplayList;
+
+// All types are defined in nsDisplayItemTypes.h
+#define NS_DISPLAY_DECL_NAME(n, e) \
+ const char* Name() const override { return n; } \
+ constexpr static DisplayItemType ItemType() { return DisplayItemType::e; } \
+ \
+ private: \
+ void* operator new(size_t aSize, nsDisplayListBuilder* aBuilder) { \
+ return aBuilder->Allocate(aSize, DisplayItemType::e); \
+ } \
+ \
+ template <typename T, typename F, typename... Args> \
+ friend T* ::MakeDisplayItemWithIndex(nsDisplayListBuilder* aBuilder, \
+ F* aFrame, const uint16_t aIndex, \
+ Args&&... aArgs); \
+ \
+ public:
+
+#define NS_DISPLAY_ALLOW_CLONING() \
+ template <typename T> \
+ friend T* MakeClone(nsDisplayListBuilder* aBuilder, const T* aItem); \
+ \
+ nsDisplayWrapList* Clone(nsDisplayListBuilder* aBuilder) const override { \
+ return MakeClone(aBuilder, this); \
+ }
+
+template <typename T>
+MOZ_ALWAYS_INLINE T* MakeClone(nsDisplayListBuilder* aBuilder, const T* aItem) {
+ static_assert(std::is_base_of<nsDisplayWrapList, T>::value,
+ "Display item type should be derived from nsDisplayWrapList");
+ T* item = new (aBuilder) T(aBuilder, *aItem);
+ item->SetType(T::ItemType());
+ return item;
+}
+
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+void AssertUniqueItem(nsDisplayItem* aItem);
+#endif
+
+/**
+ * Returns true, if a display item of given |aType| needs to be built within
+ * opacity:0 container.
+ */
+bool ShouldBuildItemForEventsOrPlugins(const DisplayItemType aType);
+
+void UpdateDisplayItemData(nsPaintedDisplayItem* aItem);
+
+template <typename T, typename F, typename... Args>
+MOZ_ALWAYS_INLINE T* MakeDisplayItemWithIndex(nsDisplayListBuilder* aBuilder,
+ F* aFrame, const uint16_t aIndex,
+ Args&&... aArgs) {
+ static_assert(std::is_base_of<nsDisplayItem, T>::value,
+ "Display item type should be derived from nsDisplayItem");
+ static_assert(std::is_base_of<nsIFrame, F>::value,
+ "Frame type should be derived from nsIFrame");
+
+ const DisplayItemType type = T::ItemType();
+ if (aBuilder->InEventsAndPluginsOnly() &&
+ !ShouldBuildItemForEventsOrPlugins(type)) {
+ // This item is not needed for events or plugins.
+ return nullptr;
+ }
+
+ T* item = new (aBuilder) T(aBuilder, aFrame, std::forward<Args>(aArgs)...);
+
+ if (type != DisplayItemType::TYPE_GENERIC) {
+ item->SetType(type);
+ }
+
+ item->SetPerFrameIndex(aIndex);
+ item->SetExtraPageForPageNum(aBuilder->GetBuildingExtraPagesForPageNum());
+
+ nsPaintedDisplayItem* paintedItem = item->AsPaintedDisplayItem();
+ if (paintedItem) {
+ UpdateDisplayItemData(paintedItem);
+ }
+
+ if (aBuilder->InInvalidSubtree() ||
+ item->FrameForInvalidation()->IsFrameModified()) {
+ item->SetModifiedFrame(true);
+ }
+
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+ if (aBuilder->IsRetainingDisplayList() && aBuilder->IsBuilding()) {
+ AssertUniqueItem(item);
+ }
+
+ // Verify that InInvalidSubtree matches invalidation frame's modified state.
+ if (aBuilder->InInvalidSubtree()) {
+ MOZ_DIAGNOSTIC_ASSERT(
+ AnyContentAncestorModified(item->FrameForInvalidation()));
+ }
+
+ mozilla::DebugOnly<bool> isContainerType =
+ (GetDisplayItemFlagsForType(type) & TYPE_IS_CONTAINER);
+
+ MOZ_ASSERT(item->HasChildren() == isContainerType,
+ "Container items must have container display item flag set.");
+#endif
+
+ return item;
+}
+
+template <typename T, typename F, typename... Args>
+MOZ_ALWAYS_INLINE T* MakeDisplayItem(nsDisplayListBuilder* aBuilder, F* aFrame,
+ Args&&... aArgs) {
+ return MakeDisplayItemWithIndex<T>(aBuilder, aFrame, 0,
+ std::forward<Args>(aArgs)...);
+}
+
+/**
+ * nsDisplayItems are put in singly-linked lists rooted in an nsDisplayList.
+ * nsDisplayItemLink holds the link. The lists are linked from lowest to
+ * highest in z-order.
+ */
+class nsDisplayItemLink {
+ // This is never instantiated directly, so no need to count constructors and
+ // destructors.
+ protected:
+ nsDisplayItemLink() : mAbove(nullptr) {}
+ nsDisplayItemLink(const nsDisplayItemLink&) : mAbove(nullptr) {}
+ ~nsDisplayItemLink() { MOZ_RELEASE_ASSERT(!mAbove); }
+ nsDisplayItem* mAbove;
+
+ friend class nsDisplayList;
+};
+
+class nsPaintedDisplayItem;
+
+/*
+ * nsDisplayItemBase is a base-class for all display items. It is mainly
+ * responsible for handling the frame-display item 1:n relationship, as well as
+ * storing the state needed for display list merging.
+ *
+ * Display items are arena-allocated during display list construction.
+ *
+ * Display items can be containers --- i.e., they can perform hit testing
+ * and painting by recursively traversing a list of child items.
+ *
+ * Display items belong to a list at all times (except temporarily as they
+ * move from one list to another).
+ */
+class nsDisplayItemBase : public nsDisplayItemLink {
+ public:
+ nsDisplayItemBase() = delete;
+
+ /**
+ * Downcasts this item to nsPaintedDisplayItem, if possible.
+ */
+ virtual nsPaintedDisplayItem* AsPaintedDisplayItem() { return nullptr; }
+ virtual const nsPaintedDisplayItem* AsPaintedDisplayItem() const {
+ return nullptr;
+ }
+
+ /**
+ * Downcasts this item to nsDisplayWrapList, if possible.
+ */
+ virtual nsDisplayWrapList* AsDisplayWrapList() { return nullptr; }
+ virtual const nsDisplayWrapList* AsDisplayWrapList() const { return nullptr; }
+
+ /**
+ * Create a clone of this item.
+ */
+ virtual nsDisplayItem* Clone(nsDisplayListBuilder* aBuilder) const {
+ return nullptr;
+ }
+
+ /**
+ * Frees the memory allocated for this display item.
+ * The given display list builder must have allocated this display item.
+ */
+ virtual void Destroy(nsDisplayListBuilder* aBuilder) {
+ const DisplayItemType type = GetType();
+ this->~nsDisplayItemBase();
+ aBuilder->Destroy(type, this);
+ }
+
+ /**
+ * Returns the frame that this display item was created for.
+ * Never returns null.
+ */
+ inline nsIFrame* Frame() const {
+ MOZ_ASSERT(mFrame, "Trying to use display item after deletion!");
+ return mFrame;
+ }
+
+ /**
+ * Called when the display item is prepared for deletion. The display item
+ * should not be used after calling this function.
+ */
+ virtual void RemoveFrame(nsIFrame* aFrame) {
+ MOZ_ASSERT(aFrame);
+
+ if (mFrame && aFrame == mFrame) {
+ MOZ_ASSERT(!mFrame->HasDisplayItem(this));
+ mFrame = nullptr;
+ SetDeletedFrame();
+ }
+ }
+
+ /**
+ * A display item can depend on multiple different frames for invalidation.
+ */
+ virtual nsIFrame* GetDependentFrame() { return nullptr; }
+
+ /**
+ * Returns the frame that provides the style data, and should
+ * be checked when deciding if this display item can be reused.
+ */
+ virtual nsIFrame* FrameForInvalidation() const { return Frame(); }
+
+ /**
+ * Returns the printable name of this display item.
+ */
+ virtual const char* Name() const = 0;
+
+ /**
+ * Some consecutive items should be rendered together as a unit, e.g.,
+ * outlines for the same element. For this, we need a way for items to
+ * identify their type. We use the type for other purposes too.
+ */
+ DisplayItemType GetType() const {
+ MOZ_ASSERT(mType != DisplayItemType::TYPE_ZERO,
+ "Display item should have a valid type!");
+ return mType;
+ }
+
+ /**
+ * Pairing this with the Frame() pointer gives a key that
+ * uniquely identifies this display item in the display item tree.
+ */
+ uint32_t GetPerFrameKey() const {
+ // The top 8 bits are the page index
+ // The middle 16 bits of the per frame key uniquely identify the display
+ // item when there are more than one item of the same type for a frame.
+ // The low 8 bits are the display item type.
+ return (static_cast<uint32_t>(mExtraPageForPageNum)
+ << (TYPE_BITS + (sizeof(mPerFrameIndex) * 8))) |
+ (static_cast<uint32_t>(mPerFrameIndex) << TYPE_BITS) |
+ static_cast<uint32_t>(mType);
+ }
+
+ /**
+ * Returns true if this item was reused during display list merging.
+ */
+ bool IsReused() const {
+ return mItemFlags.contains(ItemBaseFlag::ReusedItem);
+ }
+
+ void SetReused(bool aReused) {
+ if (aReused) {
+ mItemFlags += ItemBaseFlag::ReusedItem;
+ } else {
+ mItemFlags -= ItemBaseFlag::ReusedItem;
+ }
+ }
+
+ /**
+ * Returns true if this item can be reused during display list merging.
+ */
+ bool CanBeReused() const {
+ return !mItemFlags.contains(ItemBaseFlag::CantBeReused);
+ }
+
+ void SetCantBeReused() { mItemFlags += ItemBaseFlag::CantBeReused; }
+
+ bool CanBeCached() const {
+ return !mItemFlags.contains(ItemBaseFlag::CantBeCached);
+ }
+
+ void SetCantBeCached() { mItemFlags += ItemBaseFlag::CantBeCached; }
+
+ bool IsOldItem() const { return !!mOldList; }
+
+ /**
+ * Returns true if the frame of this display item is in a modified subtree.
+ */
+ bool HasModifiedFrame() const;
+ void SetModifiedFrame(bool aModified);
+ bool HasDeletedFrame() const;
+
+ /**
+ * Set the nsDisplayList that this item belongs to, and what index it is
+ * within that list.
+ * Temporary state for merging used by RetainedDisplayListBuilder.
+ */
+ void SetOldListIndex(nsDisplayList* aList, OldListIndex aIndex,
+ uint32_t aListKey, uint32_t aNestingDepth) {
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+ mOldListKey = aListKey;
+ mOldNestingDepth = aNestingDepth;
+#endif
+ mOldList = reinterpret_cast<uintptr_t>(aList);
+ mOldListIndex = aIndex;
+ }
+
+ bool GetOldListIndex(nsDisplayList* aList, uint32_t aListKey,
+ OldListIndex* aOutIndex) {
+ if (mOldList != reinterpret_cast<uintptr_t>(aList)) {
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+ MOZ_CRASH_UNSAFE_PRINTF(
+ "Item found was in the wrong list! type %d "
+ "(outer type was %d at depth %d, now is %d)",
+ GetPerFrameKey(), mOldListKey, mOldNestingDepth, aListKey);
+#endif
+ return false;
+ }
+ *aOutIndex = mOldListIndex;
+ return true;
+ }
+
+ /**
+ * Returns the display list containing the children of this display item.
+ * The children may be in a different coordinate system than this item.
+ */
+ virtual RetainedDisplayList* GetChildren() const { return nullptr; }
+ bool HasChildren() const { return GetChildren(); }
+
+ /**
+ * Display items with children may return true here. This causes the
+ * display list iterator to descend into the child display list.
+ */
+ virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) {
+ return false;
+ }
+
+ protected:
+ nsDisplayItemBase(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
+ : mFrame(aFrame), mType(DisplayItemType::TYPE_ZERO) {
+ MOZ_COUNT_CTOR(nsDisplayItemBase);
+ MOZ_ASSERT(mFrame);
+
+ if (aBuilder->IsRetainingDisplayList()) {
+ mFrame->AddDisplayItem(this);
+ }
+ }
+
+ nsDisplayItemBase(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemBase& aOther)
+ : mFrame(aOther.mFrame),
+ mItemFlags(aOther.mItemFlags),
+ mType(aOther.mType),
+ mExtraPageForPageNum(aOther.mExtraPageForPageNum),
+ mPerFrameIndex(aOther.mPerFrameIndex) {
+ MOZ_COUNT_CTOR(nsDisplayItemBase);
+ }
+
+ virtual ~nsDisplayItemBase() {
+ MOZ_COUNT_DTOR(nsDisplayItemBase);
+ if (mFrame) {
+ mFrame->RemoveDisplayItem(this);
+ }
+ }
+
+ void SetType(const DisplayItemType aType) { mType = aType; }
+
+ void SetPerFrameIndex(const uint16_t aIndex) { mPerFrameIndex = aIndex; }
+
+ // Display list building for printing can build duplicate
+ // container display items when they contain a mixture of
+ // OOF and normal content that is spread across multiple
+ // pages. We include the page number for the duplicates
+ // to make our GetPerFrameKey unique.
+ void SetExtraPageForPageNum(const uint8_t aPageNum) {
+ mExtraPageForPageNum = aPageNum;
+ }
+
+ void SetDeletedFrame();
+
+ nsIFrame* mFrame; // 8
+
+ private:
+ enum class ItemBaseFlag : uint8_t {
+ CantBeReused,
+ CantBeCached,
+ DeletedFrame,
+ ModifiedFrame,
+ ReusedItem,
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+ MergedItem,
+ PreProcessedItem,
+#endif
+ };
+
+ mozilla::EnumSet<ItemBaseFlag, uint8_t> mItemFlags; // 1
+ DisplayItemType mType; // 1
+ uint8_t mExtraPageForPageNum = 0; // 1
+ uint16_t mPerFrameIndex; // 2
+ OldListIndex mOldListIndex; // 4
+ uintptr_t mOldList = 0; // 8
+
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+ public:
+ bool IsMergedItem() const {
+ return mItemFlags.contains(ItemBaseFlag::MergedItem);
+ }
+
+ bool IsPreProcessedItem() const {
+ return mItemFlags.contains(ItemBaseFlag::PreProcessedItem);
+ }
+
+ void SetMergedPreProcessed(bool aMerged, bool aPreProcessed) {
+ if (aMerged) {
+ mItemFlags += ItemBaseFlag::MergedItem;
+ } else {
+ mItemFlags -= ItemBaseFlag::MergedItem;
+ }
+
+ if (aPreProcessed) {
+ mItemFlags += ItemBaseFlag::PreProcessedItem;
+ } else {
+ mItemFlags -= ItemBaseFlag::PreProcessedItem;
+ }
+ }
+
+ uint32_t mOldListKey = 0;
+ uint32_t mOldNestingDepth = 0;
+#endif
+};
+
+/**
+ * This is the unit of rendering and event testing. Each instance of this
+ * class represents an entity that can be drawn on the screen, e.g., a
+ * frame's CSS background, or a frame's text string.
+ */
+class nsDisplayItem : public nsDisplayItemBase {
+ public:
+ typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
+ typedef mozilla::DisplayItemClip DisplayItemClip;
+ typedef mozilla::DisplayItemClipChain DisplayItemClipChain;
+ typedef mozilla::ActiveScrolledRoot ActiveScrolledRoot;
+ typedef mozilla::layers::FrameMetrics FrameMetrics;
+ typedef mozilla::layers::ScrollMetadata ScrollMetadata;
+ typedef mozilla::layers::ScrollableLayerGuid::ViewID ViewID;
+ typedef mozilla::layers::Layer Layer;
+ typedef mozilla::layers::LayerManager LayerManager;
+ typedef mozilla::layers::StackingContextHelper StackingContextHelper;
+ typedef mozilla::layers::WebRenderCommand WebRenderCommand;
+ typedef mozilla::layers::WebRenderParentCommand WebRenderParentCommand;
+ typedef mozilla::LayerState LayerState;
+ typedef mozilla::image::imgDrawingParams imgDrawingParams;
+ typedef mozilla::image::ImgDrawResult ImgDrawResult;
+ typedef class mozilla::gfx::DrawTarget DrawTarget;
+ typedef mozilla::gfx::CompositorHitTestInfo CompositorHitTestInfo;
+
+ protected:
+ // This is never instantiated directly (it has pure virtual methods), so no
+ // need to count constructors and destructors.
+ nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
+ nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ const ActiveScrolledRoot* aActiveScrolledRoot);
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayItem)
+
+ /**
+ * The custom copy-constructor is implemented to prevent copying the saved
+ * state of the item.
+ * This is currently only used when creating temporary items for merging.
+ */
+ nsDisplayItem(nsDisplayListBuilder* aBuilder, const nsDisplayItem& aOther)
+ : nsDisplayItemBase(aBuilder, aOther),
+ mClipChain(aOther.mClipChain),
+ mClip(aOther.mClip),
+ mActiveScrolledRoot(aOther.mActiveScrolledRoot),
+ mReferenceFrame(aOther.mReferenceFrame),
+ mAnimatedGeometryRoot(aOther.mAnimatedGeometryRoot),
+ mToReferenceFrame(aOther.mToReferenceFrame),
+ mBuildingRect(aOther.mBuildingRect),
+ mPaintRect(aOther.mPaintRect) {
+ MOZ_COUNT_CTOR(nsDisplayItem);
+ // TODO: It might be better to remove the flags that aren't copied.
+ if (aOther.ForceNotVisible()) {
+ mItemFlags += ItemFlag::ForceNotVisible;
+ }
+ if (aOther.IsSubpixelAADisabled()) {
+ mItemFlags += ItemFlag::DisableSubpixelAA;
+ }
+ if (mFrame->In3DContextAndBackfaceIsHidden()) {
+ mItemFlags += ItemFlag::BackfaceHidden;
+ }
+ if (aOther.Combines3DTransformWithAncestors()) {
+ mItemFlags += ItemFlag::Combines3DTransformWithAncestors;
+ }
+ }
+
+ public:
+ nsDisplayItem() = delete;
+ nsDisplayItem(const nsDisplayItem&) = delete;
+
+ /**
+ * Roll back side effects carried out by processing the display list.
+ *
+ * @return true if the rollback actually modified anything, to help the caller
+ * decide whether to invalidate cached information about this node.
+ */
+ virtual bool RestoreState() {
+ if (mClipChain == mState.mClipChain && mClip == mState.mClip &&
+ !mItemFlags.contains(ItemFlag::DisableSubpixelAA)) {
+ return false;
+ }
+
+ mClipChain = mState.mClipChain;
+ mClip = mState.mClip;
+ mItemFlags -= ItemFlag::DisableSubpixelAA;
+ return true;
+ }
+
+ /**
+ * Invalidate cached information that depends on this node's contents, after
+ * a mutation of those contents.
+ *
+ * Specifically, if you mutate an |nsDisplayItem| in a way that would change
+ * the WebRender display list items generated for it, you should call this
+ * method.
+ *
+ * If a |RestoreState| method exists to restore some piece of state, that's a
+ * good indication that modifications to said state should be accompanied by a
+ * call to this method. Opacity flattening's effects on
+ * |nsDisplayBackgroundColor| items are one example.
+ */
+ virtual void InvalidateItemCacheEntry() {}
+
+ struct HitTestState {
+ explicit HitTestState() = default;
+
+ ~HitTestState() {
+ NS_ASSERTION(mItemBuffer.Length() == 0,
+ "mItemBuffer should have been cleared");
+ }
+
+ // Handling transform items for preserve 3D frames.
+ bool mInPreserves3D = false;
+ // When hit-testing for visibility, we may hit an fully opaque item in a
+ // nested display list. We want to stop at that point, without looking
+ // further on other items.
+ bool mHitOccludingItem = false;
+
+ float mCurrentOpacity = 1.0f;
+
+ AutoTArray<nsDisplayItem*, 100> mItemBuffer;
+ };
+
+ uint8_t GetFlags() const { return GetDisplayItemFlagsForType(GetType()); }
+
+ virtual bool IsContentful() const { return GetFlags() & TYPE_IS_CONTENTFUL; }
+
+ /**
+ * This is called after we've constructed a display list for event handling.
+ * When this is called, we've already ensured that aRect intersects the
+ * item's bounds and that clipping has been taking into account.
+ *
+ * @param aRect the point or rect being tested, relative to the reference
+ * frame. If the width and height are both 1 app unit, it indicates we're
+ * hit testing a point, not a rect.
+ * @param aState must point to a HitTestState. If you don't have one,
+ * just create one with the default constructor and pass it in.
+ * @param aOutFrames each item appends the frame(s) in this display item that
+ * the rect is considered over (if any) to aOutFrames.
+ */
+ virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) {}
+
+ virtual nsIFrame* StyleFrame() const { return mFrame; }
+
+ /**
+ * Compute the used z-index of our frame; returns zero for elements to which
+ * z-index does not apply, and for z-index:auto.
+ * @note This can be overridden, @see nsDisplayWrapList::SetOverrideZIndex.
+ */
+ virtual int32_t ZIndex() const;
+ /**
+ * The default bounds is the frame border rect.
+ * @param aSnap *aSnap is set to true if the returned rect will be
+ * snapped to nearest device pixel edges during actual drawing.
+ * It might be set to false and snap anyway, so code computing the set of
+ * pixels affected by this display item needs to round outwards to pixel
+ * boundaries when *aSnap is set to false.
+ * This does not take the item's clipping into account.
+ * @return a rectangle relative to aBuilder->ReferenceFrame() that
+ * contains the area drawn by this display item
+ */
+ virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const {
+ *aSnap = false;
+ return nsRect(ToReferenceFrame(), Frame()->GetSize());
+ }
+
+ /**
+ * Returns the untransformed bounds of this display item.
+ */
+ virtual nsRect GetUntransformedBounds(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const {
+ return GetBounds(aBuilder, aSnap);
+ }
+
+ virtual nsRegion GetTightBounds(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const {
+ *aSnap = false;
+ return nsRegion();
+ }
+
+ /**
+ * Returns true if nothing will be rendered inside aRect, false if uncertain.
+ * aRect is assumed to be contained in this item's bounds.
+ */
+ virtual bool IsInvisibleInRect(const nsRect& aRect) const { return false; }
+
+ /**
+ * Returns the result of GetBounds intersected with the item's clip.
+ * The intersection is approximate since rounded corners are not taking into
+ * account.
+ */
+ nsRect GetClippedBounds(nsDisplayListBuilder* aBuilder) const;
+
+ nsRect GetBorderRect() const {
+ return nsRect(ToReferenceFrame(), Frame()->GetSize());
+ }
+
+ nsRect GetPaddingRect() const {
+ return Frame()->GetPaddingRectRelativeToSelf() + ToReferenceFrame();
+ }
+
+ nsRect GetContentRect() const {
+ return Frame()->GetContentRectRelativeToSelf() + ToReferenceFrame();
+ }
+
+ /**
+ * Checks if the frame(s) owning this display item have been marked as
+ * invalid, and needing repainting.
+ */
+ virtual bool IsInvalid(nsRect& aRect) const {
+ bool result = mFrame ? mFrame->IsInvalid(aRect) : false;
+ aRect += ToReferenceFrame();
+ return result;
+ }
+
+ /**
+ * Creates and initializes an nsDisplayItemGeometry object that retains the
+ * current areas covered by this display item. These need to retain enough
+ * information such that they can be compared against a future nsDisplayItem
+ * of the same type, and determine if repainting needs to happen.
+ *
+ * Subclasses wishing to store more information need to override both this
+ * and ComputeInvalidationRegion, as well as implementing an
+ * nsDisplayItemGeometry subclass.
+ *
+ * The default implementation tracks both the display item bounds, and the
+ * frame's border rect.
+ */
+ virtual nsDisplayItemGeometry* AllocateGeometry(
+ nsDisplayListBuilder* aBuilder) {
+ return new nsDisplayItemGenericGeometry(this, aBuilder);
+ }
+
+ /**
+ * Compares an nsDisplayItemGeometry object from a previous paint against the
+ * current item. Computes if the geometry of the item has changed, and the
+ * invalidation area required for correct repainting.
+ *
+ * The existing geometry will have been created from a display item with a
+ * matching GetPerFrameKey()/mFrame pair to the current item.
+ *
+ * The default implementation compares the display item bounds, and the
+ * frame's border rect, and invalidates the entire bounds if either rect
+ * changes.
+ *
+ * @param aGeometry The geometry of the matching display item from the
+ * previous paint.
+ * @param aInvalidRegion Output param, the region to invalidate, or
+ * unchanged if none.
+ */
+ virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const {
+ const nsDisplayItemGenericGeometry* geometry =
+ static_cast<const nsDisplayItemGenericGeometry*>(aGeometry);
+ bool snap;
+ if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
+ !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
+ aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
+ }
+ }
+
+ /**
+ * An alternative default implementation of ComputeInvalidationRegion,
+ * that instead invalidates only the changed area between the two items.
+ */
+ void ComputeInvalidationRegionDifference(
+ nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemBoundsGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const {
+ bool snap;
+ nsRect bounds = GetBounds(aBuilder, &snap);
+
+ if (!aGeometry->mBounds.IsEqualInterior(bounds)) {
+ nscoord radii[8];
+ if (aGeometry->mHasRoundedCorners || Frame()->GetBorderRadii(radii)) {
+ aInvalidRegion->Or(aGeometry->mBounds, bounds);
+ } else {
+ aInvalidRegion->Xor(aGeometry->mBounds, bounds);
+ }
+ }
+ }
+
+ /**
+ * This function is called when an item's list of children has been modified
+ * by RetainedDisplayListBuilder.
+ */
+ virtual void InvalidateCachedChildInfo(nsDisplayListBuilder* aBuilder) {}
+
+ virtual void AddSizeOfExcludingThis(nsWindowSizes&) const {}
+
+ /**
+ * @param aSnap set to true if the edges of the rectangles of the opaque
+ * region would be snapped to device pixels when drawing
+ * @return a region of the item that is opaque --- that is, every pixel
+ * that is visible is painted with an opaque
+ * color. This is useful for determining when one piece
+ * of content completely obscures another so that we can do occlusion
+ * culling.
+ * This does not take clipping into account.
+ * This must return a simple region (1 rect) for painting display lists.
+ * It is only allowed to be a complex region for hit testing.
+ */
+ virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const {
+ *aSnap = false;
+ return nsRegion();
+ }
+ /**
+ * @return Some(nscolor) if the item is guaranteed to paint every pixel in its
+ * bounds with the same (possibly translucent) color
+ */
+ virtual mozilla::Maybe<nscolor> IsUniform(
+ nsDisplayListBuilder* aBuilder) const {
+ return mozilla::Nothing();
+ }
+
+ /**
+ * @return true if the contents of this item are rendered fixed relative
+ * to the nearest viewport.
+ */
+ virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) const {
+ return false;
+ }
+
+ /**
+ * Returns true if all layers that can be active should be forced to be
+ * active. Requires setting the pref layers.force-active=true.
+ */
+ static bool ForceActiveLayers();
+
+ /**
+ * @return LAYER_NONE if BuildLayer will return null. In this case
+ * there is no layer for the item, and Paint should be called instead
+ * to paint the content using Thebes.
+ * Return LAYER_INACTIVE if there is a layer --- BuildLayer will
+ * not return null (unless there's an error) --- but the layer contents
+ * are not changing frequently. In this case it makes sense to composite
+ * the layer into a PaintedLayer with other content, so we don't have to
+ * recomposite it every time we paint.
+ * Note: GetLayerState is only allowed to return LAYER_INACTIVE if all
+ * descendant display items returned LAYER_INACTIVE or LAYER_NONE. Also,
+ * all descendant display item frames must have an active scrolled root
+ * that's either the same as this item's frame's active scrolled root, or
+ * a descendant of this item's frame. This ensures that the entire
+ * set of display items can be collapsed onto a single PaintedLayer.
+ * Return LAYER_ACTIVE if the layer is active, that is, its contents are
+ * changing frequently. In this case it makes sense to keep the layer
+ * as a separate buffer in VRAM and composite it into the destination
+ * every time we paint.
+ *
+ * Users of GetLayerState should check ForceActiveLayers() and if it returns
+ * true, change a returned value of LAYER_INACTIVE to LAYER_ACTIVE.
+ */
+ virtual LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) {
+ return mozilla::LayerState::LAYER_NONE;
+ }
+
+#ifdef MOZ_DUMP_PAINTING
+ /**
+ * Mark this display item as being painted via
+ * FrameLayerBuilder::DrawPaintedLayer.
+ */
+ bool Painted() const { return mItemFlags.contains(ItemFlag::Painted); }
+
+ /**
+ * Check if this display item has been painted.
+ */
+ void SetPainted() { mItemFlags += ItemFlag::Painted; }
+#endif
+
+ void SetIsGlassItem() { mItemFlags += ItemFlag::IsGlassItem; }
+ bool IsGlassItem() { return mItemFlags.contains(ItemFlag::IsGlassItem); }
+
+ /**
+ * Function to create the WebRenderCommands.
+ * We should check if the layer state is
+ * active first and have an early return if the layer state is
+ * not active.
+ *
+ * @return true if successfully creating webrender commands.
+ */
+ virtual bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) {
+ return false;
+ }
+
+ /**
+ * Updates the provided aLayerData with any APZ-relevant scroll data
+ * that is specific to this display item. This is stuff that would normally
+ * be put on the layer during BuildLayer, but this is only called in
+ * layers-free webrender mode, where we don't have layers.
+ *
+ * This function returns true if and only if it has APZ-relevant scroll data
+ * to provide. Note that the arguments passed in may be nullptr, in which case
+ * the function should still return true if and only if it has APZ-relevant
+ * scroll data, but obviously in this case it can't actually put the
+ * data onto aLayerData, because there isn't one.
+ *
+ * This function assumes that aData and aLayerData will either both be null,
+ * or will both be non-null. The caller is responsible for enforcing this.
+ */
+ virtual bool UpdateScrollData(
+ mozilla::layers::WebRenderScrollData* aData,
+ mozilla::layers::WebRenderLayerScrollData* aLayerData) {
+ return false;
+ }
+
+ /**
+ * On entry, aVisibleRegion contains the region (relative to ReferenceFrame())
+ * which may be visible. If the display item opaquely covers an area, it
+ * can remove that area from aVisibleRegion before returning.
+ * nsDisplayList::ComputeVisibility automatically subtracts the region
+ * returned by GetOpaqueRegion, and automatically removes items whose bounds
+ * do not intersect the visible area, so implementations of
+ * nsDisplayItem::ComputeVisibility do not need to do these things.
+ * nsDisplayList::ComputeVisibility will already have set mVisibleRect on
+ * this item to the intersection of *aVisibleRegion and this item's bounds.
+ * We rely on that, so this should only be called by
+ * nsDisplayList::ComputeVisibility or nsDisplayItem::RecomputeVisibility.
+ * aAllowVisibleRegionExpansion is a rect where we are allowed to
+ * expand the visible region and is only used for making sure the
+ * background behind a plugin is visible.
+ * This method needs to be idempotent.
+ *
+ * @return true if the item is visible, false if no part of the item
+ * is visible.
+ */
+ virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion);
+
+ /**
+ * Returns true if this item needs to have its geometry updated, despite
+ * returning empty invalidation region.
+ */
+ virtual bool NeedsGeometryUpdates() const { return false; }
+
+ /**
+ * Some items such as those calling into the native themed widget machinery
+ * have to be painted on the content process. In this case it is best to avoid
+ * allocating layers that serializes and forwards the work to the compositor.
+ */
+ virtual bool MustPaintOnContentSide() const { return false; }
+
+ /**
+ * If this has a child list where the children are in the same coordinate
+ * system as this item (i.e., they have the same reference frame),
+ * return the list.
+ */
+ virtual RetainedDisplayList* GetSameCoordinateSystemChildren() const {
+ return nullptr;
+ }
+
+ virtual void UpdateBounds(nsDisplayListBuilder* aBuilder) {}
+ /**
+ * Do UpdateBounds() for items with frames establishing or extending
+ * 3D rendering context.
+ *
+ * This function is called by UpdateBoundsFor3D() of
+ * nsDisplayTransform(), and it is called by
+ * BuildDisplayListForStackingContext() on transform items
+ * establishing 3D rendering context.
+ *
+ * The bounds of a transform item with the frame establishing 3D
+ * rendering context should be computed by calling
+ * DoUpdateBoundsPreserves3D() on all descendants that participate
+ * the same 3d rendering context.
+ */
+ virtual void DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) {}
+
+ /**
+ * Returns the building rectangle used by nsDisplayListBuilder when
+ * this item was constructed.
+ */
+ const nsRect& GetBuildingRect() const { return mBuildingRect; }
+
+ void SetBuildingRect(const nsRect& aBuildingRect) {
+ if (aBuildingRect == mBuildingRect) {
+ // Avoid unnecessary paint rect recompution when the
+ // building rect is staying the same.
+ return;
+ }
+ mPaintRect = mBuildingRect = aBuildingRect;
+ mItemFlags -= ItemFlag::PaintRectValid;
+ }
+
+ void SetPaintRect(const nsRect& aPaintRect) {
+ mPaintRect = aPaintRect;
+ mItemFlags += ItemFlag::PaintRectValid;
+ }
+ bool HasPaintRect() const {
+ return mItemFlags.contains(ItemFlag::PaintRectValid);
+ }
+
+ /**
+ * Returns the building rect for the children, relative to their
+ * reference frame. Can be different from mBuildingRect for
+ * nsDisplayTransform, since the reference frame for the children is different
+ * from the reference frame for the item itself.
+ */
+ virtual const nsRect& GetBuildingRectForChildren() const {
+ return mBuildingRect;
+ }
+
+ virtual void WriteDebugInfo(std::stringstream& aStream) {}
+
+ nsDisplayItem* GetAbove() { return mAbove; }
+
+ /**
+ * Like ComputeVisibility, but does the work that nsDisplayList
+ * does per-item:
+ * -- Intersects GetBounds with aVisibleRegion and puts the result
+ * in mVisibleRect
+ * -- Subtracts bounds from aVisibleRegion if the item is opaque
+ */
+ bool RecomputeVisibility(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion);
+
+ /**
+ * Returns the result of aBuilder->ToReferenceFrame(GetUnderlyingFrame())
+ */
+ const nsPoint& ToReferenceFrame() const {
+ NS_ASSERTION(mFrame, "No frame?");
+ return mToReferenceFrame;
+ }
+ /**
+ * @return the root of the display list's frame (sub)tree, whose origin
+ * establishes the coordinate system for the display list
+ */
+ const nsIFrame* ReferenceFrame() const { return mReferenceFrame; }
+
+ /**
+ * Returns the reference frame for display item children of this item.
+ */
+ virtual const nsIFrame* ReferenceFrameForChildren() const {
+ return mReferenceFrame;
+ }
+
+ AnimatedGeometryRoot* GetAnimatedGeometryRoot() const {
+ MOZ_ASSERT(mAnimatedGeometryRoot,
+ "Must have cached AGR before accessing it!");
+ return mAnimatedGeometryRoot;
+ }
+
+ virtual struct AnimatedGeometryRoot* AnimatedGeometryRootForScrollMetadata()
+ const {
+ return GetAnimatedGeometryRoot();
+ }
+
+ /**
+ * Checks if this display item (or any children) contains content that might
+ * be rendered with component alpha (e.g. subpixel antialiasing). Returns the
+ * bounds of the area that needs component alpha, or an empty rect if nothing
+ * in the item does.
+ */
+ virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const {
+ return nsRect();
+ }
+
+ /**
+ * Disable usage of component alpha. Currently only relevant for items that
+ * have text.
+ */
+ void DisableComponentAlpha() { mItemFlags += ItemFlag::DisableSubpixelAA; }
+
+ bool IsSubpixelAADisabled() const {
+ return mItemFlags.contains(ItemFlag::DisableSubpixelAA);
+ }
+
+ /**
+ * Check if we can add async animations to the layer for this display item.
+ */
+ virtual bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) {
+ return false;
+ }
+
+ virtual bool SupportsOptimizingToImage() const { return false; }
+
+ const DisplayItemClip& GetClip() const {
+ return mClip ? *mClip : DisplayItemClip::NoClip();
+ }
+ void IntersectClip(nsDisplayListBuilder* aBuilder,
+ const DisplayItemClipChain* aOther, bool aStore);
+
+ virtual void SetActiveScrolledRoot(
+ const ActiveScrolledRoot* aActiveScrolledRoot) {
+ mActiveScrolledRoot = aActiveScrolledRoot;
+ }
+ const ActiveScrolledRoot* GetActiveScrolledRoot() const {
+ return mActiveScrolledRoot;
+ }
+
+ virtual void SetClipChain(const DisplayItemClipChain* aClipChain,
+ bool aStore);
+ const DisplayItemClipChain* GetClipChain() const { return mClipChain; }
+
+ /**
+ * Intersect all clips in our clip chain up to (and including) aASR and set
+ * set the intersection as this item's clip.
+ */
+ void FuseClipChainUpTo(nsDisplayListBuilder* aBuilder,
+ const ActiveScrolledRoot* aASR);
+
+ bool BackfaceIsHidden() const {
+ return mItemFlags.contains(ItemFlag::BackfaceHidden);
+ }
+
+ bool Combines3DTransformWithAncestors() const {
+ return mItemFlags.contains(ItemFlag::Combines3DTransformWithAncestors);
+ }
+
+ bool ForceNotVisible() const {
+ return mItemFlags.contains(ItemFlag::ForceNotVisible);
+ }
+
+ bool In3DContextAndBackfaceIsHidden() const {
+ return mItemFlags.contains(ItemFlag::BackfaceHidden) &&
+ mItemFlags.contains(ItemFlag::Combines3DTransformWithAncestors);
+ }
+
+ bool HasDifferentFrame(const nsDisplayItem* aOther) const {
+ return mFrame != aOther->mFrame;
+ }
+
+ bool HasSameTypeAndClip(const nsDisplayItem* aOther) const {
+ return GetPerFrameKey() == aOther->GetPerFrameKey() &&
+ GetClipChain() == aOther->GetClipChain();
+ }
+
+ bool HasSameContent(const nsDisplayItem* aOther) const {
+ return mFrame->GetContent() == aOther->Frame()->GetContent();
+ }
+
+ virtual void NotifyUsed(nsDisplayListBuilder* aBuilder) {}
+
+ virtual mozilla::Maybe<nsRect> GetClipWithRespectToASR(
+ nsDisplayListBuilder* aBuilder, const ActiveScrolledRoot* aASR) const;
+
+ const nsRect& GetPaintRect() const { return mPaintRect; }
+
+ virtual const nsRect& GetUntransformedPaintRect() const {
+ return GetPaintRect();
+ }
+
+ virtual bool HasHitTestInfo() const { return false; }
+
+#ifdef DEBUG
+ virtual bool IsHitTestItem() const { return false; }
+#endif
+
+ protected:
+ typedef bool (*PrefFunc)(void);
+ bool ShouldUseAdvancedLayer(LayerManager* aManager, PrefFunc aFunc) const;
+ bool CanUseAdvancedLayer(LayerManager* aManager) const;
+
+ RefPtr<const DisplayItemClipChain> mClipChain;
+ const DisplayItemClip* mClip;
+ RefPtr<const ActiveScrolledRoot> mActiveScrolledRoot;
+ // Result of FindReferenceFrameFor(mFrame), if mFrame is non-null
+ const nsIFrame* mReferenceFrame;
+ RefPtr<struct AnimatedGeometryRoot> mAnimatedGeometryRoot;
+
+ struct {
+ RefPtr<const DisplayItemClipChain> mClipChain;
+ const DisplayItemClip* mClip;
+ } mState;
+
+ // Result of ToReferenceFrame(mFrame), if mFrame is non-null
+ nsPoint mToReferenceFrame;
+
+ private:
+ // This is the rectangle that nsDisplayListBuilder was using as the visible
+ // rect to decide which items to construct.
+ nsRect mBuildingRect;
+
+ // nsDisplayList::ComputeVisibility sets this to the visible region
+ // of the item by intersecting the visible region with the bounds
+ // of the item. Paint implementations can use this to limit their drawing.
+ // Guaranteed to be contained in GetBounds().
+ nsRect mPaintRect;
+
+ enum class ItemFlag : uint8_t {
+ BackfaceHidden,
+ Combines3DTransformWithAncestors,
+ DisableSubpixelAA,
+ ForceNotVisible,
+ PaintRectValid,
+ IsGlassItem,
+#ifdef MOZ_DUMP_PAINTING
+ // True if this frame has been painted.
+ Painted,
+#endif
+ };
+
+ mozilla::EnumSet<ItemFlag, uint8_t> mItemFlags;
+};
+
+class nsPaintedDisplayItem : public nsDisplayItem {
+ public:
+ nsPaintedDisplayItem* AsPaintedDisplayItem() final { return this; }
+ const nsPaintedDisplayItem* AsPaintedDisplayItem() const final {
+ return this;
+ }
+
+ ~nsPaintedDisplayItem() override { SetDisplayItemData(nullptr, nullptr); }
+
+ void SetDisplayItemData(mozilla::DisplayItemData* aDID,
+ mozilla::layers::LayerManager* aLayerManager) {
+ if (mDisplayItemData) {
+ MOZ_ASSERT(!mDisplayItemData->GetItem() ||
+ mDisplayItemData->GetItem() == this);
+ mDisplayItemData->SetItem(nullptr);
+ }
+ if (aDID) {
+ if (aDID->GetItem()) {
+ aDID->GetItem()->SetDisplayItemData(nullptr, nullptr);
+ }
+ aDID->SetItem(this);
+ }
+ mDisplayItemData = aDID;
+ mDisplayItemDataLayerManager = aLayerManager;
+ }
+
+ mozilla::DisplayItemData* GetDisplayItemData() { return mDisplayItemData; }
+ mozilla::layers::LayerManager* GetDisplayItemDataLayerManager() {
+ return mDisplayItemDataLayerManager;
+ }
+
+ /**
+ * Stores the given opacity value to be applied when drawing. It is an error
+ * to call this if CanApplyOpacity returned false.
+ */
+ virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder, float aOpacity,
+ const DisplayItemClipChain* aClip) {
+ MOZ_ASSERT(CanApplyOpacity(), "ApplyOpacity is not supported on this type");
+ }
+
+ /**
+ * Get the layer drawn by this display item. Call this only if
+ * GetLayerState() returns something other than LAYER_NONE.
+ * If GetLayerState returned LAYER_NONE then Paint will be called
+ * instead.
+ * This is called while aManager is in the construction phase.
+ *
+ * The caller (nsDisplayList) is responsible for setting the visible
+ * region of the layer.
+ *
+ * @param aContainerParameters should be passed to
+ * FrameLayerBuilder::BuildContainerLayerFor if a ContainerLayer is
+ * constructed.
+ */
+ virtual already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) {
+ return nullptr;
+ }
+
+ /**
+ * Returns true if this display item would return true from ApplyOpacity
+ * without actually applying the opacity. Otherwise returns false.
+ */
+ virtual bool CanApplyOpacity() const { return false; }
+
+ /**
+ * Returns true if this item supports PaintWithClip, where the clipping
+ * is used directly as the primitive geometry instead of needing an explicit
+ * clip.
+ */
+ virtual bool CanPaintWithClip(const DisplayItemClip& aClip) { return false; }
+
+ /**
+ * Same as |Paint()|, except provides a clip to use the geometry to draw with.
+ * Must not be called unless |CanPaintWithClip()| returned true.
+ */
+ virtual void PaintWithClip(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
+ const DisplayItemClip& aClip) {
+ MOZ_ASSERT_UNREACHABLE("PaintWithClip() is not implemented!");
+ }
+
+ /**
+ * Paint this item to some rendering context.
+ */
+ virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
+ // TODO(miko): Make this a pure virtual function to force implementation.
+ MOZ_ASSERT_UNREACHABLE("Paint() is not implemented!");
+ }
+
+ /**
+ * External storage used by |DisplayItemCache| to avoid hashmap lookups.
+ * If an item is reused and has the cache index set, it means that
+ * |DisplayItemCache| has assigned a cache slot for the item.
+ */
+ mozilla::Maybe<uint16_t>& CacheIndex() { return mCacheIndex; }
+
+ void InvalidateItemCacheEntry() override {
+ // |nsPaintedDisplayItem|s may have |DisplayItemCache| entries
+ // that no longer match after a mutation. The cache will notice
+ // on its own that the entry is no longer in use, and free it.
+ mCacheIndex = mozilla::Nothing();
+ }
+
+ protected:
+ nsPaintedDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
+ : nsDisplayItem(aBuilder, aFrame) {}
+
+ nsPaintedDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ const ActiveScrolledRoot* aActiveScrolledRoot)
+ : nsDisplayItem(aBuilder, aFrame, aActiveScrolledRoot) {}
+
+ nsPaintedDisplayItem(nsDisplayListBuilder* aBuilder,
+ const nsPaintedDisplayItem& aOther)
+ : nsDisplayItem(aBuilder, aOther) {}
+
+ private:
+ mozilla::DisplayItemData* mDisplayItemData = nullptr;
+ mozilla::layers::LayerManager* mDisplayItemDataLayerManager = nullptr;
+ mozilla::Maybe<uint16_t> mCacheIndex;
+};
+
+/**
+ * Manages a singly-linked list of display list items.
+ *
+ * mSentinel is the sentinel list value, the first value in the null-terminated
+ * linked list of items. mTop is the last item in the list (whose 'above'
+ * pointer is null). This class has no virtual methods. So list objects are just
+ * two pointers.
+ *
+ * Stepping upward through this list is very fast. Stepping downward is very
+ * slow so we don't support it. The methods that need to step downward
+ * (HitTest(), ComputeVisibility()) internally build a temporary array of all
+ * the items while they do the downward traversal, so overall they're still
+ * linear time. We have optimized for efficient AppendToTop() of both
+ * items and lists, with minimal codesize. AppendToBottom() is efficient too.
+ */
+class nsDisplayList {
+ public:
+ typedef mozilla::ActiveScrolledRoot ActiveScrolledRoot;
+ typedef mozilla::layers::Layer Layer;
+ typedef mozilla::layers::LayerManager LayerManager;
+ typedef mozilla::layers::PaintedLayer PaintedLayer;
+
+ template <typename T>
+ class Iterator {
+ public:
+ Iterator() : mItem(nullptr) {}
+ ~Iterator() = default;
+ Iterator(const Iterator& aOther) = default;
+ Iterator& operator=(const Iterator& aOther) = default;
+
+ explicit Iterator(const nsDisplayList* aList) : mItem(aList->GetBottom()) {}
+ explicit Iterator(const nsDisplayItem* aItem) : mItem(aItem) {}
+
+ Iterator& operator++() {
+ mItem = mItem ? mItem->GetAbove() : mItem;
+ return *this;
+ }
+
+ bool operator==(const Iterator& aOther) const {
+ return mItem == aOther.mItem;
+ }
+
+ bool operator!=(const Iterator& aOther) const {
+ return !operator==(aOther);
+ }
+
+ T* operator*() { return mItem; }
+
+ private:
+ T* mItem;
+ };
+
+ using DisplayItemIterator = Iterator<nsDisplayItem>;
+
+ DisplayItemIterator begin() const { return DisplayItemIterator(this); }
+ DisplayItemIterator end() const { return DisplayItemIterator(); }
+
+ /**
+ * Create an empty list.
+ */
+ nsDisplayList()
+ : mLength(0), mIsOpaque(false), mForceTransparentSurface(false) {
+ mTop = &mSentinel;
+ mSentinel.mAbove = nullptr;
+ }
+
+ virtual ~nsDisplayList() {
+ MOZ_RELEASE_ASSERT(!mSentinel.mAbove, "Nonempty list left over?");
+ }
+
+ nsDisplayList(nsDisplayList&& aOther) {
+ mIsOpaque = aOther.mIsOpaque;
+ mForceTransparentSurface = aOther.mForceTransparentSurface;
+
+ if (aOther.mSentinel.mAbove) {
+ AppendToTop(&aOther);
+ } else {
+ mTop = &mSentinel;
+ mLength = 0;
+ }
+ }
+
+ nsDisplayList& operator=(nsDisplayList&& aOther) {
+ if (this != &aOther) {
+ if (aOther.mSentinel.mAbove) {
+ nsDisplayList tmp;
+ tmp.AppendToTop(&aOther);
+ aOther.AppendToTop(this);
+ AppendToTop(&tmp);
+ } else {
+ mTop = &mSentinel;
+ mLength = 0;
+ }
+ mIsOpaque = aOther.mIsOpaque;
+ mForceTransparentSurface = aOther.mForceTransparentSurface;
+ }
+ return *this;
+ }
+
+ nsDisplayList(const nsDisplayList&) = delete;
+ nsDisplayList& operator=(const nsDisplayList& aOther) = delete;
+
+ /**
+ * Append an item to the top of the list. The item must not currently
+ * be in a list and cannot be null.
+ */
+ void AppendToTop(nsDisplayItem* aItem) {
+ if (!aItem) {
+ return;
+ }
+ MOZ_ASSERT(!aItem->mAbove, "Already in a list!");
+ mTop->mAbove = aItem;
+ mTop = aItem;
+ mLength++;
+ }
+
+ template <typename T, typename F, typename... Args>
+ void AppendNewToTop(nsDisplayListBuilder* aBuilder, F* aFrame,
+ Args&&... aArgs) {
+ AppendNewToTopWithIndex<T>(aBuilder, aFrame, 0,
+ std::forward<Args>(aArgs)...);
+ }
+
+ template <typename T, typename F, typename... Args>
+ void AppendNewToTopWithIndex(nsDisplayListBuilder* aBuilder, F* aFrame,
+ const uint16_t aIndex, Args&&... aArgs) {
+ nsDisplayItem* item = MakeDisplayItemWithIndex<T>(
+ aBuilder, aFrame, aIndex, std::forward<Args>(aArgs)...);
+
+ if (item) {
+ AppendToTop(item);
+ }
+ }
+
+ /**
+ * Append a new item to the bottom of the list. The item must be non-null
+ * and not already in a list.
+ */
+ void AppendToBottom(nsDisplayItem* aItem) {
+ if (!aItem) {
+ return;
+ }
+ MOZ_ASSERT(!aItem->mAbove, "Already in a list!");
+ aItem->mAbove = mSentinel.mAbove;
+ mSentinel.mAbove = aItem;
+ if (mTop == &mSentinel) {
+ mTop = aItem;
+ }
+ mLength++;
+ }
+
+ template <typename T, typename F, typename... Args>
+ void AppendNewToBottom(nsDisplayListBuilder* aBuilder, F* aFrame,
+ Args&&... aArgs) {
+ AppendNewToBottomWithIndex<T>(aBuilder, aFrame, 0,
+ std::forward<Args>(aArgs)...);
+ }
+
+ template <typename T, typename F, typename... Args>
+ void AppendNewToBottomWithIndex(nsDisplayListBuilder* aBuilder, F* aFrame,
+ const uint16_t aIndex, Args&&... aArgs) {
+ nsDisplayItem* item = MakeDisplayItemWithIndex<T>(
+ aBuilder, aFrame, aIndex, std::forward<Args>(aArgs)...);
+
+ if (item) {
+ AppendToBottom(item);
+ }
+ }
+
+ /**
+ * Removes all items from aList and appends them to the top of this list
+ */
+ void AppendToTop(nsDisplayList* aList) {
+ if (aList->mSentinel.mAbove) {
+ mTop->mAbove = aList->mSentinel.mAbove;
+ mTop = aList->mTop;
+ aList->mTop = &aList->mSentinel;
+ aList->mSentinel.mAbove = nullptr;
+ mLength += aList->mLength;
+ aList->mLength = 0;
+ }
+ }
+
+ /**
+ * Removes all items from aList and prepends them to the bottom of this list
+ */
+ void AppendToBottom(nsDisplayList* aList) {
+ if (aList->mSentinel.mAbove) {
+ aList->mTop->mAbove = mSentinel.mAbove;
+ mSentinel.mAbove = aList->mSentinel.mAbove;
+ if (mTop == &mSentinel) {
+ mTop = aList->mTop;
+ }
+
+ aList->mTop = &aList->mSentinel;
+ aList->mSentinel.mAbove = nullptr;
+ mLength += aList->mLength;
+ aList->mLength = 0;
+ }
+ }
+
+ /**
+ * Remove an item from the bottom of the list and return it.
+ */
+ nsDisplayItem* RemoveBottom();
+
+ /**
+ * Remove all items from the list and call their destructors.
+ */
+ virtual void DeleteAll(nsDisplayListBuilder* aBuilder);
+
+ /**
+ * @return the item at the top of the list, or null if the list is empty
+ */
+ nsDisplayItem* GetTop() const {
+ return mTop != &mSentinel ? static_cast<nsDisplayItem*>(mTop) : nullptr;
+ }
+ /**
+ * @return the item at the bottom of the list, or null if the list is empty
+ */
+ nsDisplayItem* GetBottom() const { return mSentinel.mAbove; }
+ bool IsEmpty() const { return mTop == &mSentinel; }
+
+ /**
+ * @return the number of items in the list
+ */
+ uint32_t Count() const { return mLength; }
+ /**
+ * Stable sort the list by the z-order of GetUnderlyingFrame() on
+ * each item. 'auto' is counted as zero.
+ * It is assumed that the list is already in content document order.
+ */
+ void SortByZOrder();
+ /**
+ * Stable sort the list by the tree order of the content of
+ * GetUnderlyingFrame() on each item. z-index is ignored.
+ * @param aCommonAncestor a common ancestor of all the content elements
+ * associated with the display items, for speeding up tree order
+ * checks, or nullptr if not known; it's only a hint, if it is not an
+ * ancestor of some elements, then we lose performance but not correctness
+ */
+ void SortByContentOrder(nsIContent* aCommonAncestor);
+
+ /**
+ * Sort the display list using a stable sort. Take care, because some of the
+ * items might be nsDisplayLists themselves.
+ * aComparator(Item item1, Item item2) should return true if item1 should go
+ * before item2.
+ * We sort the items into increasing order.
+ */
+ template <typename Item, typename Comparator>
+ void Sort(const Comparator& aComparator) {
+ if (Count() < 2) {
+ // Only sort lists with more than one item.
+ return;
+ }
+
+ // Some casual local browsing testing suggests that a local preallocated
+ // array of 20 items should be able to avoid a lot of dynamic allocations
+ // here.
+ AutoTArray<Item, 20> items;
+
+ while (nsDisplayItem* item = RemoveBottom()) {
+ items.AppendElement(Item(item));
+ }
+
+ std::stable_sort(items.begin(), items.end(), aComparator);
+
+ for (Item& item : items) {
+ AppendToTop(item);
+ }
+ }
+
+ /**
+ * Compute visiblity for the items in the list.
+ * We put this logic here so it can be shared by top-level
+ * painting and also display items that maintain child lists.
+ * This is also a good place to put ComputeVisibility-related logic
+ * that must be applied to every display item. In particular, this
+ * sets mVisibleRect on each display item.
+ * This sets mIsOpaque if the entire visible area of this list has
+ * been removed from aVisibleRegion when we return.
+ * This does not remove any items from the list, so we can recompute
+ * visiblity with different regions later (see
+ * FrameLayerBuilder::DrawPaintedLayer).
+ * This method needs to be idempotent.
+ *
+ * @param aVisibleRegion the area that is visible, relative to the
+ * reference frame; on return, this contains the area visible under the list.
+ * I.e., opaque contents of this list are subtracted from aVisibleRegion.
+ * @param aListVisibleBounds must be equal to the bounds of the intersection
+ * of aVisibleRegion and GetBounds() for this list.
+ * @return true if any item in the list is visible.
+ */
+ bool ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion,
+ const nsRect& aListVisibleBounds);
+
+ /**
+ * As ComputeVisibilityForSublist, but computes visibility for a root
+ * list (a list that does not belong to an nsDisplayItem).
+ * This method needs to be idempotent.
+ *
+ * @param aVisibleRegion the area that is visible
+ */
+ bool ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion);
+
+ /**
+ * Returns true if the visible region output from ComputeVisiblity was
+ * empty, i.e. everything visible in this list is opaque.
+ */
+ bool IsOpaque() const { return mIsOpaque; }
+
+ /**
+ * Returns true if any display item requires the surface to be transparent.
+ */
+ bool NeedsTransparentSurface() const { return mForceTransparentSurface; }
+ /**
+ * Paint the list to the rendering context. We assume that (0,0) in aCtx
+ * corresponds to the origin of the reference frame. For best results,
+ * aCtx's current transform should make (0,0) pixel-aligned. The
+ * rectangle in aDirtyRect is painted, which *must* be contained in the
+ * dirty rect used to construct the display list.
+ *
+ * If aFlags contains PAINT_USE_WIDGET_LAYERS and
+ * ShouldUseWidgetLayerManager() is set, then we will paint using
+ * the reference frame's widget's layer manager (and ctx may be null),
+ * otherwise we will use a temporary BasicLayerManager and ctx must
+ * not be null.
+ *
+ * If PAINT_EXISTING_TRANSACTION is set, the reference frame's widget's
+ * layer manager has already had BeginTransaction() called on it and
+ * we should not call it again.
+ *
+ * If PAINT_COMPRESSED is set, the FrameLayerBuilder should be set to
+ * compressed mode to avoid short cut optimizations.
+ *
+ * This must only be called on the root display list of the display list
+ * tree.
+ *
+ * We return the layer manager used for painting --- mainly so that
+ * callers can dump its layer tree if necessary.
+ */
+ enum {
+ PAINT_DEFAULT = 0,
+ PAINT_USE_WIDGET_LAYERS = 0x01,
+ PAINT_EXISTING_TRANSACTION = 0x04,
+ PAINT_NO_COMPOSITE = 0x08,
+ PAINT_COMPRESSED = 0x10,
+ PAINT_IDENTICAL_DISPLAY_LIST = 0x20
+ };
+ already_AddRefed<LayerManager> PaintRoot(nsDisplayListBuilder* aBuilder,
+ gfxContext* aCtx, uint32_t aFlags);
+
+ mozilla::FrameLayerBuilder* BuildLayers(nsDisplayListBuilder* aBuilder,
+ LayerManager* aLayerManager,
+ uint32_t aFlags,
+ bool aIsWidgetTransaction);
+ /**
+ * Get the bounds. Takes the union of the bounds of all children.
+ * The result is not cached.
+ */
+ nsRect GetClippedBounds(nsDisplayListBuilder* aBuilder) const;
+
+ /**
+ * Get this list's bounds, respecting clips relative to aASR. The result is
+ * the union of each item's clipped bounds with respect to aASR. That means
+ * that if an item can move asynchronously with an ASR that is a descendant
+ * of aASR, then the clipped bounds with respect to aASR will be the clip of
+ * that item for aASR, because the item can move anywhere inside that clip.
+ * If there is an item in this list which is not bounded with respect to
+ * aASR (i.e. which does not have "finite bounds" with respect to aASR),
+ * then this method trigger an assertion failure.
+ * The optional aBuildingRect out argument can be set to non-null if the
+ * caller is also interested to know the building rect. This can be used
+ * to get the visible rect efficiently without traversing the display list
+ * twice.
+ */
+ nsRect GetClippedBoundsWithRespectToASR(
+ nsDisplayListBuilder* aBuilder, const ActiveScrolledRoot* aASR,
+ nsRect* aBuildingRect = nullptr) const;
+
+ /**
+ * Returns the opaque region of this display list.
+ */
+ nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder) {
+ nsRegion result;
+ bool snap;
+ for (nsDisplayItem* item : *this) {
+ result.OrWith(item->GetOpaqueRegion(aBuilder, &snap));
+ }
+ return result;
+ }
+
+ /**
+ * Returns the bounds of the area that needs component alpha.
+ */
+ nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const {
+ nsRect bounds;
+ for (nsDisplayItem* item : *this) {
+ bounds.UnionRect(bounds, item->GetComponentAlphaBounds(aBuilder));
+ }
+ return bounds;
+ }
+
+ /**
+ * Find the topmost display item that returns a non-null frame, and return
+ * the frame.
+ */
+ void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ nsDisplayItem::HitTestState* aState,
+ nsTArray<nsIFrame*>* aOutFrames) const;
+ /**
+ * Compute the union of the visible rects of the items in the list. The
+ * result is not cached.
+ */
+ nsRect GetBuildingRect() const;
+
+ void SetIsOpaque() { mIsOpaque = true; }
+
+ void SetNeedsTransparentSurface() { mForceTransparentSurface = true; }
+
+ void RestoreState() {
+ mIsOpaque = false;
+ mForceTransparentSurface = false;
+ }
+
+ private:
+ nsDisplayItemLink mSentinel;
+ nsDisplayItemLink* mTop;
+
+ uint32_t mLength;
+
+ // This is set to true by FrameLayerBuilder if the final visible region
+ // is empty (i.e. everything that was visible is covered by some
+ // opaque content in this list).
+ bool mIsOpaque;
+ // This is set to true by FrameLayerBuilder if any display item in this
+ // list needs to force the surface containing this list to be transparent.
+ bool mForceTransparentSurface;
+};
+
+/**
+ * This is passed as a parameter to nsIFrame::BuildDisplayList. That method
+ * will put any generated items onto the appropriate list given here. It's
+ * basically just a collection with one list for each separate stacking layer.
+ * The lists themselves are external to this object and thus can be shared
+ * with others. Some of the list pointers may even refer to the same list.
+ */
+class nsDisplayListSet {
+ public:
+ /**
+ * @return a list where one should place the border and/or background for
+ * this frame (everything from steps 1 and 2 of CSS 2.1 appendix E)
+ */
+ nsDisplayList* BorderBackground() const { return mBorderBackground; }
+ /**
+ * @return a list where one should place the borders and/or backgrounds for
+ * block-level in-flow descendants (step 4 of CSS 2.1 appendix E)
+ */
+ nsDisplayList* BlockBorderBackgrounds() const {
+ return mBlockBorderBackgrounds;
+ }
+ /**
+ * @return a list where one should place descendant floats (step 5 of
+ * CSS 2.1 appendix E)
+ */
+ nsDisplayList* Floats() const { return mFloats; }
+ /**
+ * @return a list where one should place the (pseudo) stacking contexts
+ * for descendants of this frame (everything from steps 3, 7 and 8
+ * of CSS 2.1 appendix E)
+ */
+ nsDisplayList* PositionedDescendants() const { return mPositioned; }
+ /**
+ * @return a list where one should place the outlines
+ * for this frame and its descendants (step 9 of CSS 2.1 appendix E)
+ */
+ nsDisplayList* Outlines() const { return mOutlines; }
+ /**
+ * @return a list where one should place all other content
+ */
+ nsDisplayList* Content() const { return mContent; }
+
+ void DeleteAll(nsDisplayListBuilder* aBuilder) {
+ BorderBackground()->DeleteAll(aBuilder);
+ BlockBorderBackgrounds()->DeleteAll(aBuilder);
+ Floats()->DeleteAll(aBuilder);
+ PositionedDescendants()->DeleteAll(aBuilder);
+ Outlines()->DeleteAll(aBuilder);
+ Content()->DeleteAll(aBuilder);
+ }
+
+ nsDisplayListSet(nsDisplayList* aBorderBackground,
+ nsDisplayList* aBlockBorderBackgrounds,
+ nsDisplayList* aFloats, nsDisplayList* aContent,
+ nsDisplayList* aPositionedDescendants,
+ nsDisplayList* aOutlines)
+ : mBorderBackground(aBorderBackground),
+ mBlockBorderBackgrounds(aBlockBorderBackgrounds),
+ mFloats(aFloats),
+ mContent(aContent),
+ mPositioned(aPositionedDescendants),
+ mOutlines(aOutlines) {}
+
+ /**
+ * A copy constructor that lets the caller override the BorderBackground
+ * list.
+ */
+ nsDisplayListSet(const nsDisplayListSet& aLists,
+ nsDisplayList* aBorderBackground)
+ : mBorderBackground(aBorderBackground),
+ mBlockBorderBackgrounds(aLists.BlockBorderBackgrounds()),
+ mFloats(aLists.Floats()),
+ mContent(aLists.Content()),
+ mPositioned(aLists.PositionedDescendants()),
+ mOutlines(aLists.Outlines()) {}
+
+ /**
+ * Move all display items in our lists to top of the corresponding lists in
+ * the destination.
+ */
+ void MoveTo(const nsDisplayListSet& aDestination) const;
+
+ private:
+ // This class is only used on stack, so we don't have to worry about leaking
+ // it. Don't let us be heap-allocated!
+ void* operator new(size_t sz) noexcept(true);
+
+ protected:
+ nsDisplayList* mBorderBackground;
+ nsDisplayList* mBlockBorderBackgrounds;
+ nsDisplayList* mFloats;
+ nsDisplayList* mContent;
+ nsDisplayList* mPositioned;
+ nsDisplayList* mOutlines;
+};
+
+/**
+ * A specialization of nsDisplayListSet where the lists are actually internal
+ * to the object, and all distinct.
+ */
+struct nsDisplayListCollection : public nsDisplayListSet {
+ explicit nsDisplayListCollection(nsDisplayListBuilder* aBuilder)
+ : nsDisplayListSet(&mLists[0], &mLists[1], &mLists[2], &mLists[3],
+ &mLists[4], &mLists[5]) {}
+
+ explicit nsDisplayListCollection(nsDisplayListBuilder* aBuilder,
+ nsDisplayList* aBorderBackground)
+ : nsDisplayListSet(aBorderBackground, &mLists[1], &mLists[2], &mLists[3],
+ &mLists[4], &mLists[5]) {}
+
+ /**
+ * Sort all lists by content order.
+ */
+ void SortAllByContentOrder(nsIContent* aCommonAncestor) {
+ for (auto& mList : mLists) {
+ mList.SortByContentOrder(aCommonAncestor);
+ }
+ }
+
+ /**
+ * Serialize this display list collection into a display list with the items
+ * in the correct Z order.
+ * @param aOutList the result display list
+ * @param aContent the content element to use for content ordering
+ */
+ void SerializeWithCorrectZOrder(nsDisplayList* aOutResultList,
+ nsIContent* aContent);
+
+ private:
+ // This class is only used on stack, so we don't have to worry about leaking
+ // it. Don't let us be heap-allocated!
+ void* operator new(size_t sz) noexcept(true);
+
+ nsDisplayList mLists[6];
+};
+
+/**
+ * A display list that also retains the partial build
+ * information (in the form of a DAG) used to create it.
+ *
+ * Display lists built from a partial list aren't necessarily
+ * in the same order as a full build, and the DAG retains
+ * the information needing to interpret the current
+ * order correctly.
+ */
+class RetainedDisplayList : public nsDisplayList {
+ public:
+ RetainedDisplayList() = default;
+ RetainedDisplayList(RetainedDisplayList&& aOther) {
+ AppendToTop(&aOther);
+ mDAG = std::move(aOther.mDAG);
+ }
+
+ ~RetainedDisplayList() override {
+ MOZ_ASSERT(mOldItems.IsEmpty(), "Must empty list before destroying");
+ }
+
+ RetainedDisplayList& operator=(RetainedDisplayList&& aOther) {
+ MOZ_ASSERT(!Count(), "Can only move into an empty list!");
+ MOZ_ASSERT(mOldItems.IsEmpty(), "Can only move into an empty list!");
+ AppendToTop(&aOther);
+ mDAG = std::move(aOther.mDAG);
+ mOldItems = std::move(aOther.mOldItems);
+ return *this;
+ }
+
+ void DeleteAll(nsDisplayListBuilder* aBuilder) override {
+ for (OldItemInfo& i : mOldItems) {
+ if (i.mItem && i.mOwnsItem) {
+ i.mItem->Destroy(aBuilder);
+ MOZ_ASSERT(!GetBottom(),
+ "mOldItems should not be owning items if we also have items "
+ "in the normal list");
+ }
+ }
+ mOldItems.Clear();
+ mDAG.Clear();
+ nsDisplayList::DeleteAll(aBuilder);
+ }
+
+ void AddSizeOfExcludingThis(nsWindowSizes&) const;
+
+ DirectedAcyclicGraph<MergedListUnits> mDAG;
+
+ // Temporary state initialized during the preprocess pass
+ // of RetainedDisplayListBuilder and then used during merging.
+ nsTArray<OldItemInfo> mOldItems;
+};
+
+struct HitTestInfo {
+ HitTestInfo(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ const mozilla::gfx::CompositorHitTestInfo& aHitTestFlags)
+ : mArea(aFrame->GetCompositorHitTestArea(aBuilder)),
+ mFlags(aHitTestFlags),
+ mAGR(aBuilder->FindAnimatedGeometryRootFor(aFrame)),
+ mASR(aBuilder->CurrentActiveScrolledRoot()),
+ mClipChain(aBuilder->ClipState().GetCurrentCombinedClipChain(aBuilder)),
+ mClip(mozilla::DisplayItemClipChain::ClipForASR(mClipChain, mASR)) {}
+
+ HitTestInfo(const nsRect& aArea,
+ const mozilla::gfx::CompositorHitTestInfo& aHitTestFlags)
+ : mArea(aArea),
+ mFlags(aHitTestFlags),
+ mAGR(nullptr),
+ mASR(nullptr),
+ mClipChain(nullptr),
+ mClip(nullptr) {}
+
+ nsRect mArea;
+ mozilla::gfx::CompositorHitTestInfo mFlags;
+
+ RefPtr<AnimatedGeometryRoot> mAGR;
+ RefPtr<const mozilla::ActiveScrolledRoot> mASR;
+ RefPtr<const mozilla::DisplayItemClipChain> mClipChain;
+ const mozilla::DisplayItemClip* mClip;
+};
+
+class nsDisplayHitTestInfoBase : public nsPaintedDisplayItem {
+ public:
+ nsDisplayHitTestInfoBase(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
+ : nsPaintedDisplayItem(aBuilder, aFrame) {}
+
+ nsDisplayHitTestInfoBase(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ const ActiveScrolledRoot* aActiveScrolledRoot)
+ : nsPaintedDisplayItem(aBuilder, aFrame, aActiveScrolledRoot) {}
+
+ nsDisplayHitTestInfoBase(nsDisplayListBuilder* aBuilder,
+ const nsDisplayHitTestInfoBase& aOther)
+ : nsPaintedDisplayItem(aBuilder, aOther) {}
+
+ const HitTestInfo& GetHitTestInfo() const {
+ MOZ_ASSERT(HasHitTestInfo());
+ return *mHitTestInfo;
+ }
+
+ void SetActiveScrolledRoot(
+ const ActiveScrolledRoot* aActiveScrolledRoot) override {
+ nsPaintedDisplayItem::SetActiveScrolledRoot(aActiveScrolledRoot);
+ UpdateHitTestInfoActiveScrolledRoot(aActiveScrolledRoot);
+ }
+
+ /**
+ * Updates mASR and mClip fields using the given |aActiveScrolledRoot|.
+ */
+ void UpdateHitTestInfoActiveScrolledRoot(
+ const ActiveScrolledRoot* aActiveScrolledRoot) {
+ if (HasHitTestInfo()) {
+ mHitTestInfo->mASR = aActiveScrolledRoot;
+ mHitTestInfo->mClip = mozilla::DisplayItemClipChain::ClipForASR(
+ mHitTestInfo->mClipChain, mHitTestInfo->mASR);
+ }
+ }
+
+ void SetHitTestInfo(mozilla::UniquePtr<HitTestInfo>&& aHitTestInfo) {
+ MOZ_ASSERT(aHitTestInfo);
+ MOZ_ASSERT(aHitTestInfo->mFlags !=
+ mozilla::gfx::CompositorHitTestInvisibleToHit);
+
+ mHitTestInfo = std::move(aHitTestInfo);
+ }
+
+ void SetHitTestInfo(
+ const nsRect& aArea,
+ const mozilla::gfx::CompositorHitTestInfo& aHitTestFlags) {
+ MOZ_ASSERT(aHitTestFlags != mozilla::gfx::CompositorHitTestInvisibleToHit);
+
+ mHitTestInfo = mozilla::MakeUnique<HitTestInfo>(aArea, aHitTestFlags);
+ mHitTestInfo->mAGR = mAnimatedGeometryRoot;
+ mHitTestInfo->mASR = mActiveScrolledRoot;
+ mHitTestInfo->mClipChain = mClipChain;
+ mHitTestInfo->mClip = mClip;
+ }
+
+ const nsRect& HitTestArea() const { return mHitTestInfo->mArea; }
+
+ const mozilla::gfx::CompositorHitTestInfo& HitTestFlags() const {
+ return mHitTestInfo->mFlags;
+ }
+
+ bool HasHitTestInfo() const final { return mHitTestInfo.get(); }
+
+ void AddSizeOfExcludingThis(nsWindowSizes&) const override;
+
+#ifdef DEBUG
+ bool IsHitTestItem() const final { return true; }
+#endif
+
+ protected:
+ mozilla::UniquePtr<HitTestInfo> mHitTestInfo;
+};
+
+class nsDisplayContainer final : public nsDisplayItem {
+ public:
+ nsDisplayContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
+ nsDisplayList* aList);
+
+ ~nsDisplayContainer() override { MOZ_COUNT_DTOR(nsDisplayContainer); }
+
+ NS_DISPLAY_DECL_NAME("nsDisplayContainer", TYPE_CONTAINER)
+
+ void Destroy(nsDisplayListBuilder* aBuilder) override {
+ mChildren.DeleteAll(aBuilder);
+ nsDisplayItem::Destroy(aBuilder);
+ }
+
+ bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion) override;
+
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
+
+ nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const override;
+
+ nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const override;
+
+ mozilla::Maybe<nscolor> IsUniform(
+ nsDisplayListBuilder* aBuilder) const override {
+ return mozilla::Nothing();
+ }
+
+ RetainedDisplayList* GetChildren() const override { return &mChildren; }
+ RetainedDisplayList* GetSameCoordinateSystemChildren() const override {
+ return GetChildren();
+ }
+
+ mozilla::Maybe<nsRect> GetClipWithRespectToASR(
+ nsDisplayListBuilder* aBuilder,
+ const ActiveScrolledRoot* aASR) const override;
+
+ void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
+
+ bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
+ return true;
+ }
+
+ void SetClipChain(const DisplayItemClipChain* aClipChain,
+ bool aStore) override {
+ MOZ_ASSERT_UNREACHABLE("nsDisplayContainer does not support clipping");
+ }
+
+ void UpdateBounds(nsDisplayListBuilder* aBuilder) override;
+
+ private:
+ mutable RetainedDisplayList mChildren;
+ nsRect mBounds;
+};
+
+class nsDisplayImageContainer : public nsPaintedDisplayItem {
+ public:
+ typedef mozilla::LayerIntPoint LayerIntPoint;
+ typedef mozilla::LayoutDeviceRect LayoutDeviceRect;
+ typedef mozilla::layers::ImageContainer ImageContainer;
+ typedef mozilla::layers::ImageLayer ImageLayer;
+
+ nsDisplayImageContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
+ : nsPaintedDisplayItem(aBuilder, aFrame) {}
+
+ /**
+ * @return true if this display item can be optimized into an image layer.
+ * It is an error to call GetContainer() unless you've called
+ * CanOptimizeToImageLayer() first and it returned true.
+ */
+ virtual bool CanOptimizeToImageLayer(LayerManager* aManager,
+ nsDisplayListBuilder* aBuilder);
+
+ already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
+ nsDisplayListBuilder* aBuilder);
+ void ConfigureLayer(ImageLayer* aLayer,
+ const ContainerLayerParameters& aParameters);
+
+ virtual void UpdateDrawResult(mozilla::image::ImgDrawResult aResult) = 0;
+ virtual already_AddRefed<imgIContainer> GetImage() = 0;
+ virtual nsRect GetDestRect() const = 0;
+
+ bool SupportsOptimizingToImage() const override { return true; }
+};
+
+/**
+ * Use this class to implement not-very-frequently-used display items
+ * that are not opaque, do not receive events, and are bounded by a frame's
+ * border-rect.
+ *
+ * This should not be used for display items which are created frequently,
+ * because each item is one or two pointers bigger than an item from a
+ * custom display item class could be, and fractionally slower. However it does
+ * save code size. We use this for infrequently-used item types.
+ */
+class nsDisplayGeneric : public nsPaintedDisplayItem {
+ public:
+ typedef void (*PaintCallback)(nsIFrame* aFrame, DrawTarget* aDrawTarget,
+ const nsRect& aDirtyRect, nsPoint aFramePt);
+
+ // XXX: should be removed eventually
+ typedef void (*OldPaintCallback)(nsIFrame* aFrame, gfxContext* aCtx,
+ const nsRect& aDirtyRect, nsPoint aFramePt);
+
+ nsDisplayGeneric(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ PaintCallback aPaint, const char* aName,
+ DisplayItemType aType)
+ : nsPaintedDisplayItem(aBuilder, aFrame),
+ mPaint(aPaint),
+ mOldPaint(nullptr),
+ mName(aName) {
+ MOZ_COUNT_CTOR(nsDisplayGeneric);
+ SetType(aType);
+ }
+
+ // XXX: should be removed eventually
+ nsDisplayGeneric(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ OldPaintCallback aOldPaint, const char* aName,
+ DisplayItemType aType)
+ : nsPaintedDisplayItem(aBuilder, aFrame),
+ mPaint(nullptr),
+ mOldPaint(aOldPaint),
+ mName(aName) {
+ MOZ_COUNT_CTOR(nsDisplayGeneric);
+ SetType(aType);
+ }
+
+ constexpr static DisplayItemType ItemType() {
+ return DisplayItemType::TYPE_GENERIC;
+ }
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayGeneric)
+
+ void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override {
+ MOZ_ASSERT(!!mPaint != !!mOldPaint);
+ if (mPaint) {
+ mPaint(mFrame, aCtx->GetDrawTarget(), GetPaintRect(), ToReferenceFrame());
+ } else {
+ mOldPaint(mFrame, aCtx, GetPaintRect(), ToReferenceFrame());
+ }
+ }
+
+ const char* Name() const override { return mName; }
+
+ // This override is needed because GetType() for nsDisplayGeneric subclasses
+ // does not match TYPE_GENERIC that was used to allocate the object.
+ void Destroy(nsDisplayListBuilder* aBuilder) override {
+ this->~nsDisplayGeneric();
+ aBuilder->Destroy(DisplayItemType::TYPE_GENERIC, this);
+ }
+
+ protected:
+ void* operator new(size_t aSize, nsDisplayListBuilder* aBuilder) {
+ return aBuilder->Allocate(aSize, DisplayItemType::TYPE_GENERIC);
+ }
+
+ template <typename T, typename F, typename... Args>
+ friend T* ::MakeDisplayItemWithIndex(nsDisplayListBuilder* aBuilder,
+ F* aFrame, const uint16_t aIndex,
+ Args&&... aArgs);
+
+ PaintCallback mPaint;
+ OldPaintCallback mOldPaint; // XXX: should be removed eventually
+ const char* mName;
+};
+
+#if defined(MOZ_REFLOW_PERF_DSP) && defined(MOZ_REFLOW_PERF)
+/**
+ * This class implements painting of reflow counts. Ideally, we would simply
+ * make all the frame names be those returned by nsIFrame::GetFrameName
+ * (except that tosses in the content tag name!) and support only one color
+ * and eliminate this class altogether in favor of nsDisplayGeneric, but for
+ * the time being we can't pass args to a PaintCallback, so just have a
+ * separate class to do the right thing. Sadly, this alsmo means we need to
+ * hack all leaf frame classes to handle this.
+ *
+ * XXXbz the color thing is a bit of a mess, but 0 basically means "not set"
+ * here... I could switch it all to nscolor, but why bother?
+ */
+class nsDisplayReflowCount : public nsPaintedDisplayItem {
+ public:
+ nsDisplayReflowCount(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ const char* aFrameName, uint32_t aColor = 0)
+ : nsPaintedDisplayItem(aBuilder, aFrame),
+ mFrameName(aFrameName),
+ mColor(aColor) {
+ MOZ_COUNT_CTOR(nsDisplayReflowCount);
+ }
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayReflowCount)
+
+ NS_DISPLAY_DECL_NAME("nsDisplayReflowCount", TYPE_REFLOW_COUNT)
+
+ void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
+
+ protected:
+ const char* mFrameName;
+ nscolor mColor;
+};
+
+# define DO_GLOBAL_REFLOW_COUNT_DSP(_name) \
+ PR_BEGIN_MACRO \
+ if (!aBuilder->IsBackgroundOnly() && !aBuilder->IsForEventDelivery() && \
+ PresShell()->IsPaintingFrameCounts()) { \
+ aLists.Outlines()->AppendNewToTop<nsDisplayReflowCount>(aBuilder, this, \
+ _name); \
+ } \
+ PR_END_MACRO
+
+# define DO_GLOBAL_REFLOW_COUNT_DSP_COLOR(_name, _color) \
+ PR_BEGIN_MACRO \
+ if (!aBuilder->IsBackgroundOnly() && !aBuilder->IsForEventDelivery() && \
+ PresShell()->IsPaintingFrameCounts()) { \
+ aLists.Outlines()->AppendNewToTop<nsDisplayReflowCount>(aBuilder, this, \
+ _name, _color); \
+ } \
+ PR_END_MACRO
+
+/*
+ Macro to be used for classes that don't actually implement BuildDisplayList
+ */
+# define DECL_DO_GLOBAL_REFLOW_COUNT_DSP(_class, _super) \
+ void BuildDisplayList(nsDisplayListBuilder* aBuilder, \
+ const nsRect& aDirtyRect, \
+ const nsDisplayListSet& aLists) { \
+ DO_GLOBAL_REFLOW_COUNT_DSP(#_class); \
+ _super::BuildDisplayList(aBuilder, aDirtyRect, aLists); \
+ }
+
+#else // MOZ_REFLOW_PERF_DSP && MOZ_REFLOW_PERF
+
+# define DO_GLOBAL_REFLOW_COUNT_DSP(_name)
+# define DO_GLOBAL_REFLOW_COUNT_DSP_COLOR(_name, _color)
+# define DECL_DO_GLOBAL_REFLOW_COUNT_DSP(_class, _super)
+
+#endif // MOZ_REFLOW_PERF_DSP && MOZ_REFLOW_PERF
+
+class nsDisplayCaret : public nsPaintedDisplayItem {
+ public:
+ nsDisplayCaret(nsDisplayListBuilder* aBuilder, nsIFrame* aCaretFrame);
+
+#ifdef NS_BUILD_REFCNT_LOGGING
+ ~nsDisplayCaret() override;
+#endif
+
+ NS_DISPLAY_DECL_NAME("Caret", TYPE_CARET)
+
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
+ void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
+ protected:
+ RefPtr<nsCaret> mCaret;
+ nsRect mBounds;
+};
+
+/**
+ * The standard display item to paint the CSS borders of a frame.
+ */
+class nsDisplayBorder : public nsPaintedDisplayItem {
+ public:
+ nsDisplayBorder(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayBorder)
+
+ NS_DISPLAY_DECL_NAME("Border", TYPE_BORDER)
+
+ bool IsInvisibleInRect(const nsRect& aRect) const override;
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override;
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+ void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
+ nsDisplayItemGeometry* AllocateGeometry(
+ nsDisplayListBuilder* aBuilder) override;
+ void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const override;
+
+ nsRegion GetTightBounds(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const override {
+ *aSnap = true;
+ return CalculateBounds<nsRegion>(*mFrame->StyleBorder());
+ }
+
+ protected:
+ template <typename T>
+ T CalculateBounds(const nsStyleBorder& aStyleBorder) const {
+ nsRect borderBounds(ToReferenceFrame(), mFrame->GetSize());
+ if (aStyleBorder.IsBorderImageSizeAvailable()) {
+ borderBounds.Inflate(aStyleBorder.GetImageOutset());
+ return borderBounds;
+ }
+
+ nsMargin border = aStyleBorder.GetComputedBorder();
+ T result;
+ if (border.top > 0) {
+ result = nsRect(borderBounds.X(), borderBounds.Y(), borderBounds.Width(),
+ border.top);
+ }
+ if (border.right > 0) {
+ result.OrWith(nsRect(borderBounds.XMost() - border.right,
+ borderBounds.Y(), border.right,
+ borderBounds.Height()));
+ }
+ if (border.bottom > 0) {
+ result.OrWith(nsRect(borderBounds.X(),
+ borderBounds.YMost() - border.bottom,
+ borderBounds.Width(), border.bottom));
+ }
+ if (border.left > 0) {
+ result.OrWith(nsRect(borderBounds.X(), borderBounds.Y(), border.left,
+ borderBounds.Height()));
+ }
+
+ nscoord radii[8];
+ if (mFrame->GetBorderRadii(radii)) {
+ if (border.left > 0 || border.top > 0) {
+ nsSize cornerSize(radii[mozilla::eCornerTopLeftX],
+ radii[mozilla::eCornerTopLeftY]);
+ result.OrWith(nsRect(borderBounds.TopLeft(), cornerSize));
+ }
+ if (border.top > 0 || border.right > 0) {
+ nsSize cornerSize(radii[mozilla::eCornerTopRightX],
+ radii[mozilla::eCornerTopRightY]);
+ result.OrWith(
+ nsRect(borderBounds.TopRight() - nsPoint(cornerSize.width, 0),
+ cornerSize));
+ }
+ if (border.right > 0 || border.bottom > 0) {
+ nsSize cornerSize(radii[mozilla::eCornerBottomRightX],
+ radii[mozilla::eCornerBottomRightY]);
+ result.OrWith(nsRect(borderBounds.BottomRight() -
+ nsPoint(cornerSize.width, cornerSize.height),
+ cornerSize));
+ }
+ if (border.bottom > 0 || border.left > 0) {
+ nsSize cornerSize(radii[mozilla::eCornerBottomLeftX],
+ radii[mozilla::eCornerBottomLeftY]);
+ result.OrWith(
+ nsRect(borderBounds.BottomLeft() - nsPoint(0, cornerSize.height),
+ cornerSize));
+ }
+ }
+ return result;
+ }
+
+ nsRect mBounds;
+};
+
+/**
+ * A simple display item that just renders a solid color across the
+ * specified bounds. For canvas frames (in the CSS sense) we split off the
+ * drawing of the background color into this class (from nsDisplayBackground
+ * via nsDisplayCanvasBackground). This is done so that we can always draw a
+ * background color to avoid ugly flashes of white when we can't draw a full
+ * frame tree (ie when a page is loading). The bounds can differ from the
+ * frame's bounds -- this is needed when a frame/iframe is loading and there
+ * is not yet a frame tree to go in the frame/iframe so we use the subdoc
+ * frame of the parent document as a standin.
+ */
+class nsDisplaySolidColorBase : public nsPaintedDisplayItem {
+ public:
+ nsDisplaySolidColorBase(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nscolor aColor)
+ : nsPaintedDisplayItem(aBuilder, aFrame), mColor(aColor) {}
+
+ nsDisplayItemGeometry* AllocateGeometry(
+ nsDisplayListBuilder* aBuilder) override {
+ return new nsDisplaySolidColorGeometry(this, aBuilder, mColor);
+ }
+
+ void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const override {
+ const nsDisplaySolidColorGeometry* geometry =
+ static_cast<const nsDisplaySolidColorGeometry*>(aGeometry);
+ if (mColor != geometry->mColor) {
+ bool dummy;
+ aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &dummy));
+ return;
+ }
+ ComputeInvalidationRegionDifference(aBuilder, geometry, aInvalidRegion);
+ }
+
+ nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const override {
+ *aSnap = false;
+ nsRegion result;
+ if (NS_GET_A(mColor) == 255) {
+ result = GetBounds(aBuilder, aSnap);
+ }
+ return result;
+ }
+
+ mozilla::Maybe<nscolor> IsUniform(
+ nsDisplayListBuilder* aBuilder) const override {
+ return mozilla::Some(mColor);
+ }
+
+ protected:
+ nscolor mColor;
+};
+
+class nsDisplaySolidColor : public nsDisplaySolidColorBase {
+ public:
+ nsDisplaySolidColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ const nsRect& aBounds, nscolor aColor,
+ bool aCanBeReused = true)
+ : nsDisplaySolidColorBase(aBuilder, aFrame, aColor), mBounds(aBounds) {
+ NS_ASSERTION(NS_GET_A(aColor) > 0,
+ "Don't create invisible nsDisplaySolidColors!");
+ MOZ_COUNT_CTOR(nsDisplaySolidColor);
+ if (!aCanBeReused) {
+ SetCantBeReused();
+ }
+ }
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplaySolidColor)
+
+ NS_DISPLAY_DECL_NAME("SolidColor", TYPE_SOLID_COLOR)
+
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override;
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+ void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
+ void WriteDebugInfo(std::stringstream& aStream) override;
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
+ int32_t ZIndex() const override {
+ if (mOverrideZIndex) {
+ return mOverrideZIndex.value();
+ }
+ return nsDisplaySolidColorBase::ZIndex();
+ }
+
+ void SetOverrideZIndex(int32_t aZIndex) {
+ mOverrideZIndex = mozilla::Some(aZIndex);
+ }
+
+ private:
+ nsRect mBounds;
+ mozilla::Maybe<int32_t> mOverrideZIndex;
+};
+
+/**
+ * A display item that renders a solid color over a region. This is not
+ * exposed through CSS, its only purpose is efficient invalidation of
+ * the find bar highlighter dimmer.
+ */
+class nsDisplaySolidColorRegion : public nsPaintedDisplayItem {
+ typedef mozilla::gfx::sRGBColor sRGBColor;
+
+ public:
+ nsDisplaySolidColorRegion(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ const nsRegion& aRegion, nscolor aColor)
+ : nsPaintedDisplayItem(aBuilder, aFrame),
+ mRegion(aRegion),
+ mColor(sRGBColor::FromABGR(aColor)) {
+ NS_ASSERTION(NS_GET_A(aColor) > 0,
+ "Don't create invisible nsDisplaySolidColorRegions!");
+ MOZ_COUNT_CTOR(nsDisplaySolidColorRegion);
+ }
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplaySolidColorRegion)
+
+ NS_DISPLAY_DECL_NAME("SolidColorRegion", TYPE_SOLID_COLOR_REGION)
+
+ nsDisplayItemGeometry* AllocateGeometry(
+ nsDisplayListBuilder* aBuilder) override {
+ return new nsDisplaySolidColorRegionGeometry(this, aBuilder, mRegion,
+ mColor);
+ }
+
+ void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const override {
+ const nsDisplaySolidColorRegionGeometry* geometry =
+ static_cast<const nsDisplaySolidColorRegionGeometry*>(aGeometry);
+ if (mColor == geometry->mColor) {
+ aInvalidRegion->Xor(geometry->mRegion, mRegion);
+ } else {
+ aInvalidRegion->Or(geometry->mRegion.GetBounds(), mRegion.GetBounds());
+ }
+ }
+
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
+ protected:
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
+ void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
+ void WriteDebugInfo(std::stringstream& aStream) override;
+
+ private:
+ nsRegion mRegion;
+ sRGBColor mColor;
+};
+
+/**
+ * A display item to paint one background-image for a frame. Each background
+ * image layer gets its own nsDisplayBackgroundImage.
+ */
+class nsDisplayBackgroundImage : public nsDisplayImageContainer {
+ public:
+ typedef mozilla::StyleGeometryBox StyleGeometryBox;
+
+ struct InitData {
+ nsDisplayListBuilder* builder;
+ mozilla::ComputedStyle* backgroundStyle;
+ nsCOMPtr<imgIContainer> image;
+ nsRect backgroundRect;
+ nsRect fillArea;
+ nsRect destArea;
+ uint32_t layer;
+ bool isRasterImage;
+ bool shouldFixToViewport;
+ };
+
+ /**
+ * aLayer signifies which background layer this item represents.
+ * aIsThemed should be the value of aFrame->IsThemed.
+ * aBackgroundStyle should be the result of
+ * nsCSSRendering::FindBackground, or null if FindBackground returned false.
+ * aBackgroundRect is relative to aFrame.
+ */
+ static InitData GetInitData(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ uint16_t aLayer, const nsRect& aBackgroundRect,
+ mozilla::ComputedStyle* aBackgroundStyle);
+
+ explicit nsDisplayBackgroundImage(nsDisplayListBuilder* aBuilder,
+ nsIFrame* aFrame, const InitData& aInitData,
+ nsIFrame* aFrameForBounds = nullptr);
+ ~nsDisplayBackgroundImage() override;
+
+ NS_DISPLAY_DECL_NAME("Background", TYPE_BACKGROUND)
+
+ // This will create and append new items for all the layers of the
+ // background. Returns whether we appended a themed background.
+ // aAllowWillPaintBorderOptimization should usually be left at true, unless
+ // aFrame has special border drawing that causes opaque borders to not
+ // actually be opaque.
+ static bool AppendBackgroundItemsToTop(
+ nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ const nsRect& aBackgroundRect, nsDisplayList* aList,
+ bool aAllowWillPaintBorderOptimization = true,
+ mozilla::ComputedStyle* aComputedStyle = nullptr,
+ const nsRect& aBackgroundOriginRect = nsRect(),
+ nsIFrame* aSecondaryReferenceFrame = nullptr,
+ mozilla::Maybe<nsDisplayListBuilder::AutoBuildingDisplayList>*
+ aAutoBuildingDisplayList = nullptr);
+
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override;
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+ void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
+ bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion) override;
+ nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const override;
+ mozilla::Maybe<nscolor> IsUniform(
+ nsDisplayListBuilder* aBuilder) const override;
+
+ /**
+ * GetBounds() returns the background painting area.
+ */
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
+
+ void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
+
+ /**
+ * Return the background positioning area.
+ * (GetBounds() returns the background painting area.)
+ * Can be called only when mBackgroundStyle is non-null.
+ */
+ nsRect GetPositioningArea() const;
+
+ /**
+ * Returns true if existing rendered pixels of this display item may need
+ * to be redrawn if the positioning area size changes but its position does
+ * not.
+ * If false, only the changed painting area needs to be redrawn when the
+ * positioning area size changes but its position does not.
+ */
+ bool RenderingMightDependOnPositioningAreaSizeChange() const;
+
+ nsDisplayItemGeometry* AllocateGeometry(
+ nsDisplayListBuilder* aBuilder) override {
+ return new nsDisplayBackgroundGeometry(this, aBuilder);
+ }
+
+ void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const override;
+ bool CanOptimizeToImageLayer(LayerManager* aManager,
+ nsDisplayListBuilder* aBuilder) override;
+ already_AddRefed<imgIContainer> GetImage() override;
+ nsRect GetDestRect() const override;
+
+ void UpdateDrawResult(mozilla::image::ImgDrawResult aResult) override {
+ nsDisplayBackgroundGeometry::UpdateDrawResult(this, aResult);
+ }
+
+ static nsRegion GetInsideClipRegion(const nsDisplayItem* aItem,
+ StyleGeometryBox aClip,
+ const nsRect& aRect,
+ const nsRect& aBackgroundRect);
+
+ bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) const override {
+ return mShouldFixToViewport;
+ }
+
+ nsIFrame* GetDependentFrame() override { return mDependentFrame; }
+
+ void SetDependentFrame(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) {
+ if (!aBuilder->IsRetainingDisplayList()) {
+ return;
+ }
+ mDependentFrame = aFrame;
+ if (aFrame) {
+ mDependentFrame->AddDisplayItem(this);
+ }
+ }
+
+ void RemoveFrame(nsIFrame* aFrame) override {
+ if (aFrame == mDependentFrame) {
+ mDependentFrame = nullptr;
+ }
+ nsDisplayImageContainer::RemoveFrame(aFrame);
+ }
+
+ // Match https://w3c.github.io/paint-timing/#contentful-image
+ bool IsContentful() const override {
+ const auto& styleImage =
+ mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer].mImage;
+
+ return styleImage.IsSizeAvailable() && styleImage.FinalImage().IsUrl();
+ }
+
+ protected:
+ typedef class mozilla::layers::ImageContainer ImageContainer;
+ typedef class mozilla::layers::ImageLayer ImageLayer;
+
+ bool CanBuildWebRenderDisplayItems(LayerManager* aManager,
+ nsDisplayListBuilder* aBuilder);
+ nsRect GetBoundsInternal(nsDisplayListBuilder* aBuilder,
+ nsIFrame* aFrameForBounds = nullptr);
+
+ void PaintInternal(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
+ const nsRect& aBounds, nsRect* aClipRect);
+
+ // Determine whether we want to be separated into our own layer, independent
+ // of whether this item can actually be layerized.
+ enum ImageLayerization {
+ WHENEVER_POSSIBLE,
+ ONLY_FOR_SCALING,
+ NO_LAYER_NEEDED
+ };
+ ImageLayerization ShouldCreateOwnLayer(nsDisplayListBuilder* aBuilder,
+ LayerManager* aManager);
+
+ // Cache the result of nsCSSRendering::FindBackground. Always null if
+ // mIsThemed is true or if FindBackground returned false.
+ RefPtr<mozilla::ComputedStyle> mBackgroundStyle;
+ nsCOMPtr<imgIContainer> mImage;
+ nsIFrame* mDependentFrame;
+ nsRect mBackgroundRect; // relative to the reference frame
+ nsRect mFillRect;
+ nsRect mDestRect;
+ /* Bounds of this display item */
+ nsRect mBounds;
+ uint16_t mLayer;
+ bool mIsRasterImage;
+ /* Whether the image should be treated as fixed to the viewport. */
+ bool mShouldFixToViewport;
+ uint32_t mImageFlags;
+};
+
+/**
+ * A display item to paint background image for table. For table parts, such
+ * as row, row group, col, col group, when drawing its background, we'll
+ * create separate background image display item for its containning cell.
+ * Those background image display items will reference to same DisplayItemData
+ * if we keep the mFrame point to cell's ancestor frame. We don't want to this
+ * happened bacause share same DisplatItemData will cause many bugs. So that
+ * we let mFrame point to cell frame and store the table type of the ancestor
+ * frame. And use mFrame and table type as key to generate DisplayItemData to
+ * avoid sharing DisplayItemData.
+ *
+ * Also store ancestor frame as mStyleFrame for all rendering informations.
+ */
+class nsDisplayTableBackgroundImage : public nsDisplayBackgroundImage {
+ public:
+ nsDisplayTableBackgroundImage(nsDisplayListBuilder* aBuilder,
+ nsIFrame* aFrame, const InitData& aInitData,
+ nsIFrame* aCellFrame);
+ ~nsDisplayTableBackgroundImage() override;
+
+ NS_DISPLAY_DECL_NAME("TableBackgroundImage", TYPE_TABLE_BACKGROUND_IMAGE)
+
+ bool IsInvalid(nsRect& aRect) const override;
+
+ nsIFrame* FrameForInvalidation() const override { return mStyleFrame; }
+
+ void RemoveFrame(nsIFrame* aFrame) override {
+ if (aFrame == mStyleFrame) {
+ mStyleFrame = nullptr;
+ SetDeletedFrame();
+ }
+ nsDisplayBackgroundImage::RemoveFrame(aFrame);
+ }
+
+ protected:
+ nsIFrame* StyleFrame() const override { return mStyleFrame; }
+ nsIFrame* mStyleFrame;
+};
+
+/**
+ * A display item to paint the native theme background for a frame.
+ */
+class nsDisplayThemedBackground : public nsPaintedDisplayItem {
+ public:
+ nsDisplayThemedBackground(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ const nsRect& aBackgroundRect);
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayThemedBackground)
+
+ NS_DISPLAY_DECL_NAME("ThemedBackground", TYPE_THEMED_BACKGROUND)
+
+ void Init(nsDisplayListBuilder* aBuilder);
+
+ void Destroy(nsDisplayListBuilder* aBuilder) override {
+ aBuilder->UnregisterThemeGeometry(this);
+ nsPaintedDisplayItem::Destroy(aBuilder);
+ }
+
+ void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
+ nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const override;
+ mozilla::Maybe<nscolor> IsUniform(
+ nsDisplayListBuilder* aBuilder) const override;
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
+ bool MustPaintOnContentSide() const override { return true; }
+
+ /**
+ * GetBounds() returns the background painting area.
+ */
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
+
+ void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
+
+ /**
+ * Return the background positioning area.
+ * (GetBounds() returns the background painting area.)
+ * Can be called only when mBackgroundStyle is non-null.
+ */
+ nsRect GetPositioningArea() const;
+
+ /**
+ * Return whether our frame's document does not have the state
+ * NS_DOCUMENT_STATE_WINDOW_INACTIVE.
+ */
+ bool IsWindowActive() const;
+
+ nsDisplayItemGeometry* AllocateGeometry(
+ nsDisplayListBuilder* aBuilder) override {
+ return new nsDisplayThemedBackgroundGeometry(this, aBuilder);
+ }
+
+ void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const override;
+
+ void WriteDebugInfo(std::stringstream& aStream) override;
+
+ protected:
+ nsRect GetBoundsInternal();
+
+ void PaintInternal(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
+ const nsRect& aBounds, nsRect* aClipRect);
+
+ nsRect mBackgroundRect;
+ nsRect mBounds;
+ nsITheme::Transparency mThemeTransparency;
+ mozilla::StyleAppearance mAppearance;
+};
+
+class nsDisplayTableThemedBackground : public nsDisplayThemedBackground {
+ public:
+ nsDisplayTableThemedBackground(nsDisplayListBuilder* aBuilder,
+ nsIFrame* aFrame,
+ const nsRect& aBackgroundRect,
+ nsIFrame* aAncestorFrame)
+ : nsDisplayThemedBackground(aBuilder, aFrame, aBackgroundRect),
+ mAncestorFrame(aAncestorFrame) {
+ if (aBuilder->IsRetainingDisplayList()) {
+ mAncestorFrame->AddDisplayItem(this);
+ }
+ }
+
+ ~nsDisplayTableThemedBackground() override {
+ if (mAncestorFrame) {
+ mAncestorFrame->RemoveDisplayItem(this);
+ }
+ }
+
+ NS_DISPLAY_DECL_NAME("TableThemedBackground",
+ TYPE_TABLE_THEMED_BACKGROUND_IMAGE)
+
+ nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
+
+ void RemoveFrame(nsIFrame* aFrame) override {
+ if (aFrame == mAncestorFrame) {
+ mAncestorFrame = nullptr;
+ SetDeletedFrame();
+ }
+ nsDisplayThemedBackground::RemoveFrame(aFrame);
+ }
+
+ protected:
+ nsIFrame* StyleFrame() const override { return mAncestorFrame; }
+ nsIFrame* mAncestorFrame;
+};
+
+class nsDisplayBackgroundColor : public nsPaintedDisplayItem {
+ typedef mozilla::gfx::sRGBColor sRGBColor;
+
+ public:
+ nsDisplayBackgroundColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ const nsRect& aBackgroundRect,
+ const mozilla::ComputedStyle* aBackgroundStyle,
+ const nscolor& aColor)
+ : nsPaintedDisplayItem(aBuilder, aFrame),
+ mBackgroundRect(aBackgroundRect),
+ mHasStyle(aBackgroundStyle),
+ mDependentFrame(nullptr),
+ mColor(sRGBColor::FromABGR(aColor)) {
+ mState.mColor = mColor;
+
+ if (mHasStyle) {
+ mBottomLayerClip =
+ aBackgroundStyle->StyleBackground()->BottomLayer().mClip;
+ } else {
+ MOZ_ASSERT(aBuilder->IsForEventDelivery());
+ }
+ }
+
+ ~nsDisplayBackgroundColor() override {
+ if (mDependentFrame) {
+ mDependentFrame->RemoveDisplayItem(this);
+ }
+ }
+
+ NS_DISPLAY_DECL_NAME("BackgroundColor", TYPE_BACKGROUND_COLOR)
+
+ bool RestoreState() override {
+ if (!nsPaintedDisplayItem::RestoreState() && mColor == mState.mColor) {
+ return false;
+ }
+
+ mColor = mState.mColor;
+ return true;
+ }
+
+ bool HasBackgroundClipText() const {
+ MOZ_ASSERT(mHasStyle);
+ return mBottomLayerClip == mozilla::StyleGeometryBox::Text;
+ }
+
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override;
+ void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
+ void PaintWithClip(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
+ const DisplayItemClip& aClip) override;
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+ nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const override;
+ mozilla::Maybe<nscolor> IsUniform(
+ nsDisplayListBuilder* aBuilder) const override;
+ void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
+ void ApplyOpacity(nsDisplayListBuilder* aBuilder, float aOpacity,
+ const DisplayItemClipChain* aClip) override;
+
+ bool CanApplyOpacity() const override;
+
+ float GetOpacity() const { return mColor.a; }
+
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override {
+ *aSnap = true;
+ return mBackgroundRect;
+ }
+
+ bool CanPaintWithClip(const DisplayItemClip& aClip) override {
+ if (HasBackgroundClipText()) {
+ return false;
+ }
+
+ if (aClip.GetRoundedRectCount() > 1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ nsDisplayItemGeometry* AllocateGeometry(
+ nsDisplayListBuilder* aBuilder) override {
+ return new nsDisplaySolidColorGeometry(this, aBuilder, mColor.ToABGR());
+ }
+
+ void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const override {
+ const nsDisplaySolidColorGeometry* geometry =
+ static_cast<const nsDisplaySolidColorGeometry*>(aGeometry);
+
+ if (mColor.ToABGR() != geometry->mColor) {
+ bool dummy;
+ aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &dummy));
+ return;
+ }
+ ComputeInvalidationRegionDifference(aBuilder, geometry, aInvalidRegion);
+ }
+
+ nsIFrame* GetDependentFrame() override { return mDependentFrame; }
+
+ void SetDependentFrame(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) {
+ if (!aBuilder->IsRetainingDisplayList()) {
+ return;
+ }
+ mDependentFrame = aFrame;
+ if (aFrame) {
+ mDependentFrame->AddDisplayItem(this);
+ }
+ }
+
+ void RemoveFrame(nsIFrame* aFrame) override {
+ if (aFrame == mDependentFrame) {
+ mDependentFrame = nullptr;
+ }
+
+ nsPaintedDisplayItem::RemoveFrame(aFrame);
+ }
+
+ void WriteDebugInfo(std::stringstream& aStream) override;
+
+ bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) override;
+
+ protected:
+ const nsRect mBackgroundRect;
+ const bool mHasStyle;
+ mozilla::StyleGeometryBox mBottomLayerClip;
+ nsIFrame* mDependentFrame;
+ mozilla::gfx::sRGBColor mColor;
+
+ struct {
+ mozilla::gfx::sRGBColor mColor;
+ } mState;
+};
+
+class nsDisplayTableBackgroundColor : public nsDisplayBackgroundColor {
+ public:
+ nsDisplayTableBackgroundColor(nsDisplayListBuilder* aBuilder,
+ nsIFrame* aFrame, const nsRect& aBackgroundRect,
+ const mozilla::ComputedStyle* aBackgroundStyle,
+ const nscolor& aColor, nsIFrame* aAncestorFrame)
+ : nsDisplayBackgroundColor(aBuilder, aFrame, aBackgroundRect,
+ aBackgroundStyle, aColor),
+ mAncestorFrame(aAncestorFrame) {
+ if (aBuilder->IsRetainingDisplayList()) {
+ mAncestorFrame->AddDisplayItem(this);
+ }
+ }
+
+ ~nsDisplayTableBackgroundColor() override {
+ if (mAncestorFrame) {
+ mAncestorFrame->RemoveDisplayItem(this);
+ }
+ }
+
+ NS_DISPLAY_DECL_NAME("TableBackgroundColor", TYPE_TABLE_BACKGROUND_COLOR)
+
+ nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
+
+ void RemoveFrame(nsIFrame* aFrame) override {
+ if (aFrame == mAncestorFrame) {
+ mAncestorFrame = nullptr;
+ SetDeletedFrame();
+ }
+ nsDisplayBackgroundColor::RemoveFrame(aFrame);
+ }
+
+ bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) override {
+ return false;
+ }
+
+ protected:
+ nsIFrame* mAncestorFrame;
+};
+
+/**
+ * The standard display item to paint the outer CSS box-shadows of a frame.
+ */
+class nsDisplayBoxShadowOuter final : public nsPaintedDisplayItem {
+ public:
+ nsDisplayBoxShadowOuter(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
+ : nsPaintedDisplayItem(aBuilder, aFrame), mOpacity(1.0f) {
+ MOZ_COUNT_CTOR(nsDisplayBoxShadowOuter);
+ mBounds = GetBoundsInternal();
+ }
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayBoxShadowOuter)
+
+ NS_DISPLAY_DECL_NAME("BoxShadowOuter", TYPE_BOX_SHADOW_OUTER)
+
+ bool RestoreState() override {
+ if (!nsPaintedDisplayItem::RestoreState() && mOpacity == 1.0f &&
+ mVisibleRegion.IsEmpty()) {
+ return false;
+ }
+
+ mVisibleRegion.SetEmpty();
+ mOpacity = 1.0f;
+ return true;
+ }
+
+ void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
+ bool IsInvisibleInRect(const nsRect& aRect) const override;
+ bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion) override;
+ void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const override;
+
+ void ApplyOpacity(nsDisplayListBuilder* aBuilder, float aOpacity,
+ const DisplayItemClipChain* aClip) override {
+ NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
+ mOpacity = aOpacity;
+ IntersectClip(aBuilder, aClip, false);
+ }
+
+ bool CanApplyOpacity() const override { return true; }
+
+ nsDisplayItemGeometry* AllocateGeometry(
+ nsDisplayListBuilder* aBuilder) override {
+ return new nsDisplayBoxShadowOuterGeometry(this, aBuilder, mOpacity);
+ }
+
+ bool CanBuildWebRenderDisplayItems();
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+ nsRect GetBoundsInternal();
+
+ private:
+ nsRegion mVisibleRegion;
+ nsRect mBounds;
+ float mOpacity;
+};
+
+/**
+ * The standard display item to paint the inner CSS box-shadows of a frame.
+ */
+class nsDisplayBoxShadowInner : public nsPaintedDisplayItem {
+ public:
+ nsDisplayBoxShadowInner(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
+ : nsPaintedDisplayItem(aBuilder, aFrame) {
+ MOZ_COUNT_CTOR(nsDisplayBoxShadowInner);
+ }
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayBoxShadowInner)
+
+ NS_DISPLAY_DECL_NAME("BoxShadowInner", TYPE_BOX_SHADOW_INNER)
+
+ bool RestoreState() override {
+ if (!nsPaintedDisplayItem::RestoreState() && mVisibleRegion.IsEmpty()) {
+ return false;
+ }
+
+ mVisibleRegion.SetEmpty();
+ return true;
+ }
+
+ void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
+ bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion) override;
+
+ nsDisplayItemGeometry* AllocateGeometry(
+ nsDisplayListBuilder* aBuilder) override {
+ return new nsDisplayBoxShadowInnerGeometry(this, aBuilder);
+ }
+
+ void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const override {
+ const nsDisplayBoxShadowInnerGeometry* geometry =
+ static_cast<const nsDisplayBoxShadowInnerGeometry*>(aGeometry);
+ if (!geometry->mPaddingRect.IsEqualInterior(GetPaddingRect())) {
+ // nsDisplayBoxShadowInner is based around the padding rect, but it can
+ // touch pixels outside of this. We should invalidate the entire bounds.
+ bool snap;
+ aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &snap));
+ }
+ }
+
+ static bool CanCreateWebRenderCommands(nsDisplayListBuilder* aBuilder,
+ nsIFrame* aFrame,
+ const nsPoint& aReferencePoint);
+ static void CreateInsetBoxShadowWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ const StackingContextHelper& aSc, nsRegion& aVisibleRegion,
+ nsIFrame* aFrame, const nsRect& aBorderRect);
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
+ private:
+ nsRegion mVisibleRegion;
+};
+
+/**
+ * The standard display item to paint the CSS outline of a frame.
+ */
+class nsDisplayOutline final : public nsPaintedDisplayItem {
+ public:
+ nsDisplayOutline(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
+ : nsPaintedDisplayItem(aBuilder, aFrame) {
+ MOZ_COUNT_CTOR(nsDisplayOutline);
+ }
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayOutline)
+
+ NS_DISPLAY_DECL_NAME("Outline", TYPE_OUTLINE)
+
+ bool MustPaintOnContentSide() const override {
+ MOZ_ASSERT(IsThemedOutline(),
+ "The only fallback path we have is for themed outlines");
+ return true;
+ }
+
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+ bool IsInvisibleInRect(const nsRect& aRect) const override;
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
+ void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
+
+ private:
+ bool IsThemedOutline() const;
+};
+
+/**
+ * A class that lets you receive events within the frame bounds but never
+ * paints.
+ */
+class nsDisplayEventReceiver final : public nsDisplayItem {
+ public:
+ nsDisplayEventReceiver(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
+ : nsDisplayItem(aBuilder, aFrame) {
+ MOZ_COUNT_CTOR(nsDisplayEventReceiver);
+ }
+
+ MOZ_COUNTED_DTOR_FINAL(nsDisplayEventReceiver)
+
+ NS_DISPLAY_DECL_NAME("EventReceiver", TYPE_EVENT_RECEIVER)
+
+ void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) final;
+};
+
+/**
+ * Similar to nsDisplayEventReceiver in that it is used for hit-testing. However
+ * this gets built when we're doing widget painting and we need to send the
+ * compositor some hit-test info for a frame. This is effectively a dummy item
+ * whose sole purpose is to carry the hit-test info to the compositor.
+ */
+class nsDisplayCompositorHitTestInfo : public nsDisplayHitTestInfoBase {
+ public:
+ nsDisplayCompositorHitTestInfo(
+ nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ const mozilla::gfx::CompositorHitTestInfo& aHitTestFlags,
+ const mozilla::Maybe<nsRect>& aArea = mozilla::Nothing());
+
+ nsDisplayCompositorHitTestInfo(
+ nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ mozilla::UniquePtr<HitTestInfo>&& aHitTestInfo);
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayCompositorHitTestInfo)
+
+ NS_DISPLAY_DECL_NAME("CompositorHitTestInfo", TYPE_COMPOSITOR_HITTEST_INFO)
+
+ void InitializeScrollTarget(nsDisplayListBuilder* aBuilder);
+
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
+ int32_t ZIndex() const override;
+ void SetOverrideZIndex(int32_t aZIndex);
+
+ /**
+ * ApplyOpacity() is overriden for opacity flattening.
+ */
+ void ApplyOpacity(nsDisplayListBuilder* aBuilder, float aOpacity,
+ const DisplayItemClipChain* aClip) override {}
+
+ /**
+ * CanApplyOpacity() is overriden for opacity flattening.
+ */
+ bool CanApplyOpacity() const override { return true; }
+
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override {
+ *aSnap = false;
+ return nsRect();
+ }
+
+ private:
+ mozilla::Maybe<mozilla::layers::ScrollableLayerGuid::ViewID> mScrollTarget;
+ mozilla::Maybe<int32_t> mOverrideZIndex;
+ int32_t mAppUnitsPerDevPixel;
+};
+
+/**
+ * A class that lets you wrap a display list as a display item.
+ *
+ * GetUnderlyingFrame() is troublesome for wrapped lists because if the wrapped
+ * list has many items, it's not clear which one has the 'underlying frame'.
+ * Thus we force the creator to specify what the underlying frame is. The
+ * underlying frame should be the root of a stacking context, because sorting
+ * a list containing this item will not get at the children.
+ *
+ * In some cases (e.g., clipping) we want to wrap a list but we don't have a
+ * particular underlying frame that is a stacking context root. In that case
+ * we allow the frame to be nullptr. Callers to GetUnderlyingFrame must
+ * detect and handle this case.
+ */
+class nsDisplayWrapList : public nsDisplayHitTestInfoBase {
+ public:
+ /**
+ * Takes all the items from aList and puts them in our list.
+ */
+ nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList);
+
+ nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayItem* aItem);
+
+ nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
+ bool aClearClipChain = false);
+
+ nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
+ : nsDisplayHitTestInfoBase(aBuilder, aFrame),
+ mFrameActiveScrolledRoot(aBuilder->CurrentActiveScrolledRoot()),
+ mOverrideZIndex(0),
+ mHasZIndexOverride(false) {
+ MOZ_COUNT_CTOR(nsDisplayWrapList);
+ mBaseBuildingRect = GetBuildingRect();
+ mListPtr = &mList;
+ }
+
+ nsDisplayWrapList() = delete;
+
+ /**
+ * A custom copy-constructor that does not copy mList, as this would mutate
+ * the other item.
+ */
+ nsDisplayWrapList(const nsDisplayWrapList& aOther) = delete;
+ nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
+ const nsDisplayWrapList& aOther)
+ : nsDisplayHitTestInfoBase(aBuilder, aOther),
+ mListPtr(&mList),
+ mFrameActiveScrolledRoot(aOther.mFrameActiveScrolledRoot),
+ mMergedFrames(aOther.mMergedFrames.Clone()),
+ mBounds(aOther.mBounds),
+ mBaseBuildingRect(aOther.mBaseBuildingRect),
+ mOverrideZIndex(aOther.mOverrideZIndex),
+ mHasZIndexOverride(aOther.mHasZIndexOverride),
+ mClearingClipChain(aOther.mClearingClipChain) {
+ MOZ_COUNT_CTOR(nsDisplayWrapList);
+ }
+
+ ~nsDisplayWrapList() override;
+
+ NS_DISPLAY_DECL_NAME("WrapList", TYPE_WRAP_LIST)
+
+ const nsDisplayWrapList* AsDisplayWrapList() const final { return this; }
+ nsDisplayWrapList* AsDisplayWrapList() final { return this; }
+
+ void Destroy(nsDisplayListBuilder* aBuilder) override {
+ mList.DeleteAll(aBuilder);
+ nsDisplayHitTestInfoBase::Destroy(aBuilder);
+ }
+
+ /**
+ * Creates a new nsDisplayWrapList that holds a pointer to the display list
+ * owned by the given nsDisplayItem. The new nsDisplayWrapList will be added
+ * to the bottom of this item's contents.
+ */
+ void MergeDisplayListFromItem(nsDisplayListBuilder* aBuilder,
+ const nsDisplayWrapList* aItem);
+
+ /**
+ * Call this if the wrapped list is changed.
+ */
+ void UpdateBounds(nsDisplayListBuilder* aBuilder) override {
+ // Clear the clip chain up to the asr, but don't store it, so that we'll
+ // recover it when we reuse the item.
+ if (mClearingClipChain) {
+ const DisplayItemClipChain* clip = mState.mClipChain;
+ while (clip && ActiveScrolledRoot::IsAncestor(GetActiveScrolledRoot(),
+ clip->mASR)) {
+ clip = clip->mParent;
+ }
+ SetClipChain(clip, false);
+ }
+
+ nsRect buildingRect;
+ mBounds = mListPtr->GetClippedBoundsWithRespectToASR(
+ aBuilder, mActiveScrolledRoot, &buildingRect);
+ // The display list may contain content that's visible outside the visible
+ // rect (i.e. the current dirty rect) passed in when the item was created.
+ // This happens when the dirty rect has been restricted to the visual
+ // overflow rect of a frame for some reason (e.g. when setting up dirty
+ // rects in nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay), but that
+ // frame contains placeholders for out-of-flows that aren't descendants of
+ // the frame.
+ buildingRect.UnionRect(mBaseBuildingRect, buildingRect);
+ SetBuildingRect(buildingRect);
+ }
+
+ void SetActiveScrolledRoot(
+ const ActiveScrolledRoot* aActiveScrolledRoot) override {
+ // Skip unnecessary call to
+ // |nsDisplayHitTestInfoBase::UpdateHitTestInfoActiveScrolledRoot()|, since
+ // callers will manually call that with different ASR.
+ nsDisplayHitTestInfoBase::SetActiveScrolledRoot(aActiveScrolledRoot);
+ }
+
+ void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
+ nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const override;
+ mozilla::Maybe<nscolor> IsUniform(
+ nsDisplayListBuilder* aBuilder) const override;
+ void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
+ bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion) override;
+
+ /**
+ * Checks if the given display item can be merged with this item.
+ * @return true if the merging is possible, otherwise false.
+ */
+ virtual bool CanMerge(const nsDisplayItem* aItem) const { return false; }
+
+ /**
+ * Try to merge with the other item (which is below us in the display
+ * list). This gets used by nsDisplayClip to coalesce clipping operations
+ * (optimization), by nsDisplayOpacity to merge rendering for the same
+ * content element into a single opacity group (correctness), and will be
+ * used by nsDisplayOutline to merge multiple outlines for the same element
+ * (also for correctness).
+ */
+ virtual void Merge(const nsDisplayItem* aItem) {
+ MOZ_ASSERT(CanMerge(aItem));
+ MOZ_ASSERT(Frame() != aItem->Frame());
+ MergeFromTrackingMergedFrames(static_cast<const nsDisplayWrapList*>(aItem));
+ }
+
+ /**
+ * Returns the underlying frames of all display items that have been
+ * merged into this one (excluding this item's own underlying frame)
+ * to aFrames.
+ */
+ const nsTArray<nsIFrame*>& GetMergedFrames() const { return mMergedFrames; }
+
+ bool HasMergedFrames() const { return !mMergedFrames.IsEmpty(); }
+
+ bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
+ return true;
+ }
+
+ bool IsInvalid(nsRect& aRect) const override {
+ if (mFrame->IsInvalid(aRect) && aRect.IsEmpty()) {
+ return true;
+ }
+ nsRect temp;
+ for (uint32_t i = 0; i < mMergedFrames.Length(); i++) {
+ if (mMergedFrames[i]->IsInvalid(temp) && temp.IsEmpty()) {
+ aRect.SetEmpty();
+ return true;
+ }
+ aRect = aRect.Union(temp);
+ }
+ aRect += ToReferenceFrame();
+ return !aRect.IsEmpty();
+ }
+
+ nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const override;
+
+ RetainedDisplayList* GetSameCoordinateSystemChildren() const override {
+ NS_ASSERTION(
+ mListPtr->IsEmpty() || !ReferenceFrame() ||
+ !mListPtr->GetBottom()->ReferenceFrame() ||
+ mListPtr->GetBottom()->ReferenceFrame() == ReferenceFrame(),
+ "Children must have same reference frame");
+ return mListPtr;
+ }
+
+ RetainedDisplayList* GetChildren() const override { return mListPtr; }
+
+ int32_t ZIndex() const override {
+ return (mHasZIndexOverride) ? mOverrideZIndex
+ : nsDisplayHitTestInfoBase::ZIndex();
+ }
+
+ void SetOverrideZIndex(int32_t aZIndex) {
+ mHasZIndexOverride = true;
+ mOverrideZIndex = aZIndex;
+ }
+
+ /**
+ * This creates a copy of this item, but wrapping aItem instead of
+ * our existing list. Only gets called if this item returned nullptr
+ * for GetUnderlyingFrame(). aItem is guaranteed to return non-null from
+ * GetUnderlyingFrame().
+ */
+ nsDisplayWrapList* WrapWithClone(nsDisplayListBuilder* aBuilder,
+ nsDisplayItem* aItem) {
+ MOZ_ASSERT_UNREACHABLE("We never returned nullptr for GetUnderlyingFrame!");
+ return nullptr;
+ }
+
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
+ const ActiveScrolledRoot* GetFrameActiveScrolledRoot() {
+ return mFrameActiveScrolledRoot;
+ }
+
+ protected:
+ void MergeFromTrackingMergedFrames(const nsDisplayWrapList* aOther) {
+ mBounds.UnionRect(mBounds, aOther->mBounds);
+ nsRect buildingRect;
+ buildingRect.UnionRect(GetBuildingRect(), aOther->GetBuildingRect());
+ SetBuildingRect(buildingRect);
+ mMergedFrames.AppendElement(aOther->mFrame);
+ mMergedFrames.AppendElements(aOther->mMergedFrames.Clone());
+ }
+
+ RetainedDisplayList mList;
+ RetainedDisplayList* mListPtr;
+ // The active scrolled root for the frame that created this
+ // wrap list.
+ RefPtr<const ActiveScrolledRoot> mFrameActiveScrolledRoot;
+ // The frames from items that have been merged into this item, excluding
+ // this item's own frame.
+ nsTArray<nsIFrame*> mMergedFrames;
+ nsRect mBounds;
+ // Displaylist building rect contributed by this display item itself.
+ // Our mBuildingRect may include the visible areas of children.
+ nsRect mBaseBuildingRect;
+ int32_t mOverrideZIndex;
+ bool mHasZIndexOverride;
+ bool mClearingClipChain = false;
+
+ private:
+ NS_DISPLAY_ALLOW_CLONING()
+ friend class nsDisplayListBuilder;
+};
+
+/**
+ * We call WrapDisplayList on the in-flow lists: BorderBackground(),
+ * BlockBorderBackgrounds() and Content().
+ * We call WrapDisplayItem on each item of Outlines(), PositionedDescendants(),
+ * and Floats(). This is done to support special wrapping processing for frames
+ * that may not be in-flow descendants of the current frame.
+ */
+class nsDisplayWrapper {
+ public:
+ // This is never instantiated directly (it has pure virtual methods), so no
+ // need to count constructors and destructors.
+
+ bool WrapBorderBackground() { return true; }
+ virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
+ nsIFrame* aFrame, nsDisplayList* aList) = 0;
+ virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
+ nsDisplayItem* aItem) = 0;
+
+ nsresult WrapLists(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ const nsDisplayListSet& aIn, const nsDisplayListSet& aOut);
+ nsresult WrapListsInPlace(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ const nsDisplayListSet& aLists);
+
+ protected:
+ nsDisplayWrapper() = default;
+};
+
+/**
+ * The standard display item to paint a stacking context with translucency
+ * set by the stacking context root frame's 'opacity' style.
+ */
+class nsDisplayOpacity : public nsDisplayWrapList {
+ public:
+ nsDisplayOpacity(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
+ bool aForEventsAndPluginsOnly, bool aNeedsActiveLayer);
+
+ nsDisplayOpacity(nsDisplayListBuilder* aBuilder,
+ const nsDisplayOpacity& aOther)
+ : nsDisplayWrapList(aBuilder, aOther),
+ mOpacity(aOther.mOpacity),
+ mForEventsAndPluginsOnly(aOther.mForEventsAndPluginsOnly),
+ mNeedsActiveLayer(aOther.mNeedsActiveLayer),
+ mChildOpacityState(ChildOpacityState::Unknown) {
+ MOZ_COUNT_CTOR(nsDisplayOpacity);
+ // We should not try to merge flattened opacities.
+ MOZ_ASSERT(aOther.mChildOpacityState != ChildOpacityState::Applied);
+ }
+
+ void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayOpacity)
+
+ NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY)
+
+ bool RestoreState() override {
+ if (!nsDisplayWrapList::RestoreState() && mOpacity == mState.mOpacity) {
+ return false;
+ }
+
+ mOpacity = mState.mOpacity;
+ return true;
+ }
+
+ void InvalidateCachedChildInfo(nsDisplayListBuilder* aBuilder) override {
+ mChildOpacityState = ChildOpacityState::Unknown;
+ }
+
+ nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const override;
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override;
+ bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion) override;
+
+ bool CanMerge(const nsDisplayItem* aItem) const override {
+ // items for the same content element should be merged into a single
+ // compositing group
+ // aItem->GetUnderlyingFrame() returns non-null because it's
+ // nsDisplayOpacity
+ return HasDifferentFrame(aItem) && HasSameTypeAndClip(aItem) &&
+ HasSameContent(aItem);
+ }
+
+ nsDisplayItemGeometry* AllocateGeometry(
+ nsDisplayListBuilder* aBuilder) override {
+ return new nsDisplayOpacityGeometry(this, aBuilder, mOpacity);
+ }
+
+ void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const override;
+
+ bool IsInvalid(nsRect& aRect) const override {
+ if (mForEventsAndPluginsOnly) {
+ return false;
+ }
+ return nsDisplayWrapList::IsInvalid(aRect);
+ }
+ void ApplyOpacity(nsDisplayListBuilder* aBuilder, float aOpacity,
+ const DisplayItemClipChain* aClip) override;
+ bool CanApplyOpacity() const override;
+ bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override;
+
+ bool NeedsGeometryUpdates() const override {
+ // For flattened nsDisplayOpacity items, ComputeInvalidationRegion() only
+ // handles invalidation for changed |mOpacity|. In order to keep track of
+ // the current bounds of the item for invalidation, nsDisplayOpacityGeometry
+ // for the corresponding DisplayItemData needs to be updated, even if the
+ // reported invalidation region is empty.
+ return mChildOpacityState == ChildOpacityState::Deferred;
+ }
+
+ /**
+ * Returns true if ShouldFlattenAway() applied opacity to children.
+ */
+ bool OpacityAppliedToChildren() const {
+ return mChildOpacityState == ChildOpacityState::Applied;
+ }
+
+ static bool NeedsActiveLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ bool aEnforceMinimumSize = true);
+ void WriteDebugInfo(std::stringstream& aStream) override;
+ bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) override;
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
+ float GetOpacity() const { return mOpacity; }
+
+ private:
+ NS_DISPLAY_ALLOW_CLONING()
+
+ bool ApplyToChildren(nsDisplayListBuilder* aBuilder);
+ bool ApplyToFilterOrMask(const bool aUsingLayers);
+
+ float mOpacity;
+ bool mForEventsAndPluginsOnly : 1;
+ enum class ChildOpacityState : uint8_t {
+ // Our child list has changed since the last time ApplyToChildren was
+ // called.
+ Unknown,
+ // Our children defer opacity handling to us.
+ Deferred,
+ // Opacity is applied to our children.
+ Applied
+ };
+ bool mNeedsActiveLayer : 1;
+#ifndef __GNUC__
+ ChildOpacityState mChildOpacityState : 2;
+#else
+ ChildOpacityState mChildOpacityState;
+#endif
+
+ struct {
+ float mOpacity;
+ } mState;
+};
+
+class nsDisplayBlendMode : public nsDisplayWrapList {
+ public:
+ nsDisplayBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList, mozilla::StyleBlend aBlendMode,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
+ const bool aIsForBackground);
+ nsDisplayBlendMode(nsDisplayListBuilder* aBuilder,
+ const nsDisplayBlendMode& aOther)
+ : nsDisplayWrapList(aBuilder, aOther),
+ mBlendMode(aOther.mBlendMode),
+ mIsForBackground(aOther.mIsForBackground) {
+ MOZ_COUNT_CTOR(nsDisplayBlendMode);
+ }
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayBlendMode)
+
+ NS_DISPLAY_DECL_NAME("BlendMode", TYPE_BLEND_MODE)
+
+ nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const override;
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+ void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const override {
+ // We don't need to compute an invalidation region since we have
+ // LayerTreeInvalidation
+ }
+
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override;
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+ bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion) override;
+
+ bool CanMerge(const nsDisplayItem* aItem) const override;
+
+ bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
+ return false;
+ }
+
+ mozilla::gfx::CompositionOp BlendMode();
+
+ protected:
+ mozilla::StyleBlend mBlendMode;
+ bool mIsForBackground;
+
+ private:
+ NS_DISPLAY_ALLOW_CLONING()
+};
+
+class nsDisplayTableBlendMode : public nsDisplayBlendMode {
+ public:
+ nsDisplayTableBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList, mozilla::StyleBlend aBlendMode,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
+ nsIFrame* aAncestorFrame, const bool aIsForBackground)
+ : nsDisplayBlendMode(aBuilder, aFrame, aList, aBlendMode,
+ aActiveScrolledRoot, aIsForBackground),
+ mAncestorFrame(aAncestorFrame) {
+ if (aBuilder->IsRetainingDisplayList()) {
+ mAncestorFrame->AddDisplayItem(this);
+ }
+ }
+
+ nsDisplayTableBlendMode(nsDisplayListBuilder* aBuilder,
+ const nsDisplayTableBlendMode& aOther)
+ : nsDisplayBlendMode(aBuilder, aOther),
+ mAncestorFrame(aOther.mAncestorFrame) {
+ if (aBuilder->IsRetainingDisplayList()) {
+ mAncestorFrame->AddDisplayItem(this);
+ }
+ }
+
+ ~nsDisplayTableBlendMode() override {
+ if (mAncestorFrame) {
+ mAncestorFrame->RemoveDisplayItem(this);
+ }
+ }
+
+ NS_DISPLAY_DECL_NAME("TableBlendMode", TYPE_TABLE_BLEND_MODE)
+
+ nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
+
+ void RemoveFrame(nsIFrame* aFrame) override {
+ if (aFrame == mAncestorFrame) {
+ mAncestorFrame = nullptr;
+ SetDeletedFrame();
+ }
+ nsDisplayBlendMode::RemoveFrame(aFrame);
+ }
+
+ protected:
+ nsIFrame* mAncestorFrame;
+
+ private:
+ NS_DISPLAY_ALLOW_CLONING()
+};
+
+class nsDisplayBlendContainer : public nsDisplayWrapList {
+ public:
+ static nsDisplayBlendContainer* CreateForMixBlendMode(
+ nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot);
+
+ static nsDisplayBlendContainer* CreateForBackgroundBlendMode(
+ nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsIFrame* aSecondaryFrame, nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot);
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayBlendContainer)
+
+ NS_DISPLAY_DECL_NAME("BlendContainer", TYPE_BLEND_CONTAINER)
+
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override;
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
+ bool CanMerge(const nsDisplayItem* aItem) const override {
+ // Items for the same content element should be merged into a single
+ // compositing group.
+ return HasDifferentFrame(aItem) && HasSameTypeAndClip(aItem) &&
+ HasSameContent(aItem) &&
+ mIsForBackground ==
+ static_cast<const nsDisplayBlendContainer*>(aItem)
+ ->mIsForBackground;
+ }
+
+ bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
+ return false;
+ }
+
+ protected:
+ nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
+ bool aIsForBackground);
+ nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder,
+ const nsDisplayBlendContainer& aOther)
+ : nsDisplayWrapList(aBuilder, aOther),
+ mIsForBackground(aOther.mIsForBackground) {
+ MOZ_COUNT_CTOR(nsDisplayBlendContainer);
+ }
+
+ // Used to distinguish containers created at building stacking
+ // context or appending background.
+ bool mIsForBackground;
+
+ private:
+ NS_DISPLAY_ALLOW_CLONING()
+};
+
+class nsDisplayTableBlendContainer : public nsDisplayBlendContainer {
+ public:
+ NS_DISPLAY_DECL_NAME("TableBlendContainer", TYPE_TABLE_BLEND_CONTAINER)
+
+ nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
+
+ void RemoveFrame(nsIFrame* aFrame) override {
+ if (aFrame == mAncestorFrame) {
+ mAncestorFrame = nullptr;
+ SetDeletedFrame();
+ }
+ nsDisplayBlendContainer::RemoveFrame(aFrame);
+ }
+
+ protected:
+ nsDisplayTableBlendContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
+ bool aIsForBackground, nsIFrame* aAncestorFrame)
+ : nsDisplayBlendContainer(aBuilder, aFrame, aList, aActiveScrolledRoot,
+ aIsForBackground),
+ mAncestorFrame(aAncestorFrame) {
+ if (aBuilder->IsRetainingDisplayList()) {
+ mAncestorFrame->AddDisplayItem(this);
+ }
+ }
+
+ nsDisplayTableBlendContainer(nsDisplayListBuilder* aBuilder,
+ const nsDisplayTableBlendContainer& aOther)
+ : nsDisplayBlendContainer(aBuilder, aOther),
+ mAncestorFrame(aOther.mAncestorFrame) {}
+
+ ~nsDisplayTableBlendContainer() override {
+ if (mAncestorFrame) {
+ mAncestorFrame->RemoveDisplayItem(this);
+ }
+ }
+
+ nsIFrame* mAncestorFrame;
+
+ private:
+ NS_DISPLAY_ALLOW_CLONING()
+};
+
+/**
+ * nsDisplayOwnLayer constructor flags. If we nest this class inside
+ * nsDisplayOwnLayer then we can't forward-declare it up at the top of this
+ * file and that makes it hard to use in all the places that we need to use it.
+ */
+enum class nsDisplayOwnLayerFlags {
+ None = 0,
+ GenerateSubdocInvalidations = 1 << 0,
+ GenerateScrollableLayer = 1 << 1,
+};
+
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsDisplayOwnLayerFlags)
+
+/**
+ * A display item that has no purpose but to ensure its contents get
+ * their own layer.
+ */
+class nsDisplayOwnLayer : public nsDisplayWrapList {
+ public:
+ typedef mozilla::layers::ScrollbarData ScrollbarData;
+
+ enum OwnLayerType {
+ OwnLayerForTransformWithRoundedClip,
+ OwnLayerForStackingContext,
+ OwnLayerForImageBoxFrame,
+ OwnLayerForScrollbar,
+ OwnLayerForScrollThumb,
+ OwnLayerForSubdoc,
+ OwnLayerForBoxFrame
+ };
+
+ /**
+ * @param aFlags eGenerateSubdocInvalidations :
+ * Add UserData to the created ContainerLayer, so that invalidations
+ * for this layer are send to our nsPresContext.
+ * eGenerateScrollableLayer : only valid on nsDisplaySubDocument (and
+ * subclasses), indicates this layer is to be a scrollable layer, so call
+ * ComputeFrameMetrics, etc.
+ * @param aScrollTarget when eVerticalScrollbar or eHorizontalScrollbar
+ * is set in the flags, this parameter should be the ViewID of the
+ * scrollable content this scrollbar is for.
+ */
+ nsDisplayOwnLayer(
+ nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
+ nsDisplayOwnLayerFlags aFlags = nsDisplayOwnLayerFlags::None,
+ const ScrollbarData& aScrollbarData = ScrollbarData{},
+ bool aForceActive = true, bool aClearClipChain = false);
+
+ nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
+ const nsDisplayOwnLayer& aOther)
+ : nsDisplayWrapList(aBuilder, aOther),
+ mFlags(aOther.mFlags),
+ mScrollbarData(aOther.mScrollbarData),
+ mForceActive(aOther.mForceActive),
+ mWrAnimationId(aOther.mWrAnimationId) {
+ MOZ_COUNT_CTOR(nsDisplayOwnLayer);
+ }
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayOwnLayer)
+
+ NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER)
+
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+ bool UpdateScrollData(
+ mozilla::layers::WebRenderScrollData* aData,
+ mozilla::layers::WebRenderLayerScrollData* aLayerData) override;
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override;
+
+ bool CanMerge(const nsDisplayItem* aItem) const override {
+ // Don't allow merging, each sublist must have its own layer
+ return false;
+ }
+
+ bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
+ return false;
+ }
+
+ void WriteDebugInfo(std::stringstream& aStream) override;
+ nsDisplayOwnLayerFlags GetFlags() { return mFlags; }
+ bool IsScrollThumbLayer() const;
+ bool IsScrollbarContainer() const;
+ bool IsRootScrollbarContainer() const;
+ bool IsZoomingLayer() const;
+ bool IsFixedPositionLayer() const;
+ bool IsStickyPositionLayer() const;
+ bool HasDynamicToolbar() const;
+
+ protected:
+ nsDisplayOwnLayerFlags mFlags;
+
+ /**
+ * If this nsDisplayOwnLayer represents a scroll thumb layer or a
+ * scrollbar container layer, mScrollbarData stores information
+ * about the scrollbar. Otherwise, mScrollbarData will be
+ * default-constructed (in particular with mDirection == Nothing())
+ * and can be ignored.
+ */
+ ScrollbarData mScrollbarData;
+ bool mForceActive;
+ uint64_t mWrAnimationId;
+};
+
+/**
+ * A display item for subdocuments. This is more or less the same as
+ * nsDisplayOwnLayer, except that it always populates the FrameMetrics instance
+ * on the ContainerLayer it builds.
+ */
+class nsDisplaySubDocument : public nsDisplayOwnLayer {
+ public:
+ nsDisplaySubDocument(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsSubDocumentFrame* aSubDocFrame, nsDisplayList* aList,
+ nsDisplayOwnLayerFlags aFlags);
+ ~nsDisplaySubDocument() override;
+
+ NS_DISPLAY_DECL_NAME("SubDocument", TYPE_SUBDOCUMENT)
+
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
+
+ virtual nsSubDocumentFrame* SubDocumentFrame() { return mSubDocFrame; }
+
+ bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion) override;
+ bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
+ return mShouldFlatten;
+ }
+
+ void SetShouldFlattenAway(bool aShouldFlatten) {
+ mShouldFlatten = aShouldFlatten;
+ }
+
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override {
+ if (mShouldFlatten) {
+ return mozilla::LayerState::LAYER_NONE;
+ }
+ return nsDisplayOwnLayer::GetLayerState(aBuilder, aManager, aParameters);
+ }
+
+ nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const override;
+
+ nsIFrame* FrameForInvalidation() const override;
+ void RemoveFrame(nsIFrame* aFrame) override;
+
+ void Disown();
+
+ protected:
+ ViewID mScrollParentId;
+ bool mForceDispatchToContentRegion;
+ bool mShouldFlatten;
+ nsSubDocumentFrame* mSubDocFrame;
+};
+
+/**
+ * A display item used to represent sticky position elements. The contents
+ * gets its own layer and creates a stacking context, and the layer will have
+ * position-related metadata set on it.
+ */
+class nsDisplayStickyPosition : public nsDisplayOwnLayer {
+ public:
+ nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
+ const ActiveScrolledRoot* aContainerASR,
+ bool aClippedToDisplayPort);
+ nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder,
+ const nsDisplayStickyPosition& aOther)
+ : nsDisplayOwnLayer(aBuilder, aOther),
+ mContainerASR(aOther.mContainerASR),
+ mClippedToDisplayPort(aOther.mClippedToDisplayPort) {
+ MOZ_COUNT_CTOR(nsDisplayStickyPosition);
+ }
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayStickyPosition)
+
+ void SetClipChain(const DisplayItemClipChain* aClipChain,
+ bool aStore) override;
+ bool IsClippedToDisplayPort() const { return mClippedToDisplayPort; }
+
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+ NS_DISPLAY_DECL_NAME("StickyPosition", TYPE_STICKY_POSITION)
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override {
+ return mozilla::LayerState::LAYER_ACTIVE;
+ }
+
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
+ bool UpdateScrollData(
+ mozilla::layers::WebRenderScrollData* aData,
+ mozilla::layers::WebRenderLayerScrollData* aLayerData) override;
+
+ const ActiveScrolledRoot* GetContainerASR() const { return mContainerASR; }
+
+ private:
+ NS_DISPLAY_ALLOW_CLONING()
+
+ void CalculateLayerScrollRanges(
+ mozilla::StickyScrollContainer* aStickyScrollContainer,
+ float aAppUnitsPerDevPixel, float aScaleX, float aScaleY,
+ mozilla::LayerRectAbsolute& aStickyOuter,
+ mozilla::LayerRectAbsolute& aStickyInner);
+
+ mozilla::StickyScrollContainer* GetStickyScrollContainer();
+
+ // This stores the ASR that this sticky container item would have assuming it
+ // has no fixed descendants. This may be the same as the ASR returned by
+ // GetActiveScrolledRoot(), or it may be a descendant of that.
+ RefPtr<const ActiveScrolledRoot> mContainerASR;
+ // This flag tracks if this sticky item is just clipped to the enclosing
+ // scrollframe's displayport, or if there are additional clips in play. In
+ // the former case, we can skip setting the displayport clip as the scrolled-
+ // clip of the corresponding layer. This allows sticky items to remain
+ // unclipped when the enclosing scrollframe is scrolled past the displayport.
+ // i.e. when the rest of the scrollframe checkerboards, the sticky item will
+ // not. This makes sense to do because the sticky item has abnormal scrolling
+ // behavior and may still be visible even if the rest of the scrollframe is
+ // checkerboarded. Note that the sticky item will still be subject to the
+ // scrollport clip.
+ bool mClippedToDisplayPort;
+};
+
+class nsDisplayFixedPosition : public nsDisplayOwnLayer {
+ public:
+ nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
+ const ActiveScrolledRoot* aContainerASR);
+ nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder,
+ const nsDisplayFixedPosition& aOther)
+ : nsDisplayOwnLayer(aBuilder, aOther),
+ mAnimatedGeometryRootForScrollMetadata(
+ aOther.mAnimatedGeometryRootForScrollMetadata),
+ mContainerASR(aOther.mContainerASR),
+ mIsFixedBackground(aOther.mIsFixedBackground) {
+ MOZ_COUNT_CTOR(nsDisplayFixedPosition);
+ }
+
+ static nsDisplayFixedPosition* CreateForFixedBackground(
+ nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsIFrame* aSecondaryFrame, nsDisplayBackgroundImage* aImage,
+ const uint16_t aIndex);
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayFixedPosition)
+
+ NS_DISPLAY_DECL_NAME("FixedPosition", TYPE_FIXED_POSITION)
+
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override {
+ return mozilla::LayerState::LAYER_ACTIVE_FORCE;
+ }
+
+ bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) const override {
+ return mIsFixedBackground;
+ }
+
+ AnimatedGeometryRoot* AnimatedGeometryRootForScrollMetadata() const override {
+ return mAnimatedGeometryRootForScrollMetadata;
+ }
+
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+ bool UpdateScrollData(
+ mozilla::layers::WebRenderScrollData* aData,
+ mozilla::layers::WebRenderLayerScrollData* aLayerData) override;
+ void WriteDebugInfo(std::stringstream& aStream) override;
+
+ protected:
+ // For background-attachment:fixed
+ nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList);
+ void Init(nsDisplayListBuilder* aBuilder);
+ ViewID GetScrollTargetId();
+
+ RefPtr<AnimatedGeometryRoot> mAnimatedGeometryRootForScrollMetadata;
+ RefPtr<const ActiveScrolledRoot> mContainerASR;
+ bool mIsFixedBackground;
+
+ private:
+ NS_DISPLAY_ALLOW_CLONING()
+};
+
+class nsDisplayTableFixedPosition : public nsDisplayFixedPosition {
+ public:
+ NS_DISPLAY_DECL_NAME("TableFixedPosition", TYPE_TABLE_FIXED_POSITION)
+
+ nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
+
+ void RemoveFrame(nsIFrame* aFrame) override {
+ if (aFrame == mAncestorFrame) {
+ mAncestorFrame = nullptr;
+ SetDeletedFrame();
+ }
+ nsDisplayFixedPosition::RemoveFrame(aFrame);
+ }
+
+ protected:
+ nsDisplayTableFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList, nsIFrame* aAncestorFrame);
+
+ nsDisplayTableFixedPosition(nsDisplayListBuilder* aBuilder,
+ const nsDisplayTableFixedPosition& aOther)
+ : nsDisplayFixedPosition(aBuilder, aOther),
+ mAncestorFrame(aOther.mAncestorFrame) {}
+
+ ~nsDisplayTableFixedPosition() override {
+ if (mAncestorFrame) {
+ mAncestorFrame->RemoveDisplayItem(this);
+ }
+ }
+
+ nsIFrame* mAncestorFrame;
+
+ private:
+ NS_DISPLAY_ALLOW_CLONING()
+};
+
+/**
+ * This creates an empty scrollable layer. It has no child layers.
+ * It is used to record the existence of a scrollable frame in the layer
+ * tree.
+ */
+class nsDisplayScrollInfoLayer : public nsDisplayWrapList {
+ public:
+ nsDisplayScrollInfoLayer(nsDisplayListBuilder* aBuilder,
+ nsIFrame* aScrolledFrame, nsIFrame* aScrollFrame,
+ const CompositorHitTestInfo& aHitInfo,
+ const nsRect& aHitArea);
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayScrollInfoLayer)
+
+ NS_DISPLAY_DECL_NAME("ScrollInfoLayer", TYPE_SCROLL_INFO_LAYER)
+
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+
+ nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const override {
+ *aSnap = false;
+ return nsRegion();
+ }
+
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override;
+
+ bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
+ return false;
+ }
+
+ void WriteDebugInfo(std::stringstream& aStream) override;
+ mozilla::UniquePtr<ScrollMetadata> ComputeScrollMetadata(
+ nsDisplayListBuilder* aBuilder, LayerManager* aLayerManager,
+ const ContainerLayerParameters& aContainerParameters);
+ bool UpdateScrollData(
+ mozilla::layers::WebRenderScrollData* aData,
+ mozilla::layers::WebRenderLayerScrollData* aLayerData) override;
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
+ protected:
+ nsIFrame* mScrollFrame;
+ nsIFrame* mScrolledFrame;
+ ViewID mScrollParentId;
+ CompositorHitTestInfo mHitInfo;
+ nsRect mHitArea;
+};
+
+/**
+ * nsDisplayZoom is used for subdocuments that have a different full zoom than
+ * their parent documents. This item creates a container layer.
+ */
+class nsDisplayZoom : public nsDisplaySubDocument {
+ public:
+ /**
+ * @param aFrame is the root frame of the subdocument.
+ * @param aList contains the display items for the subdocument.
+ * @param aAPD is the app units per dev pixel ratio of the subdocument.
+ * @param aParentAPD is the app units per dev pixel ratio of the parent
+ * document.
+ * @param aFlags eGenerateSubdocInvalidations :
+ * Add UserData to the created ContainerLayer, so that invalidations
+ * for this layer are send to our nsPresContext.
+ */
+ nsDisplayZoom(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsSubDocumentFrame* aSubDocFrame, nsDisplayList* aList,
+ int32_t aAPD, int32_t aParentAPD,
+ nsDisplayOwnLayerFlags aFlags = nsDisplayOwnLayerFlags::None);
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayZoom)
+
+ NS_DISPLAY_DECL_NAME("Zoom", TYPE_ZOOM)
+
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
+ void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
+ bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion) override;
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override {
+ return mozilla::LayerState::LAYER_ACTIVE;
+ }
+
+ // Get the app units per dev pixel ratio of the child document.
+ int32_t GetChildAppUnitsPerDevPixel() { return mAPD; }
+ // Get the app units per dev pixel ratio of the parent document.
+ int32_t GetParentAppUnitsPerDevPixel() { return mParentAPD; }
+
+ private:
+ int32_t mAPD, mParentAPD;
+};
+
+/**
+ * nsDisplayAsyncZoom is used for APZ zooming. It wraps the contents of the
+ * root content document's scroll frame, including fixed position content. It
+ * does not contain the scroll frame's scrollbars. It is clipped to the scroll
+ * frame's scroll port clip. It is not scrolled; only its non-fixed contents
+ * are scrolled. This item creates a container layer.
+ */
+class nsDisplayAsyncZoom : public nsDisplayOwnLayer {
+ public:
+ nsDisplayAsyncZoom(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
+ mozilla::layers::FrameMetrics::ViewID aViewID);
+ nsDisplayAsyncZoom(nsDisplayListBuilder* aBuilder,
+ const nsDisplayAsyncZoom& aOther)
+ : nsDisplayOwnLayer(aBuilder, aOther), mViewID(aOther.mViewID) {
+ MOZ_COUNT_CTOR(nsDisplayAsyncZoom);
+ }
+
+#ifdef NS_BUILD_REFCNT_LOGGING
+ virtual ~nsDisplayAsyncZoom();
+#endif
+
+ NS_DISPLAY_DECL_NAME("AsyncZoom", TYPE_ASYNC_ZOOM)
+
+ void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override {
+ return mozilla::LayerState::LAYER_ACTIVE_FORCE;
+ }
+ bool UpdateScrollData(
+ mozilla::layers::WebRenderScrollData* aData,
+ mozilla::layers::WebRenderLayerScrollData* aLayerData) override;
+
+ protected:
+ mozilla::layers::FrameMetrics::ViewID mViewID;
+};
+
+/**
+ * A base class for different effects types.
+ */
+class nsDisplayEffectsBase : public nsDisplayWrapList {
+ public:
+ nsDisplayEffectsBase(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
+ bool aClearClipChain = false);
+ nsDisplayEffectsBase(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList);
+
+ nsDisplayEffectsBase(nsDisplayListBuilder* aBuilder,
+ const nsDisplayEffectsBase& aOther)
+ : nsDisplayWrapList(aBuilder, aOther),
+ mEffectsBounds(aOther.mEffectsBounds),
+ mHandleOpacity(aOther.mHandleOpacity) {
+ MOZ_COUNT_CTOR(nsDisplayEffectsBase);
+ }
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayEffectsBase)
+
+ nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const override;
+ void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
+
+ bool RestoreState() override {
+ if (!nsDisplayWrapList::RestoreState() && !mHandleOpacity) {
+ return false;
+ }
+
+ mHandleOpacity = false;
+ return true;
+ }
+
+ bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
+ return false;
+ }
+
+ virtual void SelectOpacityOptimization(const bool /* aUsingLayers */) {
+ SetHandleOpacity();
+ }
+
+ bool ShouldHandleOpacity() const { return mHandleOpacity; }
+
+ gfxRect BBoxInUserSpace() const;
+ gfxPoint UserSpaceOffset() const;
+
+ void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const override;
+
+ protected:
+ void SetHandleOpacity() { mHandleOpacity = true; }
+ bool ValidateSVGFrame();
+
+ // relative to mFrame
+ nsRect mEffectsBounds;
+ // True if we need to handle css opacity in this display item.
+ bool mHandleOpacity;
+};
+
+/**
+ * A display item to paint a stacking context with 'mask' and 'clip-path'
+ * effects set by the stacking context root frame's style. The 'mask' and
+ * 'clip-path' properties may both contain multiple masks and clip paths,
+ * respectively.
+ *
+ * Note that 'mask' and 'clip-path' may just contain CSS simple-images and CSS
+ * basic shapes, respectively. That is, they don't necessarily reference
+ * resources such as SVG 'mask' and 'clipPath' elements.
+ */
+class nsDisplayMasksAndClipPaths : public nsDisplayEffectsBase {
+ public:
+ typedef mozilla::layers::ImageLayer ImageLayer;
+
+ nsDisplayMasksAndClipPaths(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot);
+ nsDisplayMasksAndClipPaths(nsDisplayListBuilder* aBuilder,
+ const nsDisplayMasksAndClipPaths& aOther)
+ : nsDisplayEffectsBase(aBuilder, aOther),
+ mDestRects(aOther.mDestRects.Clone()) {
+ MOZ_COUNT_CTOR(nsDisplayMasksAndClipPaths);
+ }
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayMasksAndClipPaths)
+
+ NS_DISPLAY_DECL_NAME("Mask", TYPE_MASK)
+
+ bool CanMerge(const nsDisplayItem* aItem) const override;
+
+ void Merge(const nsDisplayItem* aItem) override {
+ nsDisplayWrapList::Merge(aItem);
+
+ const nsDisplayMasksAndClipPaths* other =
+ static_cast<const nsDisplayMasksAndClipPaths*>(aItem);
+ mEffectsBounds.UnionRect(
+ mEffectsBounds,
+ other->mEffectsBounds + other->mFrame->GetOffsetTo(mFrame));
+ }
+
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override;
+ bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion) override;
+
+ nsDisplayItemGeometry* AllocateGeometry(
+ nsDisplayListBuilder* aBuilder) override {
+ return new nsDisplayMasksAndClipPathsGeometry(this, aBuilder);
+ }
+
+ void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const override;
+#ifdef MOZ_DUMP_PAINTING
+ void PrintEffects(nsACString& aTo);
+#endif
+
+ bool IsValidMask();
+
+ void PaintAsLayer(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
+ LayerManager* aManager);
+
+ void PaintWithContentsPaintCallback(
+ nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
+ const std::function<void()>& aPaintChildren);
+
+ /*
+ * Paint mask onto aMaskContext in mFrame's coordinate space and
+ * return whether the mask layer was painted successfully.
+ */
+ bool PaintMask(nsDisplayListBuilder* aBuilder, gfxContext* aMaskContext,
+ bool* aMaskPainted = nullptr);
+
+ const nsTArray<nsRect>& GetDestRects() { return mDestRects; }
+
+ void SelectOpacityOptimization(const bool aUsingLayers) override;
+
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
+ mozilla::Maybe<nsRect> GetClipWithRespectToASR(
+ nsDisplayListBuilder* aBuilder,
+ const ActiveScrolledRoot* aASR) const override;
+
+ private:
+ NS_DISPLAY_ALLOW_CLONING()
+
+ // According to mask property and the capability of aManager, determine
+ // whether we can paint the mask onto a dedicate mask layer.
+ bool CanPaintOnMaskLayer(LayerManager* aManager);
+
+ nsTArray<nsRect> mDestRects;
+ bool mApplyOpacityWithSimpleClipPath;
+};
+
+class nsDisplayBackdropRootContainer : public nsDisplayWrapList {
+ public:
+ nsDisplayBackdropRootContainer(nsDisplayListBuilder* aBuilder,
+ nsIFrame* aFrame, nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot)
+ : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, true) {
+ MOZ_COUNT_CTOR(nsDisplayBackdropRootContainer);
+ }
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayBackdropRootContainer)
+
+ NS_DISPLAY_DECL_NAME("BackdropRootContainer", TYPE_BACKDROP_ROOT_CONTAINER)
+
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override;
+
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
+ bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
+ return !aBuilder->IsPaintingForWebRender();
+ }
+};
+
+class nsDisplayBackdropFilters : public nsDisplayWrapList {
+ public:
+ nsDisplayBackdropFilters(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList, const nsRect& aBackdropRect)
+ : nsDisplayWrapList(aBuilder, aFrame, aList),
+ mBackdropRect(aBackdropRect) {
+ MOZ_COUNT_CTOR(nsDisplayBackdropFilters);
+ }
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayBackdropFilters)
+
+ NS_DISPLAY_DECL_NAME("BackdropFilter", TYPE_BACKDROP_FILTER)
+
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
+ static bool CanCreateWebRenderCommands(nsDisplayListBuilder* aBuilder,
+ nsIFrame* aFrame);
+
+ bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
+ return !aBuilder->IsPaintingForWebRender();
+ }
+
+ private:
+ nsRect mBackdropRect;
+};
+
+/**
+ * A display item to paint a stacking context with filter effects set by the
+ * stacking context root frame's style.
+ *
+ * Note that the filters may just be simple CSS filter functions. That is,
+ * they won't necessarily be references to SVG 'filter' elements.
+ */
+class nsDisplayFilters : public nsDisplayEffectsBase {
+ public:
+ nsDisplayFilters(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList);
+
+ nsDisplayFilters(nsDisplayListBuilder* aBuilder,
+ const nsDisplayFilters& aOther)
+ : nsDisplayEffectsBase(aBuilder, aOther),
+ mEffectsBounds(aOther.mEffectsBounds) {
+ MOZ_COUNT_CTOR(nsDisplayFilters);
+ }
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayFilters)
+
+ NS_DISPLAY_DECL_NAME("Filter", TYPE_FILTER)
+
+ bool CanMerge(const nsDisplayItem* aItem) const override {
+ // Items for the same content element should be merged into a single
+ // compositing group.
+ return HasDifferentFrame(aItem) && HasSameTypeAndClip(aItem) &&
+ HasSameContent(aItem);
+ }
+
+ void Merge(const nsDisplayItem* aItem) override {
+ nsDisplayWrapList::Merge(aItem);
+
+ const nsDisplayFilters* other = static_cast<const nsDisplayFilters*>(aItem);
+ mEffectsBounds.UnionRect(
+ mEffectsBounds,
+ other->mEffectsBounds + other->mFrame->GetOffsetTo(mFrame));
+ }
+
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override;
+
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override {
+ *aSnap = false;
+ return mEffectsBounds + ToReferenceFrame();
+ }
+
+ bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion) override;
+
+ nsDisplayItemGeometry* AllocateGeometry(
+ nsDisplayListBuilder* aBuilder) override {
+ return new nsDisplayFiltersGeometry(this, aBuilder);
+ }
+
+ void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const override;
+#ifdef MOZ_DUMP_PAINTING
+ void PrintEffects(nsACString& aTo);
+#endif
+
+ void PaintAsLayer(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
+ LayerManager* aManager);
+
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+ bool CanCreateWebRenderCommands();
+
+ private:
+ NS_DISPLAY_ALLOW_CLONING()
+
+ // relative to mFrame
+ nsRect mEffectsBounds;
+};
+
+/* A display item that applies a transformation to all of its descendant
+ * elements. This wrapper should only be used if there is a transform applied
+ * to the root element.
+ *
+ * The reason that a "bounds" rect is involved in transform calculations is
+ * because CSS-transforms allow percentage values for the x and y components
+ * of <translation-value>s, where percentages are percentages of the element's
+ * border box.
+ *
+ * INVARIANT: The wrapped frame is transformed or we supplied a transform getter
+ * function.
+ * INVARIANT: The wrapped frame is non-null.
+ */
+class nsDisplayTransform : public nsDisplayHitTestInfoBase {
+ using Matrix4x4 = mozilla::gfx::Matrix4x4;
+ using Matrix4x4Flagged = mozilla::gfx::Matrix4x4Flagged;
+ using Point3D = mozilla::gfx::Point3D;
+ using TransformReferenceBox = nsStyleTransformMatrix::TransformReferenceBox;
+
+ public:
+ enum class PrerenderDecision : uint8_t { No, Full, Partial };
+
+ /**
+ * Returns a matrix (in pixels) for the current frame. The matrix should be
+ * relative to the current frame's coordinate space.
+ *
+ * @param aFrame The frame to compute the transform for.
+ * @param aAppUnitsPerPixel The number of app units per graphics unit.
+ */
+ typedef Matrix4x4 (*ComputeTransformFunction)(nsIFrame* aFrame,
+ float aAppUnitsPerPixel);
+
+ /* Constructor accepts a display list, empties it, and wraps it up. It also
+ * ferries the underlying frame to the nsDisplayItem constructor.
+ */
+ nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList, const nsRect& aChildrenBuildingRect);
+
+ nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList, const nsRect& aChildrenBuildingRect,
+ PrerenderDecision aPrerenderDecision);
+
+ nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList, const nsRect& aChildrenBuildingRect,
+ ComputeTransformFunction aTransformGetter);
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayTransform)
+
+ NS_DISPLAY_DECL_NAME("nsDisplayTransform", TYPE_TRANSFORM)
+
+ bool RestoreState() override {
+ if (!nsDisplayHitTestInfoBase::RestoreState() && !mShouldFlatten) {
+ return false;
+ }
+
+ mShouldFlatten = false;
+ return true;
+ }
+
+ void UpdateBounds(nsDisplayListBuilder* aBuilder) override;
+
+ /**
+ * This function updates bounds for items with a frame establishing
+ * 3D rendering context.
+ */
+ void UpdateBoundsFor3D(nsDisplayListBuilder* aBuilder);
+
+ void DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) override;
+
+ void Destroy(nsDisplayListBuilder* aBuilder) override {
+ GetChildren()->DeleteAll(aBuilder);
+ nsDisplayHitTestInfoBase::Destroy(aBuilder);
+ }
+
+ nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const override;
+
+ RetainedDisplayList* GetChildren() const override { return &mChildren; }
+
+ nsRect GetUntransformedBounds(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const override {
+ *aSnap = false;
+ return mChildBounds;
+ }
+
+ const nsRect& GetUntransformedPaintRect() const override {
+ return mChildrenBuildingRect;
+ }
+
+ bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override;
+
+ void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
+ nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const override;
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override;
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+ bool UpdateScrollData(
+ mozilla::layers::WebRenderScrollData* aData,
+ mozilla::layers::WebRenderLayerScrollData* aLayerData) override;
+ bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion) override;
+
+ nsDisplayItemGeometry* AllocateGeometry(
+ nsDisplayListBuilder* aBuilder) override {
+ return new nsDisplayTransformGeometry(
+ this, aBuilder, GetTransformForRendering(),
+ mFrame->PresContext()->AppUnitsPerDevPixel());
+ }
+
+ void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const override {
+ const nsDisplayTransformGeometry* geometry =
+ static_cast<const nsDisplayTransformGeometry*>(aGeometry);
+
+ // This code is only called for flattened, inactive transform items.
+ // Only check if the transform has changed. The bounds invalidation should
+ // be handled by the children themselves.
+ if (!geometry->mTransform.FuzzyEqual(GetTransformForRendering())) {
+ bool snap;
+ aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
+ }
+ }
+
+ bool NeedsGeometryUpdates() const override { return mShouldFlatten; }
+
+ const nsIFrame* ReferenceFrameForChildren() const override {
+ // If we were created using a transform-getter, then we don't
+ // belong to a transformed frame, and aren't a reference frame
+ // for our children.
+ if (!mTransformGetter) {
+ return mFrame;
+ }
+ return nsDisplayHitTestInfoBase::ReferenceFrameForChildren();
+ }
+
+ AnimatedGeometryRoot* AnimatedGeometryRootForScrollMetadata() const override {
+ return mAnimatedGeometryRootForScrollMetadata;
+ }
+
+ const nsRect& GetBuildingRectForChildren() const override {
+ return mChildrenBuildingRect;
+ }
+
+ enum { INDEX_MAX = UINT32_MAX >> TYPE_BITS };
+
+ /**
+ * We include the perspective matrix from our containing block for the
+ * purposes of visibility calculations, but we exclude it from the transform
+ * we set on the layer (for rendering), since there will be an
+ * nsDisplayPerspective created for that.
+ */
+ const Matrix4x4Flagged& GetTransform() const;
+ const Matrix4x4Flagged& GetInverseTransform() const;
+
+ bool ShouldSkipTransform(nsDisplayListBuilder* aBuilder) const;
+ Matrix4x4 GetTransformForRendering(
+ mozilla::LayoutDevicePoint* aOutOrigin = nullptr) const;
+
+ /**
+ * Return the transform that is aggregation of all transform on the
+ * preserves3d chain.
+ */
+ const Matrix4x4& GetAccumulatedPreserved3DTransform(
+ nsDisplayListBuilder* aBuilder);
+
+ float GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder,
+ const nsPoint& aPoint);
+
+ /**
+ * TransformRect takes in as parameters a rectangle (in aFrame's coordinate
+ * space) and returns the smallest rectangle (in aFrame's coordinate space)
+ * containing the transformed image of that rectangle. That is, it takes
+ * the four corners of the rectangle, transforms them according to the
+ * matrix associated with the specified frame, then returns the smallest
+ * rectangle containing the four transformed points.
+ *
+ * @param untransformedBounds The rectangle (in app units) to transform.
+ * @param aFrame The frame whose transformation should be applied. This
+ * function raises an assertion if aFrame is null or doesn't have a
+ * transform applied to it.
+ * @param aRefBox the reference box to use, which would usually be just
+ * TransformReferemceBox(aFrame), but callers may override it if
+ * needed.
+ */
+ static nsRect TransformRect(const nsRect& aUntransformedBounds,
+ const nsIFrame* aFrame,
+ TransformReferenceBox& aRefBox);
+
+ /* UntransformRect is like TransformRect, except that it inverts the
+ * transform.
+ */
+ static bool UntransformRect(const nsRect& aTransformedBounds,
+ const nsRect& aChildBounds,
+ const nsIFrame* aFrame, nsRect* aOutRect);
+
+ bool UntransformRect(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ nsRect* aOutRect) const;
+
+ bool UntransformBuildingRect(nsDisplayListBuilder* aBuilder,
+ nsRect* aOutRect) const {
+ return UntransformRect(aBuilder, GetBuildingRect(), aOutRect);
+ }
+
+ bool UntransformPaintRect(nsDisplayListBuilder* aBuilder,
+ nsRect* aOutRect) const {
+ return UntransformRect(aBuilder, GetPaintRect(), aOutRect);
+ }
+
+ static Point3D GetDeltaToTransformOrigin(const nsIFrame* aFrame,
+ TransformReferenceBox&,
+ float aAppUnitsPerPixel);
+
+ /*
+ * Returns true if aFrame has perspective applied from its containing
+ * block.
+ * Returns the matrix to append to apply the persective (taking
+ * perspective-origin into account), relative to aFrames coordinate
+ * space).
+ * aOutMatrix is assumed to be the identity matrix, and isn't explicitly
+ * cleared.
+ */
+ static bool ComputePerspectiveMatrix(const nsIFrame* aFrame,
+ float aAppUnitsPerPixel,
+ Matrix4x4& aOutMatrix);
+
+ struct MOZ_STACK_CLASS FrameTransformProperties {
+ FrameTransformProperties(const nsIFrame* aFrame,
+ TransformReferenceBox& aRefBox,
+ float aAppUnitsPerPixel);
+ FrameTransformProperties(
+ const mozilla::StyleTranslate& aTranslate,
+ const mozilla::StyleRotate& aRotate, const mozilla::StyleScale& aScale,
+ const mozilla::StyleTransform& aTransform,
+ const mozilla::Maybe<mozilla::ResolvedMotionPathData>& aMotion,
+ const Point3D& aToTransformOrigin)
+ : mFrame(nullptr),
+ mTranslate(aTranslate),
+ mRotate(aRotate),
+ mScale(aScale),
+ mTransform(aTransform),
+ mMotion(aMotion),
+ mToTransformOrigin(aToTransformOrigin) {}
+
+ bool HasTransform() const {
+ return !mTranslate.IsNone() || !mRotate.IsNone() || !mScale.IsNone() ||
+ !mTransform.IsNone() || mMotion.isSome();
+ }
+
+ const nsIFrame* mFrame;
+ const mozilla::StyleTranslate& mTranslate;
+ const mozilla::StyleRotate& mRotate;
+ const mozilla::StyleScale& mScale;
+ const mozilla::StyleTransform& mTransform;
+ const mozilla::Maybe<mozilla::ResolvedMotionPathData> mMotion;
+ const Point3D mToTransformOrigin;
+ };
+
+ /**
+ * Given a frame with the transform property or an SVG transform,
+ * returns the transformation matrix for that frame.
+ *
+ * @param aFrame The frame to get the matrix from.
+ * @param aOrigin Relative to which point this transform should be applied.
+ * @param aAppUnitsPerPixel The number of app units per graphics unit.
+ * @param aBoundsOverride [optional] If this is nullptr (the default), the
+ * computation will use the value of TransformReferenceBox(aFrame).
+ * Otherwise, it will use the value of aBoundsOverride. This is
+ * mostly for internal use and in most cases you will not need to
+ * specify a value.
+ * @param aFlags OFFSET_BY_ORIGIN The resulting matrix will be translated
+ * by aOrigin. This translation is applied *before* the CSS transform.
+ * @param aFlags INCLUDE_PRESERVE3D_ANCESTORS The computed transform will
+ * include the transform of any ancestors participating in the same
+ * 3d rendering context.
+ * @param aFlags INCLUDE_PERSPECTIVE The resulting matrix will include the
+ * perspective transform from the containing block if applicable.
+ */
+ enum {
+ OFFSET_BY_ORIGIN = 1 << 0,
+ INCLUDE_PRESERVE3D_ANCESTORS = 1 << 1,
+ INCLUDE_PERSPECTIVE = 1 << 2,
+ };
+ static Matrix4x4 GetResultingTransformMatrix(const nsIFrame* aFrame,
+ const nsPoint& aOrigin,
+ float aAppUnitsPerPixel,
+ uint32_t aFlags);
+ static Matrix4x4 GetResultingTransformMatrix(
+ const FrameTransformProperties& aProperties, TransformReferenceBox&,
+ float aAppUnitsPerPixel);
+
+ struct PrerenderInfo {
+ bool CanUseAsyncAnimations() const {
+ return mDecision != PrerenderDecision::No && mHasAnimations;
+ }
+ PrerenderDecision mDecision = PrerenderDecision::No;
+ bool mHasAnimations = true;
+ };
+ /**
+ * Decide whether we should prerender some or all of the contents of the
+ * transformed frame even when it's not completely visible (yet).
+ * Return PrerenderDecision::Full if the entire contents should be
+ * prerendered, PrerenderDecision::Partial if some but not all of the
+ * contents should be prerendered, or PrerenderDecision::No if only the
+ * visible area should be rendered.
+ * |mNoAffectDecisionInPreserve3D| is set if the prerender decision should not
+ * affect the decision on other frames in the preserve 3d tree.
+ * |aDirtyRect| is updated to the area that should be prerendered.
+ */
+ static PrerenderInfo ShouldPrerenderTransformedContent(
+ nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsRect* aDirtyRect);
+
+ bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) override;
+
+ bool MayBeAnimated(nsDisplayListBuilder* aBuilder,
+ bool aEnforceMinimumSize = true) const;
+
+ void WriteDebugInfo(std::stringstream& aStream) override;
+
+ /**
+ * This item is an additional item as the boundary between parent
+ * and child 3D rendering context.
+ * \see nsIFrame::BuildDisplayListForStackingContext().
+ */
+ bool IsTransformSeparator() const { return mIsTransformSeparator; }
+ /**
+ * This item is the boundary between parent and child 3D rendering
+ * context.
+ */
+ bool IsLeafOf3DContext() const {
+ return (IsTransformSeparator() ||
+ (!mFrame->Extend3DContext() && Combines3DTransformWithAncestors()));
+ }
+ /**
+ * The backing frame of this item participates a 3D rendering
+ * context.
+ */
+ bool IsParticipating3DContext() const {
+ return mFrame->Extend3DContext() || Combines3DTransformWithAncestors();
+ }
+
+ bool IsPartialPrerender() const {
+ return mPrerenderDecision == PrerenderDecision::Partial;
+ }
+
+ void AddSizeOfExcludingThis(nsWindowSizes&) const override;
+
+ private:
+ void ComputeBounds(nsDisplayListBuilder* aBuilder);
+ nsRect TransformUntransformedBounds(nsDisplayListBuilder* aBuilder,
+ const Matrix4x4Flagged& aMatrix) const;
+ void UpdateUntransformedBounds(nsDisplayListBuilder* aBuilder);
+
+ void SetReferenceFrameToAncestor(nsDisplayListBuilder* aBuilder);
+ void Init(nsDisplayListBuilder* aBuilder, nsDisplayList* aChildren);
+
+ static Matrix4x4 GetResultingTransformMatrixInternal(
+ const FrameTransformProperties& aProperties,
+ TransformReferenceBox& aRefBox, const nsPoint& aOrigin,
+ float aAppUnitsPerPixel, uint32_t aFlags);
+
+ mutable mozilla::Maybe<Matrix4x4Flagged> mTransform;
+ mutable mozilla::Maybe<Matrix4x4Flagged> mInverseTransform;
+ // Accumulated transform of ancestors on the preserves-3d chain.
+ mozilla::UniquePtr<Matrix4x4> mTransformPreserves3D;
+ ComputeTransformFunction mTransformGetter;
+ RefPtr<AnimatedGeometryRoot> mAnimatedGeometryRootForChildren;
+ RefPtr<AnimatedGeometryRoot> mAnimatedGeometryRootForScrollMetadata;
+ nsRect mChildrenBuildingRect;
+ mutable RetainedDisplayList mChildren;
+
+ // The untransformed bounds of |mChildren|.
+ nsRect mChildBounds;
+ // The transformed bounds of this display item.
+ nsRect mBounds;
+ PrerenderDecision mPrerenderDecision : 8;
+ // This item is a separator between 3D rendering contexts, and
+ // mTransform have been presetted by the constructor.
+ // This also forces us not to extend the 3D context. Since we don't create a
+ // transform item, a container layer, for every frame in a preserves3d
+ // context, the transform items of a child preserves3d context may extend the
+ // parent context unintendedly if the root of the child preserves3d context
+ // doesn't create a transform item.
+ bool mIsTransformSeparator : 1;
+ // True if this nsDisplayTransform should get flattened
+ bool mShouldFlatten : 1;
+};
+
+/* A display item that applies a perspective transformation to a single
+ * nsDisplayTransform child item. We keep this as a separate item since the
+ * perspective-origin is relative to an ancestor of the transformed frame, and
+ * APZ can scroll the child separately.
+ */
+class nsDisplayPerspective : public nsDisplayHitTestInfoBase {
+ typedef mozilla::gfx::Point3D Point3D;
+
+ public:
+ nsDisplayPerspective(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList);
+ ~nsDisplayPerspective() override = default;
+
+ NS_DISPLAY_DECL_NAME("nsDisplayPerspective", TYPE_PERSPECTIVE)
+
+ void Destroy(nsDisplayListBuilder* aBuilder) override {
+ mList.DeleteAll(aBuilder);
+ nsDisplayHitTestInfoBase::Destroy(aBuilder);
+ }
+
+ void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override {
+ return GetChildren()->HitTest(aBuilder, aRect, aState, aOutFrames);
+ }
+
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override {
+ *aSnap = false;
+ return GetChildren()->GetClippedBoundsWithRespectToASR(aBuilder,
+ mActiveScrolledRoot);
+ }
+
+ bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+ nsRegion* aVisibleRegion) override;
+
+ void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const override {}
+
+ nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+ bool* aSnap) const override;
+
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override;
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+
+ RetainedDisplayList* GetSameCoordinateSystemChildren() const override {
+ return &mList;
+ }
+
+ RetainedDisplayList* GetChildren() const override { return &mList; }
+
+ nsRect GetComponentAlphaBounds(
+ nsDisplayListBuilder* aBuilder) const override {
+ return GetChildren()->GetComponentAlphaBounds(aBuilder);
+ }
+
+ void DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) override {
+ if (GetChildren()->GetTop()) {
+ static_cast<nsDisplayTransform*>(GetChildren()->GetTop())
+ ->DoUpdateBoundsPreserves3D(aBuilder);
+ }
+ }
+
+ private:
+ mutable RetainedDisplayList mList;
+};
+
+/**
+ * This class adds basic support for limiting the rendering (in the inline axis
+ * of the writing mode) to the part inside the specified edges.
+ * The two members, mVisIStartEdge and mVisIEndEdge, are relative to the edges
+ * of the frame's scrollable overflow rectangle and are the amount to suppress
+ * on each side.
+ *
+ * Setting none, both or only one edge is allowed.
+ * The values must be non-negative.
+ * The default value for both edges is zero, which means everything is painted.
+ */
+class nsDisplayText final : public nsPaintedDisplayItem {
+ public:
+ nsDisplayText(nsDisplayListBuilder* aBuilder, nsTextFrame* aFrame,
+ const mozilla::Maybe<bool>& aIsSelected);
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayText)
+
+ NS_DISPLAY_DECL_NAME("Text", TYPE_TEXT)
+
+ bool RestoreState() final {
+ if (!nsPaintedDisplayItem::RestoreState() && mIsFrameSelected.isNothing() &&
+ mOpacity == 1.0f) {
+ return false;
+ }
+
+ mIsFrameSelected.reset();
+ mOpacity = 1.0f;
+ return true;
+ }
+
+ nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const final {
+ *aSnap = false;
+ return mBounds;
+ }
+
+ void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) final {
+ if (nsRect(ToReferenceFrame(), mFrame->GetSize()).Intersects(aRect)) {
+ aOutFrames->AppendElement(mFrame);
+ }
+ }
+
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) final;
+ void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) final;
+
+ nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const final {
+ if (gfxPlatform::GetPlatform()->RespectsFontStyleSmoothing()) {
+ // On OS X, web authors can turn off subpixel text rendering using the
+ // CSS property -moz-osx-font-smoothing. If they do that, we don't need
+ // to use component alpha layers for the affected text.
+ if (mFrame->StyleFont()->mFont.smoothing == NS_FONT_SMOOTHING_GRAYSCALE) {
+ return nsRect();
+ }
+ }
+ bool snap;
+ return GetBounds(aBuilder, &snap);
+ }
+
+ nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) final;
+
+ void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+ const nsDisplayItemGeometry* aGeometry,
+ nsRegion* aInvalidRegion) const final;
+
+ void RenderToContext(gfxContext* aCtx, nsDisplayListBuilder* aBuilder,
+ bool aIsRecording = false);
+
+ bool CanApplyOpacity() const final;
+
+ void ApplyOpacity(nsDisplayListBuilder* aBuilder, float aOpacity,
+ const DisplayItemClipChain* aClip) final {
+ NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
+ mOpacity = aOpacity;
+ IntersectClip(aBuilder, aClip, false);
+ }
+
+ void WriteDebugInfo(std::stringstream& aStream) final;
+
+ static nsDisplayText* CheckCast(nsDisplayItem* aItem) {
+ return (aItem->GetType() == DisplayItemType::TYPE_TEXT)
+ ? static_cast<nsDisplayText*>(aItem)
+ : nullptr;
+ }
+
+ bool IsSelected() const;
+
+ struct ClipEdges {
+ ClipEdges(const nsIFrame* aFrame, const nsPoint& aToReferenceFrame,
+ nscoord aVisIStartEdge, nscoord aVisIEndEdge) {
+ nsRect r = aFrame->ScrollableOverflowRect() + aToReferenceFrame;
+ if (aFrame->GetWritingMode().IsVertical()) {
+ mVisIStart = aVisIStartEdge > 0 ? r.y + aVisIStartEdge : nscoord_MIN;
+ mVisIEnd = aVisIEndEdge > 0
+ ? std::max(r.YMost() - aVisIEndEdge, mVisIStart)
+ : nscoord_MAX;
+ } else {
+ mVisIStart = aVisIStartEdge > 0 ? r.x + aVisIStartEdge : nscoord_MIN;
+ mVisIEnd = aVisIEndEdge > 0
+ ? std::max(r.XMost() - aVisIEndEdge, mVisIStart)
+ : nscoord_MAX;
+ }
+ }
+
+ void Intersect(nscoord* aVisIStart, nscoord* aVisISize) const {
+ nscoord end = *aVisIStart + *aVisISize;
+ *aVisIStart = std::max(*aVisIStart, mVisIStart);
+ *aVisISize = std::max(std::min(end, mVisIEnd) - *aVisIStart, 0);
+ }
+
+ nscoord mVisIStart;
+ nscoord mVisIEnd;
+ };
+
+ nscoord& VisIStartEdge() { return mVisIStartEdge; }
+ nscoord& VisIEndEdge() { return mVisIEndEdge; }
+ float Opacity() const { return mOpacity; }
+
+ private:
+ nsRect mBounds;
+ float mOpacity;
+
+ // Lengths measured from the visual inline start and end sides
+ // (i.e. left and right respectively in horizontal writing modes,
+ // regardless of bidi directionality; top and bottom in vertical modes).
+ nscoord mVisIStartEdge;
+ nscoord mVisIEndEdge;
+
+ // Cached result of mFrame->IsSelected(). Only initialized when needed.
+ mutable mozilla::Maybe<bool> mIsFrameSelected;
+};
+
+/**
+ * A display item that for webrender to handle SVG
+ */
+class nsDisplaySVGWrapper : public nsDisplayWrapList {
+ public:
+ nsDisplaySVGWrapper(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList);
+
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplaySVGWrapper)
+
+ NS_DISPLAY_DECL_NAME("SVGWrapper", TYPE_SVG_WRAPPER)
+
+ already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+ LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override;
+ bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override;
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+};
+
+/**
+ * A display item for webrender to handle SVG foreign object
+ */
+class nsDisplayForeignObject : public nsDisplayWrapList {
+ public:
+ nsDisplayForeignObject(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList);
+#ifdef NS_BUILD_REFCNT_LOGGING
+ virtual ~nsDisplayForeignObject();
+#endif
+
+ NS_DISPLAY_DECL_NAME("ForeignObject", TYPE_FOREIGN_OBJECT)
+
+ virtual already_AddRefed<Layer> BuildLayer(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+ virtual LayerState GetLayerState(
+ nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+ const ContainerLayerParameters& aParameters) override;
+ virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override;
+
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+};
+
+class FlattenedDisplayListIterator {
+ public:
+ FlattenedDisplayListIterator(nsDisplayListBuilder* aBuilder,
+ nsDisplayList* aList)
+ : FlattenedDisplayListIterator(aBuilder, aList, true) {}
+
+ ~FlattenedDisplayListIterator() { MOZ_ASSERT(!HasNext()); }
+
+ virtual bool HasNext() const { return mNext || !mStack.IsEmpty(); }
+
+ nsDisplayItem* GetNextItem() {
+ MOZ_ASSERT(mNext);
+
+ nsDisplayItem* next = mNext;
+ mNext = next->GetAbove();
+
+ if (mNext && next->HasChildren() && mNext->HasChildren()) {
+ // Since |next| and |mNext| are container items in the same list,
+ // merging them might be possible.
+ next = TryMergingFrom(next);
+ }
+
+ ResolveFlattening();
+
+ return next;
+ }
+
+ nsDisplayItem* PeekNext() { return mNext; }
+
+ protected:
+ FlattenedDisplayListIterator(nsDisplayListBuilder* aBuilder,
+ nsDisplayList* aList,
+ const bool aResolveFlattening)
+ : mBuilder(aBuilder), mNext(aList->GetBottom()) {
+ if (aResolveFlattening) {
+ // This is done conditionally in case subclass overrides
+ // ShouldFlattenNextItem().
+ ResolveFlattening();
+ }
+ }
+
+ virtual void EnterChildList(nsDisplayItem* aContainerItem) {}
+ virtual void ExitChildList() {}
+
+ bool AtEndOfNestedList() const { return !mNext && mStack.Length() > 0; }
+
+ virtual bool ShouldFlattenNextItem() {
+ return mNext && mNext->ShouldFlattenAway(mBuilder);
+ }
+
+ void ResolveFlattening() {
+ // Handle the case where we reach the end of a nested list, or the current
+ // item should start a new nested list. Repeat this until we find an actual
+ // item, or the very end of the outer list.
+ while (AtEndOfNestedList() || ShouldFlattenNextItem()) {
+ if (AtEndOfNestedList()) {
+ ExitChildList();
+
+ // We reached the end of the list, pop the next item from the stack.
+ mNext = mStack.PopLastElement();
+ } else {
+ EnterChildList(mNext);
+
+ // This item wants to be flattened. Store the next item on the stack,
+ // and use the first item in the child list instead.
+ mStack.AppendElement(mNext->GetAbove());
+ mNext = mNext->GetChildren()->GetBottom();
+ }
+ }
+ }
+
+ /**
+ * Tries to merge display items starting from |aCurrent|.
+ * Updates the internal pointer to the next display item.
+ */
+ nsDisplayItem* TryMergingFrom(nsDisplayItem* aCurrent) {
+ MOZ_ASSERT(aCurrent);
+ MOZ_ASSERT(aCurrent->GetAbove());
+
+ nsDisplayWrapList* current = aCurrent->AsDisplayWrapList();
+ nsDisplayWrapList* next = mNext->AsDisplayWrapList();
+
+ if (!current || !next) {
+ // Either the current or the next item do not support merging.
+ return aCurrent;
+ }
+
+ // Attempt to merge |next| with |current|.
+ if (current->CanMerge(next)) {
+ // Merging is possible, collect all the successive mergeable items.
+ AutoTArray<nsDisplayWrapList*, 2> willMerge{current};
+
+ do {
+ willMerge.AppendElement(next);
+ mNext = next->GetAbove();
+ next = mNext ? mNext->AsDisplayWrapList() : nullptr;
+ } while (next && current->CanMerge(next));
+
+ current = mBuilder->MergeItems(willMerge);
+ }
+
+ // Here |mNext| will be either the first item that could not be merged with
+ // |current|, or nullptr.
+ return current;
+ }
+
+ private:
+ nsDisplayListBuilder* mBuilder;
+ nsDisplayItem* mNext;
+ AutoTArray<nsDisplayItem*, 16> mStack;
+};
+
+namespace mozilla {
+
+class PaintTelemetry {
+ public:
+ enum class Metric {
+ DisplayList,
+ Layerization,
+ FlushRasterization,
+ Rasterization,
+ COUNT,
+ };
+
+ class AutoRecord {
+ public:
+ explicit AutoRecord(Metric aMetric);
+ ~AutoRecord();
+
+ TimeStamp GetStart() const { return mStart; }
+
+ private:
+ Metric mMetric;
+ mozilla::TimeStamp mStart;
+ };
+
+ class AutoRecordPaint {
+ public:
+ AutoRecordPaint();
+ ~AutoRecordPaint();
+
+ private:
+ mozilla::TimeStamp mStart;
+ };
+
+ private:
+ static uint32_t sPaintLevel;
+ static uint32_t sMetricLevel;
+ static mozilla::EnumeratedArray<Metric, Metric::COUNT, double> sMetrics;
+};
+
+} // namespace mozilla
+
+#endif /*NSDISPLAYLIST_H_*/