/* -*- 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 "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/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 "nsCaret.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 nsSubDocumentFrame;
struct WrFiltersHolder;
namespace nsStyleTransformMatrix {
class TransformReferenceBox;
}
namespace mozilla {
enum class nsDisplayOwnLayerFlags;
class nsDisplayCompositorHitTestInfo;
class nsDisplayScrollInfoLayer;
class PresShell;
class ScrollContainerFrame;
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"
#undef DISPLAY_LIST_ARENA_OBJECT
COUNT
};
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__)
#else
// Disable Debug and Verbose logs for release builds.
# define DL_LOGD(...)
# define DL_LOGV(...)
#endif
/*
* 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.
*/
/**
* 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,
ScrollContainerFrame* aScrollContainerFrame,
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;
ScrollContainerFrame* mScrollContainerFrame = nullptr;
NS_INLINE_DECL_REFCOUNTING(ActiveScrolledRoot)
private:
ActiveScrolledRoot() : mDepth(0), mRetained(
false) {}
~ActiveScrolledRoot();
static void DetachASR(ActiveScrolledRoot* aASR) {
aASR->mParent = nullptr;
aASR->mScrollContainerFrame = 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;
}
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 {
Painting,
PaintForPrinting,
EventDelivery,
FrameVisibility,
GenerateGlyph,
};
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 {
public:
Preserves3DContext()
: mAccumulatedRectLevels(0), mAllowAsyncAnimation(
true) {}
Preserves3DContext(
const Preserves3DContext& aOther)
: mAccumulatedRectLevels(0),
mVisibleRect(aOther.mVisibleRect),
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;
};
public:
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);
~nsDisplayListBuilder();
void BeginFrame();
void EndFrame();
void AddTemporaryItem(nsDisplayItem* aItem) {
mTemporaryItems.AppendElement(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 mAsyncPanZoomEnabled && mIsPaintingToWindow;
}
/**
* @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; }
/**
* Set for display lists built for hit-testing a point that is already
* relative to the layout viewport. Display lists with this flag set
* do not build an async zoom container (which would transform coordinates
* relative to the visual viewport into coordinates relative to the
* layout viewport during hit-testing).
*/
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();
uint32_t GetNumActiveScrollframesEncountered()
const {
return mNumActiveScrollframesEncountered;
}
/**
* 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; }
/**
* 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 CurrentPresShellState()->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;
/**
* 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<nsIWidget::ThemeGeometry> GetThemeGeometries()
const {
nsTArray<nsIWidget::ThemeGeometry> geometries;
for (
const auto& data : mThemeGeometries.Values()) {
geometries.AppendElements(*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::MozWindowTitlebar) 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) {
return;
}
nsTArray<nsIWidget::ThemeGeometry>* geometries =
mThemeGeometries.GetOrInsertNew(aItem);
geometries->AppendElement(nsIWidget::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();
/**
* Invalidates the caret frames from previous paints, if they have changed.
*/
void InvalidateCaretFramesIfNeeded();
/**
* 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) ==
size_t(DisplayListArenaObjectId::CLIPCHAIN),
"");
static_assert(size_t(DisplayItemType::TYPE_MAX) + 1 ==
size_t(DisplayListArenaObjectId::LISTNODE),
"");
#undef DECLARE_DISPLAY_ITEM_TYPE
return Allocate(aSize, DisplayListArenaObjectId(size_t(aType)));
}
void Destroy(DisplayListArenaObjectId aId,
void* aPtr) {
if (!mIsDestroying) {
mPool.Free(aId, aPtr);
}
}
void Destroy(DisplayItemType aType,
void* aPtr) {
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,
ScrollContainerFrame* aScrollContainerFrame);
/**
* 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 {
public:
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 = 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 =
mPrevAncestorHasApzAwareEventHandler;
mBuilder->mBuildingInvisibleItems = mPrevBuildingInvisibleItems;
mBuilder->mInInvalidSubtree = mPrevInInvalidSubtree;
mBuilder->mAdditionalOffset = mPrevAdditionalOffset;
mBuilder->mCompositorHitTestInfo = mPrevCompositorHitTestInfo;
}
private:
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 {
public:
AutoInTransformSetter(nsDisplayListBuilder* aBuilder,
bool aInTransform)
: mBuilder(aBuilder), mOldValue(aBuilder->mInTransform) {
aBuilder->mInTransform = aInTransform;
}
~AutoInTransformSetter() { mBuilder->mInTransform = mOldValue; }
private:
nsDisplayListBuilder* mBuilder;
bool mOldValue;
};
class AutoInEventsOnly {
public:
AutoInEventsOnly(nsDisplayListBuilder* aBuilder,
bool aInEventsOnly)
: mBuilder(aBuilder), mOldValue(aBuilder->mInEventsOnly) {
aBuilder->mInEventsOnly |= aInEventsOnly;
}
~AutoInEventsOnly() { mBuilder->mInEventsOnly = 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;
};
/**
* 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),
mOldScrollParentId(aBuilder->mCurrentScrollParentId),
mOldForceLayer(aBuilder->mForceLayerForScrollParent),
mOldContainsNonMinimalDisplayPort(
mBuilder->mContainsNonMinimalDisplayPort),
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 |=
mOldContainsNonMinimalDisplayPort;
}
void SetCurrentActiveScrolledRoot(
const ActiveScrolledRoot* aActiveScrolledRoot);
void EnterScrollFrame(ScrollContainerFrame* aScrollContainerFrame) {
MOZ_ASSERT(!mUsed);
ActiveScrolledRoot* asr = mBuilder->AllocateActiveScrolledRoot(
mBuilder->mCurrentActiveScrolledRoot, aScrollContainerFrame);
mBuilder->mCurrentActiveScrolledRoot = asr;
mUsed =
true;
}
void InsertScrollFrame(ScrollContainerFrame* aScrollContainerFrame);
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;
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 {
public:
explicit AutoContainerASRTracker(nsDisplayListBuilder* aBuilder);
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 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 =
layers::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:
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();
}
private:
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 {
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 ViewID& aScrollParentId,
const nsRect& aVisibleRect,
const nsRect& aDirtyRect)
: mContainingBlockClipChain(aContainingBlockClipChain),
mCombinedClipChain(aCombinedClipChain),
mContainingBlockActiveScrolledRoot(
aContainingBlockActiveScrolledRoot),
mVisibleRect(aVisibleRect),
mDirtyRect(aDirtyRect),
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);
}
};
NS_DECLARE_FRAME_PROPERTY_DELETABLE(OutOfFlowDisplayDataProperty,
OutOfFlowDisplayData)
struct DisplayListBuildingData {
nsIFrame* 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 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;
}
/**
* 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 {
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;
}
bool HitTestIsForVisibility()
const {
return mVisibleThreshold.isSome(); }
float VisibilityThreshold()
const {
MOZ_DIAGNOSTIC_ASSERT(HitTestIsForVisibility());
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>
void Add(nsIFrame* aFrame,
const RectType& aRect) {
if (mFrameSet.Contains(aFrame)) {
return;
}
mFrameSet.Insert(aFrame);
mFrames.AppendElement(WeakFrameWrapper(aFrame));
mRects.AppendElement(nsRegion::RectToBox(aRect));
}
void Clear() {
mFrameSet.Clear();
mFrames.Clear();
mRects.Clear();
}
void RemoveModifiedFramesAndRects();
size_t SizeOfExcludingThis(MallocSizeOf)
const;
typedef gfx::ArrayView<pixman_box32_t> BoxArrayView;
nsRegion ToRegion()
const {
return nsRegion(BoxArrayView(mRects)); }
LayoutDeviceIntRegion ToLayoutDeviceIntRegion()
const {
return LayoutDeviceIntRegion(BoxArrayView(mRects));
}
};
void AddScrollContainerFrameToNotify(
ScrollContainerFrame* aScrollContainerFrame);
void NotifyAndClearScrollContainerFrames();
// Helper class to find what link spec (if any) to associate with a frame,
// recording it in the builder, and generate the corresponding DisplayItem.
// This also takes care of generating a named destination for internal links
// if the element has an id or name attribute.
class Linkifier {
public:
Linkifier(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList);
~Linkifier() {
if (mBuilderToReset) {
mBuilderToReset->mLinkURI.Truncate(0);
mBuilderToReset->mLinkDest.Truncate(0);
}
}
void MaybeAppendLink(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
private:
nsDisplayListBuilder* mBuilderToReset = nullptr;
nsDisplayList* mList;
};
/**
* 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);
/**
* Returns true if this is a retained builder and reuse stacking contexts
* mode is enabled by pref.
*/
bool IsReusingStackingContextItems()
const {
return mIsReusingStackingContextItems;
}
/**
* Adds display item |aItem| to the reuseable display items set.
*/
void AddReusableDisplayItem(nsDisplayItem* aItem);
/**
* Removes display item |aItem| from the reuseable display items set.
* This is needed because display items are sometimes deleted during
* display list building.
* Called by |nsDisplayItem::Destroy()| when the item has been reused.
*/
void RemoveReusedDisplayItem(nsDisplayItem* aItem);
/**
* Clears the reuseable display items set.
*/
void ClearReuseableDisplayItems();
/**
* Marks the given display item |aItem| as reused, and updates the necessary
* display list builder state.
*/
void ReuseDisplayItem(nsDisplayItem* aItem);
void SetIsDestroying() { mIsDestroying =
true; }
bool IsDestroying()
const {
return mIsDestroying; }
private:
bool MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame,
const nsRect& aVisibleRect,
const nsRect& aDirtyRect);
friend class nsDisplayBackgroundImage;
friend class RetainedDisplayListBuilder;
/**
* Returns whether a frame acts as an animated geometry root, optionally
* returning the next ancestor to check.
*/
bool IsAnimatedGeometryRoot(nsIFrame* aFrame, nsIFrame** aParent = nullptr);
struct PresShellState {
PresShell* mPresShell;
#ifdef DEBUG
Maybe<nsAutoLayoutPhase> mAutoLayoutPhase;
#endif
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;
nsIFrame* mCaretFrame = nullptr;
};
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;
};
// will-change budget tracker
typedef uint32_t DocumentWillChangeBudget;
nsIFrame*
const mReferenceFrame;
nsIFrame* mIgnoreScrollFrame;
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;
// 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;
DisplayItemClipChain* mFirstClipChainToDestroy;
nsTArray<nsDisplayItem*> mTemporaryItems;
nsDisplayTableBackgroundSet* mTableBackgroundSet;
ViewID mCurrentScrollParentId;
ViewID mCurrentScrollbarTarget;
nsTArray<nsIFrame*> mSVGEffectsFrames;
// When we are inside a filter, the current ASR at the time we entered the
// filter. Otherwise nullptr.
const ActiveScrolledRoot* mFilterASR;
nsCString mLinkURI;
// URI of link currently being emitted, if any.
nsCString mLinkDest;
// Local destination name of link, if any.
// Optimized versions for non-retained display list.
LayoutDeviceIntRegion mWindowDraggingRegion;
LayoutDeviceIntRegion mWindowNoDraggingRegion;
nsRegion mWindowOpaqueRegion;
nsClassHashtable<nsPtrHashKey<nsDisplayItem>,
nsTArray<nsIWidget::ThemeGeometry>>
mThemeGeometries;
DisplayListClipState mClipState;
nsTHashMap<nsPtrHashKey<
const nsPresContext>, DocumentWillChangeBudget>
mDocumentWillChangeBudgets;
// Any frame listed in this set is already counted in the budget
// and thus is in-budget.
nsTHashMap<nsPtrHashKey<
const nsIFrame>, FrameWillChangeBudget>
mFrameWillChangeBudgets;
nsTHashSet<nsCString> mDestinations;
// Destination names emitted.
// Stores reusable items collected during display list preprocessing.
nsTHashSet<nsDisplayItem*> mReuseableItems;
// Tracked carets used for retained display list.
AutoTArray<RefPtr<nsCaret>, 1> mPaintedCarets;
// Tracked regions used for retained display list.
WeakFrameRegion mRetainedWindowDraggingRegion;
WeakFrameRegion mRetainedWindowNoDraggingRegion;
// Window opaque region is calculated during layer building.
WeakFrameRegion mRetainedWindowOpaqueRegion;
std::unordered_set<
const DisplayItemClipChain*, DisplayItemClipChainHasher,
DisplayItemClipChainEqualer>
mClipDeduplicator;
std::unordered_set<ScrollContainerFrame*> mScrollContainerFramesToNotify;
AutoTArray<nsIFrame*, 20> mFramesWithOOFData;
AutoTArray<nsIFrame*, 40> mFramesMarkedForDisplayIfVisible;
AutoTArray<PresShellState, 8> mPresShellStates;
using Arena = nsPresArena<32768, DisplayListArenaObjectId,
size_t(DisplayListArenaObjectId::COUNT)>;
Arena mPool;
AutoTArray<nsIFrame*, 400> mFramesMarkedForDisplay;
gfx::CompositorHitTestInfo mCompositorHitTestInfo;
// The offset from mCurrentFrame to mCurrentReferenceFrame.
nsPoint mCurrentOffsetToReferenceFrame;
Maybe<
float> mVisibleThreshold;
Maybe<nsPoint> mAdditionalOffset;
// Relative to mCurrentFrame.
nsRect mVisibleRect;
nsRect mDirtyRect;
nsRect mCaretRect;
Preserves3DContext mPreserves3DCtx;
uint8_t mBuildingExtraPagesForPageNum;
nsDisplayListBuilderMode mMode;
static uint32_t sPaintSequenceNumber;
uint32_t mNumActiveScrollframesEncountered = 0;
bool mContainsBlendMode;
bool mIsBuildingScrollbar;
bool mCurrentScrollbarWillHaveLayer;
bool mBuildCaret;
bool mRetainingDisplayList;
bool mPartialUpdate;
bool mIgnoreSuppression;
bool mIncludeAllOutOfFlows;
bool mDescendIntoSubdocuments;
--> --------------------
--> maximum size reached
--> --------------------