Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at
* structures that represent things to be painted (ordered in z-order),
* used during painting and hit testing
#include "DisplayItemClipChain.h"
#include "DisplayListClipState.h"
#include "FrameMetrics.h"
#include "HitTestInfo.h"
#include "ImgDrawResult.h"
#include "RetainedDisplayListHelpers.h"
#include "Units.h"
#include "gfxContext.h"
#include "mozilla/ArenaAllocator.h"
#include "mozilla/Array.h"
#include "mozilla/ArrayIterator.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/EffectCompositor.h"
#include "mozilla/EnumSet.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/Logging.h"
#include "mozilla/Maybe.h"
#include "mozilla/MotionPathUtils.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TemplateLib.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/EffectsInfo.h"
#include "mozilla/gfx/UserData.h"
#include "mozilla/layers/BSPTree.h"
#include "mozilla/layers/ScrollableLayerGuid.h"
#include "mozilla/layers/ScrollbarData.h"
#include "nsAutoLayoutPhase.h"
#include "nsCOMPtr.h"
#include "nsCSSRenderingBorders.h"
#include "nsContainerFrame.h"
#include "nsDisplayItemTypes.h"
#include "nsDisplayListInvalidation.h"
#include "nsPoint.h"
#include "nsPresArena.h"
#include "nsRect.h"
#include "nsRegion.h"
#include "nsClassHashtable.h"
#include "nsTHashSet.h"
#include "nsTHashMap.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 nsIScrollableFrame;
class nsSubDocumentFrame;
class nsCaret;
struct WrFiltersHolder;
namespace nsStyleTransformMatrix {
class TransformReferenceBox;
namespace mozilla {
enum class nsDisplayOwnLayerFlags;
class nsDisplayCompositorHitTestInfo;
class nsDisplayScrollInfoLayer;
class PresShell;
class StickyScrollContainer;
namespace layers {
struct FrameMetrics;
class RenderRootStateManager;
class Layer;
class ImageContainer;
class StackingContextHelper;
class WebRenderScrollData;
class WebRenderLayerScrollData;
class WebRenderLayerManager;
} // namespace layers
namespace wr {
class DisplayListBuilder;
} // namespace wr
namespace dom {
class RemoteBrowser;
class Selection;
} // namespace dom
enum class DisplayListArenaObjectId {
#define DISPLAY_LIST_ARENA_OBJECT(name_) name_,
#include "nsDisplayListArenaTypes.h"
extern LazyLogModule sContentDisplayListLog;
extern LazyLogModule sParentDisplayListLog;
LazyLogModule& GetLoggerByProcess();
#define DL_LOG(lvl, ...) MOZ_LOG(GetLoggerByProcess(), lvl, (__VA_ARGS__))
#define DL_LOGI(...) DL_LOG(LogLevel::Info, __VA_ARGS__)
#define DL_LOG_TEST(lvl) MOZ_LOG_TEST(GetLoggerByProcess(), lvl)
#ifdef DEBUG
# define DL_LOGD(...) DL_LOG(LogLevel::Debug, __VA_ARGS__)
# define DL_LOGV(...) DL_LOG(LogLevel::Verbose, __VA_ARGS__)
// Disable Debug and Verbose logs for release builds.
# define DL_LOGD(...)
# define DL_LOGV(...)
* 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:
* 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.
* 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 bool IsProperAncestor(const ActiveScrolledRoot* aAncestor,
const ActiveScrolledRoot* aDescendant);
static nsCString ToString(const 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.
layers::ScrollableLayerGuid::ViewID GetViewId() const {
if (!mViewId.isSome()) {
mViewId = Some(ComputeViewId());
return *mViewId;
RefPtr<const ActiveScrolledRoot> mParent;
nsIScrollableFrame* mScrollableFrame;
: mScrollableFrame(nullptr), mDepth(0), mRetained(false) {}
static void DetachASR(ActiveScrolledRoot* aASR) {
aASR->mParent = nullptr;
aASR->mScrollableFrame = nullptr;
ActiveScrolledRoot, DetachASR)
static uint32_t Depth(const ActiveScrolledRoot* aActiveScrolledRoot) {
return aActiveScrolledRoot ? aActiveScrolledRoot->mDepth : 0;
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<layers::ScrollableLayerGuid::ViewID> mViewId;
uint32_t mDepth;
bool mRetained;
enum class nsDisplayListBuilderMode : uint8_t {
using ListArenaAllocator = ArenaAllocator<4096, 8>;
class nsDisplayItem;
class nsPaintedDisplayItem;
class nsDisplayList;
class nsDisplayWrapList;
class nsDisplayTableBackgroundSet;
class nsDisplayTableItem;
class RetainedDisplayList;
* 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 {
* 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 {
: mAccumulatedRectLevels(0), mAllowAsyncAnimation(true) {}
Preserves3DContext(const Preserves3DContext& aOther)
: mAccumulatedRectLevels(0),
mAllowAsyncAnimation(aOther.mAllowAsyncAnimation) {}
// Accmulate transforms of ancestors on the preserves-3d chain.
gfx::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;
using ViewID = layers::ScrollableLayerGuid::ViewID;
* @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);
void BeginFrame();
void EndFrame();
void AddTemporaryItem(nsDisplayItem* aItem) {
WindowRenderer* GetWidgetWindowRenderer(nsView** aView = nullptr);
layers::WebRenderLayerManager* 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;
* @return true if the display list is being built for painting. This
* includes both painting to a window or other buffer and painting to
* a print/pdf destination.
bool IsForPainting() const {
return mMode == nsDisplayListBuilderMode::Painting ||
mMode == nsDisplayListBuilderMode::PaintForPrinting;
* @return true if the display list is being built specifically for printing.
bool IsForPrinting() const {
return mMode == nsDisplayListBuilderMode::PaintForPrinting;
* @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;
* @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 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; }
* Set the flag that indicates there is a non-minimal display port in the
* current subtree. This is used to determine display port expiry.
void SetContainsNonMinimalDisplayPort() {
mContainsNonMinimalDisplayPort = 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; }
Maybe<layers::ScrollDirection> 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; }
* @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;
void Check() { mPool.Check(); }
* Get the paint sequence number of the current paint.
static uint32_t GetPaintSequenceNumber() { return sPaintSequenceNumber; }
* Increment the paint sequence number.
static void IncrementPaintSequenceNumber() { ++sPaintSequenceNumber; }
* 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;
void SetCompositorHitTestInfo(const gfx::CompositorHitTestInfo& aInfo) {
mCompositorHitTestInfo = aInfo;
const gfx::CompositorHitTestInfo& GetCompositorHitTestInfo() const {
return mCompositorHitTestInfo;
* Builds a new nsDisplayCompositorHitTestInfo for the frame |aFrame| if
* needed, and adds it to the top of |aList|.
void BuildCompositorHitTestInfoIfNeeded(nsIFrame* aFrame,
nsDisplayList* aList);
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(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 InEventsOnly() const { return mInEventsOnly; }
* 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; }
* 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.
uint32_t GetBackgroundPaintFlags();
* Helper method to generate nsImageRenderer flags based on the information
* available in the display list builder.
uint32_t GetImageRendererFlags() const;
* 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 {
(aVisible && aFrame->ForceDescendIntoIfVisible()) ||
* Returns the list of registered theme geometries.
nsTArray<nsIWidget::ThemeGeometry> GetThemeGeometries() const {
nsTArray<nsIWidget::ThemeGeometry> geometries;
for (const auto& data : mThemeGeometries.Values()) {
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 LayoutDeviceIntRect& aRect) {
if (!mIsPaintingToWindow) {
nsTArray<nsIWidget::ThemeGeometry>* geometries =
geometries->AppendElement(nsIWidget::ThemeGeometry(aWidgetType, aRect));
* Removes theme geometries associated with the given display item |aItem|.
void UnregisterThemeGeometry(nsDisplayItem* 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 nsTHashMap<nsPtrHashKey<dom::RemoteBrowser>, dom::EffectsInfo>&
GetEffectUpdates() const {
return mEffectsUpdates;
void AddEffectUpdate(dom::RemoteBrowser* aBrowser,
const dom::EffectsInfo& 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, DisplayListArenaObjectId aId) {
return mPool.Allocate(aId, aSize);
void* Allocate(size_t aSize, DisplayItemType aType) {
#define DECLARE_DISPLAY_ITEM_TYPE(name_, ...) \
static_assert(size_t(DisplayItemType::TYPE_##name_) == \
size_t(DisplayListArenaObjectId::name_), \
#include "nsDisplayItemTypesList.h"
static_assert(size_t(DisplayItemType::TYPE_MAX) ==
static_assert(size_t(DisplayItemType::TYPE_MAX) + 1 ==
return Allocate(aSize, DisplayListArenaObjectId(size_t(aType)));
void Destroy(DisplayListArenaObjectId aId, void* aPtr) {
return mPool.Free(aId, aPtr);
void Destroy(DisplayItemType aType, void* aPtr) {
return Destroy(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);
* Same as above, except aAncestor is computed as the nearest common
* ancestor of the two provided clips.
const DisplayItemClipChain* CreateClipChainIntersection(
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);
const ActiveScrolledRoot* GetFilterASR() const { return mFilterASR; }
* 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<nsDisplayItem*>& aItems);
* A helper class used to temporarily set nsDisplayListBuilder properties for
* building display items.
* aVisibleRect and aDirtyRect are relative to aForChild.
class AutoBuildingDisplayList {
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) {
mBuilder->mAdditionalOffset = Some(aOffset);
mBuilder->mCurrentOffsetToReferenceFrame += aOffset;
void RestoreBuildingInvisibleItemsValue() {
mBuilder->mBuildingInvisibleItems = mPrevBuildingInvisibleItems;
~AutoBuildingDisplayList() {
mBuilder->mCurrentFrame = mPrevFrame;
mBuilder->mCurrentReferenceFrame = mPrevReferenceFrame;
mBuilder->mCurrentOffsetToReferenceFrame = mPrevOffset;
mBuilder->mVisibleRect = mPrevVisibleRect;
mBuilder->mDirtyRect = mPrevDirtyRect;
mBuilder->mAncestorHasApzAwareEventHandler =
mBuilder->mBuildingInvisibleItems = mPrevBuildingInvisibleItems;
mBuilder->mInInvalidSubtree = mPrevInInvalidSubtree;
mBuilder->mAdditionalOffset = mPrevAdditionalOffset;
mBuilder->mCompositorHitTestInfo = mPrevCompositorHitTestInfo;
nsDisplayListBuilder* mBuilder;
const nsIFrame* mPrevFrame;
const nsIFrame* mPrevReferenceFrame;
nsPoint mPrevOffset;
Maybe<nsPoint> mPrevAdditionalOffset;
nsRect mPrevVisibleRect;
nsRect mPrevDirtyRect;
gfx::CompositorHitTestInfo mPrevCompositorHitTestInfo;
bool mPrevAncestorHasApzAwareEventHandler;
bool mPrevBuildingInvisibleItems;
bool mPrevInInvalidSubtree;
* A helper class to temporarily set the value of mInTransform.
class AutoInTransformSetter {
AutoInTransformSetter(nsDisplayListBuilder* aBuilder, bool aInTransform)
: mBuilder(aBuilder), mOldValue(aBuilder->mInTransform) {
aBuilder->mInTransform = aInTransform;
~AutoInTransformSetter() { mBuilder->mInTransform = mOldValue; }
nsDisplayListBuilder* mBuilder;
bool mOldValue;
class AutoInEventsOnly {
AutoInEventsOnly(nsDisplayListBuilder* aBuilder, bool aInEventsOnly)
: mBuilder(aBuilder), mOldValue(aBuilder->mInEventsOnly) {
aBuilder->mInEventsOnly |= aInEventsOnly;
~AutoInEventsOnly() { mBuilder->mInEventsOnly = mOldValue; }
nsDisplayListBuilder* mBuilder;
bool mOldValue;
* A helper class to temporarily set the value of mFilterASR and
* mInFilter.
class AutoEnterFilter {
AutoEnterFilter(nsDisplayListBuilder* aBuilder, bool aUsingFilter)
: mBuilder(aBuilder),
mOldInFilter(aBuilder->mInFilter) {
if (!aBuilder->mFilterASR && aUsingFilter) {
aBuilder->mFilterASR = aBuilder->CurrentActiveScrolledRoot();
aBuilder->mInFilter = true;
~AutoEnterFilter() {
mBuilder->mFilterASR = mOldValue;
mBuilder->mInFilter = mOldInFilter;
nsDisplayListBuilder* mBuilder;
const ActiveScrolledRoot* mOldValue;
bool mOldInFilter;
* Used to update the current active scrolled root on the display list
* builder, and to create new active scrolled roots.
class AutoCurrentActiveScrolledRootSetter {
explicit AutoCurrentActiveScrolledRootSetter(nsDisplayListBuilder* aBuilder)
: mBuilder(aBuilder),
mCanBeScrollParent(false) {}
void SetCurrentScrollParentId(ViewID aScrollId) {
// Update the old scroll parent id.
mOldScrollParentId = mBuilder->mCurrentScrollParentId;
// If this AutoCurrentActiveScrolledRootSetter has the same aScrollId 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 = (mOldScrollParentId != aScrollId);
mBuilder->mCurrentScrollParentId = aScrollId;
mBuilder->mForceLayerForScrollParent = false;
mBuilder->mContainsNonMinimalDisplayPort = false;
bool ShouldForceLayerForScrollParent() const {
// Only scrollframes participating in scroll handoff can be forced to
// layerize
return mCanBeScrollParent && mBuilder->mForceLayerForScrollParent;
bool GetContainsNonMinimalDisplayPort() const {
// Only for scrollframes participating in scroll handoff can we return
// true.
return mCanBeScrollParent && mBuilder->mContainsNonMinimalDisplayPort;
~AutoCurrentActiveScrolledRootSetter() {
mBuilder->mCurrentActiveScrolledRoot = mSavedActiveScrolledRoot;
mBuilder->mCurrentScrollParentId = mOldScrollParentId;
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;
mBuilder->mContainsNonMinimalDisplayPort |=
void SetCurrentActiveScrolledRoot(
const ActiveScrolledRoot* aActiveScrolledRoot);
void EnterScrollFrame(nsIScrollableFrame* aScrollableFrame) {
ActiveScrolledRoot* asr = mBuilder->AllocateActiveScrolledRoot(
mBuilder->mCurrentActiveScrolledRoot, aScrollableFrame);
mBuilder->mCurrentActiveScrolledRoot = asr;
mUsed = true;
void InsertScrollFrame(nsIScrollableFrame* aScrollableFrame);
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;
ViewID mOldScrollParentId;
bool mOldForceLayer;
bool mOldContainsNonMinimalDisplayPort;
bool mCanBeScrollParent;
* 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 {
explicit AutoContainerASRTracker(nsDisplayListBuilder* aBuilder);
const ActiveScrolledRoot* GetContainerASR() {
return mBuilder->mCurrentContainerASR;
~AutoContainerASRTracker() {
mBuilder->mCurrentContainerASR = ActiveScrolledRoot::PickAncestor(
mBuilder->mCurrentContainerASR, mSavedContainerASR);
nsDisplayListBuilder* mBuilder;
const ActiveScrolledRoot* mSavedContainerASR;
* A helper class to temporarily set the value of mCurrentScrollbarTarget
* and mCurrentScrollbarFlags.
class AutoCurrentScrollbarInfoSetter {
nsDisplayListBuilder* aBuilder, ViewID aScrollTargetID,
const Maybe<layers::ScrollDirection>& 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 =
mBuilder->mCurrentScrollbarWillHaveLayer = false;
nsDisplayListBuilder* mBuilder;
* A helper class to temporarily set mBuildingExtraPagesForPageNum.
class MOZ_RAII AutoPageNumberSetter {
AutoPageNumberSetter(nsDisplayListBuilder* aBuilder, const uint8_t aPageNum)
: mBuilder(aBuilder),
mOldPageNum(aBuilder->GetBuildingExtraPagesForPageNum()) {
~AutoPageNumberSetter() {
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 {
explicit AutoAccumulateTransform(nsDisplayListBuilder* aBuilder)
: mBuilder(aBuilder),
mSavedTransform(aBuilder->mPreserves3DCtx.mAccumulatedTransform) {}
~AutoAccumulateTransform() {
mBuilder->mPreserves3DCtx.mAccumulatedTransform = mSavedTransform;
void Accumulate(const gfx::Matrix4x4& aTransform) {
mBuilder->mPreserves3DCtx.mAccumulatedTransform =
aTransform * mBuilder->mPreserves3DCtx.mAccumulatedTransform;
const gfx::Matrix4x4& GetCurrentTransform() {
return mBuilder->mPreserves3DCtx.mAccumulatedTransform;
void StartRoot() {
mBuilder->mPreserves3DCtx.mAccumulatedTransform = gfx::Matrix4x4();
nsDisplayListBuilder* mBuilder;
gfx::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 {
explicit AutoAccumulateRect(nsDisplayListBuilder* aBuilder)
: mBuilder(aBuilder),
mSavedRect(aBuilder->mPreserves3DCtx.mAccumulatedRect) {
aBuilder->mPreserves3DCtx.mAccumulatedRect = nsRect();
~AutoAccumulateRect() {
mBuilder->mPreserves3DCtx.mAccumulatedRect = mSavedRect;
nsDisplayListBuilder* mBuilder;
nsRect mSavedRect;
void AccumulateRect(const nsRect& 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 {
const DisplayItemClipChain* aContainingBlockClipChain,
const DisplayItemClipChain* aCombinedClipChain,
const ActiveScrolledRoot* aContainingBlockActiveScrolledRoot,
const ViewID& aScrollParentId, const nsRect& aVisibleRect,
const nsRect& aDirtyRect)
: mContainingBlockClipChain(aContainingBlockClipChain),
mScrollParentId(aScrollParentId) {}
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;
ViewID mScrollParentId;
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);
struct DisplayListBuildingData {
nsIFrame* mModifiedAGR = nullptr;
nsRect mDirtyRect;
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 opaque stuff into the window opaque region.
void AddWindowOpaqueRegion(nsIFrame* aFrame, const nsRect& aBounds) {
if (IsRetainingDisplayList()) {
mRetainedWindowOpaqueRegion.Add(aFrame, aBounds);
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;
* 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; }
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 {
explicit AutoPreserves3DContext(nsDisplayListBuilder* aBuilder)
: mBuilder(aBuilder), mSavedCtx(aBuilder->mPreserves3DCtx) {}
~AutoPreserves3DContext() { mBuilder->mPreserves3DCtx = mSavedCtx; }
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;
bool HitTestIsForVisibility() const { return mVisibleThreshold.isSome(); }
float VisibilityThreshold() const {
return mVisibleThreshold.valueOr(1.0f);
void SetHitTestIsForVisibility(float aVisibleThreshold) {
mVisibleThreshold = 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) {}
UniquePtr<WeakFrame> mWeakFrame;
void* mFrame;
nsTHashSet<void*> mFrameSet;
nsTArray<WeakFrameWrapper> mFrames;
nsTArray<pixman_box32_t> mRects;
template <typename RectType>